Guiusepe pushed to branch main at Root / DMARC Report

Commits:

2 changed files:

Changes:

  • README.md
    1 1
     # TODO
    
    2 2
     [x] Renomear /data pra /reports/.
    
    3
    +
    
    3 4
     [x] Renomear a rota /details?serial=:serial para /reports/details/:serial.
    
    5
    +
    
    4 6
     [x] ip e ip6 tão vindo em número/bytes, dá pra vir como uma string formatada de IP.
    
    7
    +
    
    5 8
     [x] Criar uma rota pra baixar o XML, algo tipo /reports/:id.xml
    
    9
    +
    
    6 10
     [x] Converter as datas para padrão BR
    
    11
    +
    
    7 12
     [x] Mudar padrão de argumentos pela URL para usar query
    
    13
    +
    
    8 14
     [x] Adicionar ordenação, tipo um ?sort ou ?order, daí a ordenação padrão poderia ser ?order=-maxdate, ou seja data máxima descendente.
    
    9 15
     
    
    10
    -[ ] Adicionar paginação, ?page, ?offset, algo tipo 50 resultados por página ou escolhe via ?per_page.
    
    11
    -[ ] Adicionar um /reports/extended/ que vem com cada linha "expandida", ou seja, já vem tipo um details em cada linha.
    
    16
    +[x] Adicionar paginação, ?page, ?offset, algo tipo 50 resultados por página ou escolhe via ?per_page.
    
    17
    +
    
    18
    +[x] Adicionar um /reports/extended/ que vem com cada linha "expandida", ou seja, já vem tipo um details em cada linha.
    
    19
    +
    
    20
    +[ ] Mudar respostas de erros para http500
    
    21
    +
    
    22
    +[ ] Remover duplicação de código
    
    23
    +
    
    12 24
     [ ]O dmarc_result_max é igual ao dmarc_result_min no details, dá pra só mudar pra dmarc_result, esse é tipo um "score" do que passou.
    
    13 25
     
    
    14 26
     ### Filtros
    
    15 27
     [ ] ?maxdate__gte=2025-07-24T03:00:00Z (depois ou igual a data)
    
    28
    +
    
    16 29
     [ ] ?maxdate__lt=2025-07-24T05:00:00Z (antes de data)
    
    30
    +
    
    17 31
     [ ] ?domain= (domínio exato)
    
    32
    +
    
    18 33
     [ ] ?dmarc_result_min__lte (score de DMARC menor ou igual)

  • backend.js
    ... ... @@ -116,6 +116,10 @@ const reports_query = `
    116 116
     		report.serial = rptrecord.serial
    
    117 117
         ORDER BY
    
    118 118
             @@@@
    
    119
    +    LIMIT
    
    120
    +        $1
    
    121
    +    OFFSET
    
    122
    +        $2
    
    119 123
     ` ;
    
    120 124
     
    
    121 125
     const details_query = `
    
    ... ... @@ -162,6 +166,7 @@ app.get('/', (req, res) => {
    162 166
     app.get('/reports', (req, res) => {
    
    163 167
         const { sort } = req.query ;
    
    164 168
         
    
    169
    +    // Inject string in query to sort results
    
    165 170
         var sortStr = "" ;
    
    166 171
         switch (sort) {
    
    167 172
             case "maxdate":
    
    ... ... @@ -177,7 +182,12 @@ app.get('/reports', (req, res) => {
    177 182
                 sortStr = "maxdate DESC" ;
    
    178 183
         }
    
    179 184
     
    
    180
    -    pgClient.query(reports_query.replace("@@@@", sortStr), (err, result) => {
    
    185
    +    // Arguments for paging
    
    186
    +    var { page, perPage } = req.query ;
    
    187
    +    if(!page) page=1 ; if(!perPage) perPage=50;
    
    188
    +
    
    189
    +    // replaces the sorting column, adds arguments
    
    190
    +    pgClient.query(reports_query.replace("@@@@", sortStr), [perPage, ((page-1) * perPage)], (err, result) => {
    
    181 191
             if (err) {
    
    182 192
                 console.log("ERROR: Unable to run query") ;
    
    183 193
             } else {
    
    ... ... @@ -194,11 +204,13 @@ app.get('/reports', (req, res) => {
    194 204
     
    
    195 205
     // Individual report details
    
    196 206
     app.get('/reports/details', (req, res) => {
    
    207
    +    // Serial required in URL 
    
    197 208
         const { serial } = req.query ;
    
    198 209
         if (! serial) {
    
    199 210
             res.send("No serial specified...") ;
    
    200 211
             return
    
    201 212
         } 
    
    213
    +
    
    202 214
         pgClient.query(details_query, [serial], (err, result) => {
    
    203 215
             if (err) {
    
    204 216
                 console.log("ERROR: Unable to run query") ;
    
    ... ... @@ -220,6 +232,63 @@ app.get('/reports/details', (req, res) => {
    220 232
     //##############################################################################
    
    221 233
     
    
    222 234
     
    
    235
    +
    
    236
    +// Reports extended
    
    237
    +app.get('/reports/extended', async (req, res) => {
    
    238
    +    let { page, perPage, sort } = req.query;
    
    239
    +    if (!page) page = 1;
    
    240
    +    if (!perPage) perPage = 50;
    
    241
    +
    
    242
    +    // Validate and format sort string
    
    243
    +    let sortStr;
    
    244
    +    switch (sort) {
    
    245
    +        case 'maxdate':
    
    246
    +            sortStr = 'maxdate ASC';
    
    247
    +        break;
    
    248
    +        case 'mindate':
    
    249
    +            sortStr = 'mindate ASC';
    
    250
    +        break;
    
    251
    +        case '-mindate':
    
    252
    +            sortStr = 'mindate DESC';
    
    253
    +        break;
    
    254
    +        default:
    
    255
    +            sortStr = 'maxdate DESC';
    
    256
    +    }
    
    257
    +
    
    258
    +    try {
    
    259
    +        // Equivalent to route /reports
    
    260
    +        const resultO = await pgClient.query(reports_query.replace('@@@@', sortStr), [perPage, (page - 1) * perPage]);
    
    261
    +
    
    262
    +        const rows = resultO.rows;
    
    263
    +
    
    264
    +        // Async gets the /details for each serial in the /reports query
    
    265
    +        await Promise.all(
    
    266
    +            rows.map(async (row) => {
    
    267
    +                const detailResult = await pgClient.query(details_query, [row.serial]);
    
    268
    +                detailResult.rows.forEach((row, index) => {
    
    269
    +                    // Conversion for /details data
    
    270
    +                    row["ip"] = ip.fromLong(row["ip"]) ;
    
    271
    +                    if (row["ip6"] != null) {
    
    272
    +                        row["ip6"] = ip.fromLong(row["ip6"]) ;
    
    273
    +                    }
    
    274
    +                }) ;
    
    275
    +                // Conversion for /reports data
    
    276
    +                row.details = detailResult.rows;
    
    277
    +                row.maxdate = convertDate(row.maxdate) ;
    
    278
    +                row.mindate = convertDate(row.mindate) ;
    
    279
    +            })
    
    280
    +        );
    
    281
    +        res.send(rows);
    
    282
    +    
    
    283
    +    } catch (err) {
    
    284
    +        console.error(err);
    
    285
    +        res.status(500).send('Error fetching data');
    
    286
    +    }
    
    287
    +});
    
    288
    +//##############################################################################
    
    289
    +
    
    290
    +
    
    291
    +
    
    223 292
     // Download xml
    
    224 293
     app.get('/reports/:serial.xml', (req, res) => {
    
    225 294
         pgClient.query(xml_query, [req.params.serial], (err, result) => {