@prairielearn/signed-token 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @prairielearn/signed-token
2
2
 
3
+ ## 2.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 0f7c90f: Upgrade all JavaScript dependencies
8
+
9
+ ## 2.0.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 901fce8: Upgrade all JavaScript dependencies
14
+
3
15
  ## 2.0.0
4
16
 
5
17
  ### Major Changes
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
+ import crypto from 'node:crypto';
1
2
  import base64url from 'base64url';
2
3
  import debugfn from 'debug';
3
4
  import _ from 'lodash';
4
- import crypto from 'node:crypto';
5
5
  const debug = debugfn('prairielearn:csrf');
6
6
  const sep = '.';
7
7
  export function generateSignedToken(data, secretKey) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import base64url from 'base64url';\nimport debugfn from 'debug';\nimport _ from 'lodash';\nimport crypto from 'node:crypto';\n\nconst debug = debugfn('prairielearn:csrf');\nconst sep = '.';\n\ninterface CheckOptions {\n maxAge?: number;\n}\n\nexport function generateSignedToken(data: any, secretKey: string) {\n debug(`generateSignedToken(): data = ${JSON.stringify(data)}`);\n debug(`generateSignedToken(): secretKey = ${secretKey}`);\n const dataJSON = JSON.stringify(data);\n const dataString = base64url.default.encode(dataJSON);\n const dateString = new Date().getTime().toString(36);\n const checkString = dateString + sep + dataString;\n const signature = crypto.createHmac('sha256', secretKey).update(checkString).digest('hex');\n const encodedSignature = base64url.default.encode(signature);\n debug(\n `generateSignedToken(): ${JSON.stringify({\n dataString,\n dateString,\n checkString,\n encodedSignature,\n })}`,\n );\n const token = encodedSignature + sep + checkString;\n debug(`generateSignedToken(): token = ${token}`);\n return token;\n}\n\nexport function getCheckedSignedTokenData(\n token: string,\n secretKey: string,\n options: CheckOptions = {},\n) {\n debug(`getCheckedSignedTokenData(): token = ${token}`);\n debug(`getCheckedSignedTokenData(): secretKey = ${secretKey}`);\n debug(`getCheckedSignedTokenData(): options = ${JSON.stringify(options)}`);\n if (!_.isString(token)) {\n debug(`getCheckedSignedTokenData(): FAIL - token is not string`);\n return null;\n }\n\n // break token apart into the three components\n const match = token.split(sep);\n if (match == null) {\n debug(`getCheckedSignedTokenData(): FAIL - could not split token`);\n return null;\n }\n const tokenSignature = match[0];\n const tokenDateString = match[1];\n const tokenDataString = match[2];\n\n // check the signature\n const checkString = tokenDateString + sep + tokenDataString;\n const checkSignature = crypto.createHmac('sha256', secretKey).update(checkString).digest('hex');\n const encodedCheckSignature = base64url.default.encode(checkSignature);\n if (encodedCheckSignature !== tokenSignature) {\n debug(\n `getCheckedSignedTokenData(): FAIL - signature mismatch: checkSig=${encodedCheckSignature} != tokenSig=${tokenSignature}`,\n );\n return null;\n }\n\n // check the age if we have the maxAge parameter\n if (options.maxAge != null) {\n let tokenDate;\n try {\n tokenDate = new Date(parseInt(tokenDateString, 36));\n } catch (e) {\n debug(`getCheckedSignedTokenData(): FAIL - could not parse date: ${tokenDateString}`);\n return null;\n }\n const currentTime = Date.now();\n const elapsedTime = currentTime - tokenDate.getTime();\n if (elapsedTime > options.maxAge) {\n debug(\n `getCheckedSignedTokenData(): FAIL - too old: elapsedTime=${elapsedTime} > maxAge=${options.maxAge}`,\n );\n return null;\n }\n }\n\n // get the data\n let tokenDataJSON, tokenData;\n try {\n tokenDataJSON = base64url.default.decode(tokenDataString);\n } catch (e) {\n debug(`getCheckedSignedTokenData(): FAIL - could not base64 decode: ${tokenDateString}`);\n return null;\n }\n try {\n tokenData = JSON.parse(tokenDataJSON);\n } catch (e) {\n debug(`getCheckedSignedTokenData(): FAIL - could not parse JSON: ${tokenDataJSON}`);\n return null;\n }\n debug(`getCheckedSignedTokenData(): tokenData = ${tokenData}`);\n return tokenData;\n}\n\nexport function checkSignedToken(\n token: string,\n data: any,\n secretKey: string,\n options: CheckOptions = {},\n) {\n debug(`checkSignedToken(): token = ${token}`);\n debug(`checkSignedToken(): data = ${JSON.stringify(data)}`);\n debug(`checkSignedToken(): secretKey = ${secretKey}`);\n debug(`checkSignedToken(): options = ${JSON.stringify(options)}`);\n debug(`checkSignedToken(): data = ${JSON.stringify(data)}`);\n const tokenData = getCheckedSignedTokenData(token, secretKey, options);\n debug(`checkSignedToken(): tokenData = ${JSON.stringify(tokenData)}`);\n if (tokenData == null) return false;\n if (!_.isEqual(data, tokenData)) return false;\n return true;\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from 'node:crypto';\n\nimport base64url from 'base64url';\nimport debugfn from 'debug';\nimport _ from 'lodash';\n\nconst debug = debugfn('prairielearn:csrf');\nconst sep = '.';\n\ninterface CheckOptions {\n maxAge?: number;\n}\n\nexport function generateSignedToken(data: any, secretKey: string) {\n debug(`generateSignedToken(): data = ${JSON.stringify(data)}`);\n debug(`generateSignedToken(): secretKey = ${secretKey}`);\n const dataJSON = JSON.stringify(data);\n const dataString = base64url.default.encode(dataJSON);\n const dateString = new Date().getTime().toString(36);\n const checkString = dateString + sep + dataString;\n const signature = crypto.createHmac('sha256', secretKey).update(checkString).digest('hex');\n const encodedSignature = base64url.default.encode(signature);\n debug(\n `generateSignedToken(): ${JSON.stringify({\n dataString,\n dateString,\n checkString,\n encodedSignature,\n })}`,\n );\n const token = encodedSignature + sep + checkString;\n debug(`generateSignedToken(): token = ${token}`);\n return token;\n}\n\nexport function getCheckedSignedTokenData(\n token: string,\n secretKey: string,\n options: CheckOptions = {},\n) {\n debug(`getCheckedSignedTokenData(): token = ${token}`);\n debug(`getCheckedSignedTokenData(): secretKey = ${secretKey}`);\n debug(`getCheckedSignedTokenData(): options = ${JSON.stringify(options)}`);\n if (!_.isString(token)) {\n debug(`getCheckedSignedTokenData(): FAIL - token is not string`);\n return null;\n }\n\n // break token apart into the three components\n const match = token.split(sep);\n if (match == null) {\n debug(`getCheckedSignedTokenData(): FAIL - could not split token`);\n return null;\n }\n const tokenSignature = match[0];\n const tokenDateString = match[1];\n const tokenDataString = match[2];\n\n // check the signature\n const checkString = tokenDateString + sep + tokenDataString;\n const checkSignature = crypto.createHmac('sha256', secretKey).update(checkString).digest('hex');\n const encodedCheckSignature = base64url.default.encode(checkSignature);\n if (encodedCheckSignature !== tokenSignature) {\n debug(\n `getCheckedSignedTokenData(): FAIL - signature mismatch: checkSig=${encodedCheckSignature} != tokenSig=${tokenSignature}`,\n );\n return null;\n }\n\n // check the age if we have the maxAge parameter\n if (options.maxAge != null) {\n let tokenDate;\n try {\n tokenDate = new Date(parseInt(tokenDateString, 36));\n } catch (e) {\n debug(`getCheckedSignedTokenData(): FAIL - could not parse date: ${tokenDateString}`);\n return null;\n }\n const currentTime = Date.now();\n const elapsedTime = currentTime - tokenDate.getTime();\n if (elapsedTime > options.maxAge) {\n debug(\n `getCheckedSignedTokenData(): FAIL - too old: elapsedTime=${elapsedTime} > maxAge=${options.maxAge}`,\n );\n return null;\n }\n }\n\n // get the data\n let tokenDataJSON, tokenData;\n try {\n tokenDataJSON = base64url.default.decode(tokenDataString);\n } catch (e) {\n debug(`getCheckedSignedTokenData(): FAIL - could not base64 decode: ${tokenDateString}`);\n return null;\n }\n try {\n tokenData = JSON.parse(tokenDataJSON);\n } catch (e) {\n debug(`getCheckedSignedTokenData(): FAIL - could not parse JSON: ${tokenDataJSON}`);\n return null;\n }\n debug(`getCheckedSignedTokenData(): tokenData = ${tokenData}`);\n return tokenData;\n}\n\nexport function checkSignedToken(\n token: string,\n data: any,\n secretKey: string,\n options: CheckOptions = {},\n) {\n debug(`checkSignedToken(): token = ${token}`);\n debug(`checkSignedToken(): data = ${JSON.stringify(data)}`);\n debug(`checkSignedToken(): secretKey = ${secretKey}`);\n debug(`checkSignedToken(): options = ${JSON.stringify(options)}`);\n debug(`checkSignedToken(): data = ${JSON.stringify(data)}`);\n const tokenData = getCheckedSignedTokenData(token, secretKey, options);\n debug(`checkSignedToken(): tokenData = ${JSON.stringify(tokenData)}`);\n if (tokenData == null) return false;\n if (!_.isEqual(data, tokenData)) return false;\n return true;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prairielearn/signed-token",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "repository": {
@@ -12,16 +12,15 @@
12
12
  "build": "tsc",
13
13
  "dev": "tsc --watch --preserveWatchOutput"
14
14
  },
15
- "devDependencies": {
16
- "@prairielearn/tsconfig": "*",
17
- "@types/debug": "^4.1.12",
18
- "@types/node": "^20.12.2",
19
- "mocha": "^10.4.0",
20
- "typescript": "^5.4.3"
21
- },
22
15
  "dependencies": {
23
16
  "base64url": "^3.0.1",
24
- "debug": "^4.3.4",
17
+ "debug": "^4.3.5",
25
18
  "lodash": "^4.17.21"
19
+ },
20
+ "devDependencies": {
21
+ "@prairielearn/tsconfig": "*",
22
+ "@types/debug": "^4.1.12",
23
+ "@types/node": "^20.13.0",
24
+ "typescript": "^5.4.5"
26
25
  }
27
26
  }
package/src/index.ts CHANGED
@@ -1,7 +1,8 @@
1
+ import crypto from 'node:crypto';
2
+
1
3
  import base64url from 'base64url';
2
4
  import debugfn from 'debug';
3
5
  import _ from 'lodash';
4
- import crypto from 'node:crypto';
5
6
 
6
7
  const debug = debugfn('prairielearn:csrf');
7
8
  const sep = '.';