auth.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. const assert = require('assert');
  2. const crypto = require('crypto');
  3. const storage = require('../storage');
  4. const fxa = require('../fxa');
  5. module.exports = {
  6. hmac: async function(req, res, next) {
  7. const id = req.params.id;
  8. const authHeader = req.header('Authorization');
  9. if (id && authHeader) {
  10. try {
  11. const auth = req.header('Authorization').split(' ')[1];
  12. const meta = await storage.metadata(id);
  13. if (!meta) {
  14. return res.sendStatus(404);
  15. }
  16. const hmac = crypto.createHmac(
  17. 'sha256',
  18. Buffer.from(meta.auth, 'base64')
  19. );
  20. hmac.update(Buffer.from(meta.nonce, 'base64'));
  21. const verifyHash = hmac.digest();
  22. if (crypto.timingSafeEqual(verifyHash, Buffer.from(auth, 'base64'))) {
  23. req.nonce = crypto.randomBytes(16).toString('base64');
  24. storage.setField(id, 'nonce', req.nonce);
  25. res.set('WWW-Authenticate', `send-v1 ${req.nonce}`);
  26. req.authorized = true;
  27. req.meta = meta;
  28. } else {
  29. res.set('WWW-Authenticate', `send-v1 ${meta.nonce}`);
  30. req.authorized = false;
  31. }
  32. } catch (e) {
  33. req.authorized = false;
  34. }
  35. }
  36. if (req.authorized) {
  37. next();
  38. } else {
  39. res.sendStatus(401);
  40. }
  41. },
  42. owner: async function(req, res, next) {
  43. const id = req.params.id;
  44. const ownerToken = req.body.owner_token;
  45. if (id && ownerToken) {
  46. try {
  47. req.meta = await storage.metadata(id);
  48. if (!req.meta) {
  49. return res.sendStatus(404);
  50. }
  51. const metaOwner = Buffer.from(req.meta.owner, 'utf8');
  52. const owner = Buffer.from(ownerToken, 'utf8');
  53. assert(metaOwner.length > 0);
  54. assert(metaOwner.length === owner.length);
  55. req.authorized = crypto.timingSafeEqual(metaOwner, owner);
  56. } catch (e) {
  57. req.authorized = false;
  58. }
  59. }
  60. if (req.authorized) {
  61. next();
  62. } else {
  63. res.sendStatus(401);
  64. }
  65. },
  66. fxa: async function(req, res, next) {
  67. const authHeader = req.header('Authorization');
  68. if (authHeader && /^Bearer\s/i.test(authHeader)) {
  69. const token = authHeader.split(' ')[1];
  70. req.user = await fxa.verify(token);
  71. }
  72. return next();
  73. }
  74. };