0.2.0 • Published 4 years ago

@ozawa/express-audit-log-middleware v0.2.0

Weekly downloads
16
License
MIT
Repository
-
Last release
4 years ago

Express Audit Log Middleware

Add Audit log middleware to express.

How to use

npm install --save @ozawa/express-audit-log-middleware
const express = require('express');
const jwt = require('express-jwt');
const bodyParser = require('body-parser');
const auditLogMiddleware = require('@ozawa/express-audit-log-middleware');

const app = express();

const defaultPublicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSv
vkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHc
aT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIy
tvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0
e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWb
V6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9
MwIDAQAB
-----END PUBLIC KEY-----`;

app.use(
  jwt({
    secret             : process.env.JWT_AUTH_PUBLIC_KEY || defaultPublicKey,
    credentialsRequired: true,
    requestProperty    : 'auth',
    getToken           : (req) => {
      if (
        req.headers.authorization &&
              req.headers.authorization.split(' ')[0] === 'Bearer'
      ) {
        return req.headers.authorization.split(' ')[1];
      }
      return null;
    },
  })
);
app.use(bodyParser.json());

app.use(auditLogMiddleware({
  routes: [
    {
      methods: [
        'POST',
        'PUT',
        'DELETE',
      ],
      uris: [
        '**',
      ],
    },
  ],
  extractorFunctions: {
    actor        : (req) => req.auth,
    ipAddress    : (req) => req.ip,
    correlationID: (req) => req.headers['x-correlation-id'] || undefined,
  },
  filename: `${__dirname}/logs/audit_log.json`,
}));

app.get('/cat', async function(req, res) {
  const query = JSON.parse(req.query.query || '{}') || {};
  const opts = {
    limit: req.query.limit || 10,
    skip : req.query.skip || 0,
  };
  res.json(await Cat.find(query, null, opts).exec());
});

app.get('/cat/:id', async function(req, res) {
  const kitty = await Cat.findById(req.params.id).exec();
  if (!kitty) {
    res.status(404).send('Kitty not found');
  }
  return res.json(kitty);
});

app.post('/cat', async function(req, res) {
  const kitty = new Cat(req.body);
  await kitty.save();
  res.json(kitty);
});

app.put('/cat/:id', async function(req, res) {
  try {
    await Cat.findByIdAndUpdate(req.params.id, req.body).exec();
    const kitty = await Cat.findById(req.params.id).exec();
    res.json(kitty);
  } catch (error) {
    res.status(500).send('Kitty error');
  }
});

app.delete('/cat/:id', async function(req, res) {
  try {
    await Cat.findByIdAndDelete(req.params.id).exec();
    res.status(204).send('');
  } catch (error) {
    res.status(500).send('Kitty error');
  }
});


const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const Cat = mongoose.model('Cat', new Schema({name: String}, {
  toJSON: {
    versionKey: false,
    transform : (doc, ret) => {
      ret.id = ret._id;
      delete ret._id;
    },
  },
}));

const main = async () => {
  const mongooseOptions = {useNewUrlParser: true};
  const databaseUrl = process.env.DATABASE_URL || 'mongodb://localhost:27017/kitty-db';
  await mongoose.connect(databaseUrl, mongooseOptions);
  const port = process.env.PORT || 3000;
  app.listen(port);
  console.log(`Server started at http://localhost:${port}`);
};

main();

Example logs

{"timestamp":"2019-04-25T09:36:16.758Z","correlationID":"932fc631-aed2-4988-af50-1f12e6c82a3f","method":"POST","uri":"/cat","statusCode":200,"params":{},"headers":{"content-type":"application/json","authorization":"[REDACTED]","x-correlation-id":"932fc631-aed2-4988-af50-1f12e6c82a3f","user-agent":"vscode-restclient","accept-encoding":"gzip","host":"localhost:3000","content-length":"44","connection":"close"},"body":{"name":"Bob","password":"[REDACTED]"},"ip":"::ffff:127.0.0.1","actor":{"sub":"1234567890","name":"John Doe","admin":true,"iat":1516239022}}
{"timestamp":"2019-04-25T09:36:25.466Z","correlationID":"b64f81b2-ab31-45a3-97dc-34bb95061cf2","method":"PUT","uri":"/cat/5cc17f9013fd2c0e84df27a1","statusCode":200,"params":{"id":"5cc17f9013fd2c0e84df27a1"},"headers":{"authorization":"[REDACTED]","x-correlation-id":"b64f81b2-ab31-45a3-97dc-34bb95061cf2","content-type":"application/json","user-agent":"vscode-restclient","accept-encoding":"gzip","host":"localhost:3000","content-length":"21","connection":"close"},"body":{"name":"Furry"},"ip":"::ffff:127.0.0.1","actor":{"sub":"1234567890","name":"John Doe","admin":true,"iat":1516239022}}
{"timestamp":"2019-04-25T09:36:27.487Z","correlationID":"b33d0a82-ace7-44b3-9d36-f36218cec4dc","method":"DELETE","uri":"/cat/5cc17f9013fd2c0e84df27a1","statusCode":204,"params":{"id":"5cc17f9013fd2c0e84df27a1"},"headers":{"authorization":"[REDACTED]","x-correlation-id":"b33d0a82-ace7-44b3-9d36-f36218cec4dc","user-agent":"vscode-restclient","accept-encoding":"gzip","host":"localhost:3000","content-length":"0","connection":"close"},"body":{},"ip":"::ffff:127.0.0.1","actor":{"sub":"1234567890","name":"John Doe","admin":true,"iat":1516239022}}