token.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. var fernet = require('../fernet');
  2. //TokenFoctory
  3. module = module.exports = function (parent) {
  4. var Token = function Token(opts) {
  5. opts = opts || {};
  6. this.secret = opts.secret || parent.secret;
  7. this.ttl = opts.ttl || parent.ttl;
  8. if (opts.ttl === 0) this.ttl = 0;
  9. this.message = opts.message;
  10. this.cipherText = opts.cipherText;
  11. this.token = opts.token;
  12. this.version = opts.version || fernet.parseHex(parent.versionHex);
  13. this.optsIV = opts.iv;
  14. this.maxClockSkew = 60;
  15. if (opts.time) this.setTime(Date.parse(opts.time));
  16. else this.setTime();
  17. }
  18. Token.prototype = {
  19. setIV: fernet.setIV,
  20. setTime: function tokenSetTime(time) {
  21. this.time = fernet.timeBytes(time);
  22. },
  23. toString: function tokenToString() {
  24. if (this.encoded) {
  25. return this.token
  26. } else {
  27. return this.message
  28. }
  29. },
  30. encode: function encodeToken(message) {
  31. if (!this.secret) throw (new Error("Secret not set"));
  32. this.encoded = true;
  33. this.setIV(this.optsIV); //if null will always be a fresh IV
  34. this.message = message || this.message;
  35. this.cipherText = fernet.encryptMessage(this.message, this.secret.encryptionKey, this.iv);
  36. this.token = fernet.createToken(this.secret.signingKey, this.time, this.iv, this.cipherText)
  37. return this.token;
  38. },
  39. decode: function decodeToken(token) {
  40. if (!this.secret) throw (new Error("Secret not set"));
  41. this.encoded = false;
  42. this.token = token || this.token;
  43. var tokenString = fernet.decode64toHex(this.token);
  44. var versionOffset = fernet.hexBits(8);
  45. var timeOffset = versionOffset + fernet.hexBits(64);
  46. var ivOffset = timeOffset + fernet.hexBits(128);
  47. var hmacOffset = tokenString.length - fernet.hexBits(256);
  48. var timeInt = fernet.parseHex(tokenString.slice(versionOffset, timeOffset));
  49. this.version = fernet.parseHex(tokenString.slice(0, versionOffset));
  50. if (this.version != 128) {
  51. throw new Error("Invalid version");
  52. }
  53. this.time = new Date(timeInt * 1000);
  54. var currentTime = new Date()
  55. var timeDiff = (currentTime - this.time) / 1000;
  56. if (this.ttl > 0) {
  57. if (timeDiff > this.ttl) {
  58. throw new Error("Invalid Token: TTL");
  59. }
  60. if (((currentTime / 1000) + this.maxClockSkew) < timeInt) {
  61. throw new Error("far-future timestamp");
  62. }
  63. }
  64. this.ivHex = tokenString.slice(timeOffset, ivOffset);
  65. this.iv = fernet.Hex.parse(this.ivHex);
  66. this.cipherTextHex = tokenString.slice(ivOffset, hmacOffset);
  67. this.cipherText = fernet.Hex.parse(this.cipherTextHex);
  68. this.hmacHex = tokenString.slice(hmacOffset);
  69. var decodedHmac = fernet.createHmac(this.secret.signingKey, fernet.timeBytes(this.time), this.iv, this.cipherText);
  70. var decodedHmacHex = decodedHmac.toString(fernet.Hex);
  71. var accum = 0
  72. for (var i = 0; i < 64; i++) {
  73. accum += decodedHmacHex.charCodeAt(i) ^ this.hmacHex.charCodeAt(i)
  74. }
  75. if (accum != 0) throw new Error("Invalid Token: HMAC");
  76. this.message = fernet.decryptMessage(this.cipherText, this.secret.encryptionKey, this.iv)
  77. return this.message;
  78. }
  79. }
  80. return Token;
  81. }
  82. //exports = module.exports = Token;