@dr.pogodin/csurf
Version:
CSRF token middleware for ExpressJS
1 lines • 5.82 kB
Source Map (JSON)
{"version":3,"file":"tokens.mjs","names":["crypto","rndm","uid","compare","EQUAL_GLOBAL_REGEXP","PLUS_GLOBAL_REGEXP","SLASH_GLOBAL_REGEXP","hash","str","createHash","update","digest","replace","privateTokenize","secret","salt","verify","token","index","indexOf","slice","expected","Tokens","constructor","options","opts","saltLength","Number","isFinite","TypeError","secretLength","create","callback","undefined","secretSync","sync"],"sources":["../../src/tokens.ts"],"sourcesContent":["import crypto from 'crypto';\n\nimport rndm from 'rndm';\nimport uid from 'uid-safe';\nimport compare from 'tsscmp';\n\nconst EQUAL_GLOBAL_REGEXP = /=/g;\nconst PLUS_GLOBAL_REGEXP = /\\+/g;\nconst SLASH_GLOBAL_REGEXP = /\\//g;\n\n/**\n * Hash a string with SHA256, returning url-safe base64.\n */\nfunction hash(str: string): string {\n return crypto\n .createHash('sha256')\n .update(str, 'ascii')\n .digest('base64')\n .replace(PLUS_GLOBAL_REGEXP, '-')\n .replace(SLASH_GLOBAL_REGEXP, '_')\n .replace(EQUAL_GLOBAL_REGEXP, '');\n}\n\n/**\n * Tokenize a secret and salt.\n */\nfunction privateTokenize(secret: string, salt: string): string {\n return `${salt}-${hash(`${salt}-${secret}`)}`;\n}\n\n/**\n * Verify if a given token is valid for a given secret.\n */\nexport function verify(secret: string, token: string): boolean {\n if (!secret || typeof secret !== 'string') {\n return false;\n }\n\n if (!token || typeof token !== 'string') {\n return false;\n }\n\n const index = token.indexOf('-');\n\n if (index === -1) {\n return false;\n }\n\n const salt = token.slice(0, index);\n const expected = privateTokenize(secret, salt);\n\n return compare(token, expected);\n}\n\nexport type Options = {\n saltLength?: number;\n secretLength?: number;\n};\n\n/**\n * Token generation/verification class.\n */\nexport default class Tokens {\n private saltLength: number;\n private secretLength: number;\n\n /**\n * @param [options]\n * @param [options.saltLength=8] The string length of the salt\n * @param [options.secretLength=18] The byte length of the secret key\n */\n constructor(options?: Options) {\n const opts = options ?? {};\n\n const saltLength = opts.saltLength ?? 8;\n\n if (typeof saltLength !== 'number' || !Number.isFinite(saltLength) || saltLength < 1) {\n throw new TypeError('option saltLength must be finite number > 1');\n }\n\n const secretLength = opts.secretLength ?? 18;\n\n if (typeof secretLength !== 'number' || !Number.isFinite(secretLength) || secretLength < 1) {\n throw new TypeError('option secretLength must be finite number > 1');\n }\n\n this.saltLength = saltLength;\n this.secretLength = secretLength;\n }\n\n /**\n * Create a new CSRF token.\n *\n * @param secret The secret for the token.\n */\n create(secret: string): string {\n if (!secret || typeof secret !== 'string') {\n throw new TypeError('argument secret is required');\n }\n\n return privateTokenize(secret, rndm(this.saltLength));\n }\n\n secret(): Promise<string>;\n secret(callback: (err: unknown, str: string) => void): void;\n\n /**\n * Create a new secret key.\n */\n secret(\n callback?: (err: unknown, str: string) => void,\n ): Promise<string> | undefined {\n if (callback) {\n uid(this.secretLength, callback);\n return undefined;\n }\n\n return uid(this.secretLength);\n }\n\n /**\n * Create a new secret key synchronously.\n */\n secretSync(): string {\n return uid.sync(this.secretLength);\n }\n}\n"],"mappings":"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","ignoreList":[]}