auth.js 2.4 KB

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