cybertoken 5.1.0 → 5.1.1
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/.oxfmtrc.json +5 -0
- package/dist/cli.mjs +2 -5
- package/dist/index.mjs +2 -54
- package/dist/{parse-B28-mi8z.mjs → src-BbnMQEpi.mjs} +53 -8
- package/package.json +24 -20
package/.oxfmtrc.json
ADDED
package/dist/cli.mjs
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./
|
|
3
|
-
import { createTokenGenerator } from "./index.mjs";
|
|
4
|
-
|
|
2
|
+
import { t as createTokenGenerator } from "./src-BbnMQEpi.mjs";
|
|
5
3
|
//#region src/cli.ts
|
|
6
4
|
const prefixWithoutUnderscore = process.argv[2] ?? process.env.CYBERTOKEN_PREFIX;
|
|
7
5
|
if (!prefixWithoutUnderscore) {
|
|
@@ -18,6 +16,5 @@ if (!prefixWithoutUnderscore) {
|
|
|
18
16
|
}
|
|
19
17
|
const token = createTokenGenerator({ prefixWithoutUnderscore }).generateToken();
|
|
20
18
|
console.log(token);
|
|
21
|
-
|
|
22
19
|
//#endregion
|
|
23
|
-
export {
|
|
20
|
+
export {};
|
package/dist/index.mjs
CHANGED
|
@@ -1,54 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
//#region src/index.ts
|
|
4
|
-
const prefixCheck = /^[a-zA-Z0-9_]+$/;
|
|
5
|
-
/**
|
|
6
|
-
* Creates a new {@link TokenGenerator}.
|
|
7
|
-
* @param {TokenGeneratorOptions} options Options bag.
|
|
8
|
-
*/
|
|
9
|
-
function createTokenGenerator(options) {
|
|
10
|
-
if (!options.prefixWithoutUnderscore) throw new Error("The `prefixWithoutUnderscore` option is required and must not be an empty string.");
|
|
11
|
-
if (!prefixCheck.test(options.prefixWithoutUnderscore) || options.prefixWithoutUnderscore.endsWith("_")) throw new Error("The `prefixWithoutUnderscore` option must only contain alphanumeric characters and underscores. It must not end with an underscore.");
|
|
12
|
-
const prefixWithUnderscore = `${options.prefixWithoutUnderscore}_`;
|
|
13
|
-
const tokenPattern = getTokenPattern(prefixWithUnderscore);
|
|
14
|
-
const tokenSecretByteCount = options.entropyBytes ?? 20;
|
|
15
|
-
if (tokenSecretByteCount < 20 || tokenSecretByteCount >= 100) throw new Error("The token secret byte count (`entropyBytes`) must be >= 20 and < 100.");
|
|
16
|
-
return {
|
|
17
|
-
generateToken,
|
|
18
|
-
isTokenString
|
|
19
|
-
};
|
|
20
|
-
function generateToken() {
|
|
21
|
-
const tokenData = generateTokenData();
|
|
22
|
-
return prefixWithUnderscore + encode(tokenData);
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* @remarks As the token generation uses cryptographically secure random numbers, keep in mind that generating a large amount of tokens will block the entire application for a short amount of time (until the entropy pool is filled again).
|
|
26
|
-
* This can lead to a Denial of Service (DoS) attack, so you might want to limit the amount of tokens that can be generated in a short amount of time.
|
|
27
|
-
*/
|
|
28
|
-
function generateTokenData() {
|
|
29
|
-
const entropyWithVersion = globalThis.crypto.getRandomValues(new Uint8Array(tokenSecretByteCount + 1));
|
|
30
|
-
entropyWithVersion[entropyWithVersion.length - 1] = version;
|
|
31
|
-
const checksum = crc32(entropyWithVersion);
|
|
32
|
-
console.assert(checksum.byteLength === 4);
|
|
33
|
-
const payloadWithChecksum = new Uint8Array(entropyWithVersion.byteLength + checksum.byteLength);
|
|
34
|
-
payloadWithChecksum.set(entropyWithVersion, 0);
|
|
35
|
-
payloadWithChecksum.set(checksum, entropyWithVersion.byteLength);
|
|
36
|
-
console.assert(payloadWithChecksum.length === tokenSecretByteCount + 4 + 1);
|
|
37
|
-
return payloadWithChecksum;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Function to check if a token is syntactically valid. **Not** used for token validation.
|
|
41
|
-
* You can use this for secret scanning or as a heuristic/optimization before asking some backend whether the token is valid.
|
|
42
|
-
*
|
|
43
|
-
* @param {boolean} value The token candidate to check.
|
|
44
|
-
* @returns `true` if the token is syntactically valid, `false` otherwise.
|
|
45
|
-
*/
|
|
46
|
-
function isTokenString(value) {
|
|
47
|
-
if (!value || typeof value !== "string" || !value.startsWith(prefixWithUnderscore) || !tokenPattern.test(value)) return false;
|
|
48
|
-
const tokenData = parseTokenData(value);
|
|
49
|
-
return !!tokenData && tokenData.isSyntacticallyValid;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
//#endregion
|
|
54
|
-
export { createTokenGenerator };
|
|
1
|
+
import { t as createTokenGenerator } from "./src-BbnMQEpi.mjs";
|
|
2
|
+
export { createTokenGenerator };
|
|
@@ -333,7 +333,6 @@ function decode(string) {
|
|
|
333
333
|
if (buffer) return buffer;
|
|
334
334
|
throw new Error("Failed to decode string");
|
|
335
335
|
}
|
|
336
|
-
|
|
337
336
|
//#endregion
|
|
338
337
|
//#region src/crc32.ts
|
|
339
338
|
const table = new Uint32Array([
|
|
@@ -602,10 +601,6 @@ function crc32(inputBuffer) {
|
|
|
602
601
|
new DataView(result.buffer).setUint32(0, (crc ^ -1) >>> 0);
|
|
603
602
|
return result;
|
|
604
603
|
}
|
|
605
|
-
|
|
606
|
-
//#endregion
|
|
607
|
-
//#region src/parse.ts
|
|
608
|
-
const version = 0;
|
|
609
604
|
function getTokenPattern(prefixWithUnderscore) {
|
|
610
605
|
return new RegExp(`^${prefixWithUnderscore}[${alphabet}]+$`);
|
|
611
606
|
}
|
|
@@ -627,7 +622,7 @@ function parseTokenData(token) {
|
|
|
627
622
|
const actualChecksum = crc32(secretAndVersionBuffer);
|
|
628
623
|
const isSyntacticallyValid = secretAndVersionBuffer.length > 0 && buffersEqual(suppliedChecksum, actualChecksum);
|
|
629
624
|
const suppliedVersion = secretAndVersionBuffer[secretAndVersionBuffer.length - 1];
|
|
630
|
-
if (suppliedVersion !==
|
|
625
|
+
if (suppliedVersion !== 0) return;
|
|
631
626
|
return {
|
|
632
627
|
version: suppliedVersion,
|
|
633
628
|
prefixWithoutUnderscore: prefix,
|
|
@@ -642,6 +637,56 @@ function buffersEqual(a, b) {
|
|
|
642
637
|
for (let i = 0; i < a.byteLength; ++i) if (a[i] !== b[i]) return false;
|
|
643
638
|
return true;
|
|
644
639
|
}
|
|
645
|
-
|
|
646
640
|
//#endregion
|
|
647
|
-
|
|
641
|
+
//#region src/index.ts
|
|
642
|
+
const prefixCheck = /^[a-zA-Z0-9_]+$/;
|
|
643
|
+
/**
|
|
644
|
+
* Creates a new {@link TokenGenerator}.
|
|
645
|
+
* @param {TokenGeneratorOptions} options Options bag.
|
|
646
|
+
*/
|
|
647
|
+
function createTokenGenerator(options) {
|
|
648
|
+
const prefix = options.prefixWithoutUnderscore;
|
|
649
|
+
if (!prefix || typeof prefix !== "string") throw new Error("The `prefixWithoutUnderscore` option is required and must not be an empty string.");
|
|
650
|
+
if (prefix.length < 2 || prefix.length > 10) throw new Error("The `prefixWithoutUnderscore` option must be between 2 and 10 characters long.");
|
|
651
|
+
if (prefix.endsWith("_") || !prefixCheck.test(prefix)) throw new Error("The `prefixWithoutUnderscore` option must only contain alphanumeric characters and underscores. It must not end with an underscore.");
|
|
652
|
+
const prefixWithUnderscore = `${options.prefixWithoutUnderscore}_`;
|
|
653
|
+
const tokenPattern = getTokenPattern(prefixWithUnderscore);
|
|
654
|
+
const tokenSecretByteCount = options.entropyBytes ?? 20;
|
|
655
|
+
if (tokenSecretByteCount < 20 || tokenSecretByteCount >= 100) throw new Error("The token secret byte count (`entropyBytes`) must be >= 20 and < 100.");
|
|
656
|
+
return {
|
|
657
|
+
generateToken,
|
|
658
|
+
isTokenString
|
|
659
|
+
};
|
|
660
|
+
function generateToken() {
|
|
661
|
+
return prefixWithUnderscore + encode(generateTokenData());
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* @remarks As the token generation uses cryptographically secure random numbers, keep in mind that generating a large amount of tokens will block the entire application for a short amount of time (until the entropy pool is filled again).
|
|
665
|
+
* This can lead to a Denial of Service (DoS) attack, so you might want to limit the amount of tokens that can be generated in a short amount of time.
|
|
666
|
+
*/
|
|
667
|
+
function generateTokenData() {
|
|
668
|
+
const entropyWithVersion = globalThis.crypto.getRandomValues(new Uint8Array(tokenSecretByteCount + 1));
|
|
669
|
+
entropyWithVersion[entropyWithVersion.length - 1] = 0;
|
|
670
|
+
const checksum = crc32(entropyWithVersion);
|
|
671
|
+
console.assert(checksum.byteLength === 4);
|
|
672
|
+
const payloadWithChecksum = new Uint8Array(entropyWithVersion.byteLength + checksum.byteLength);
|
|
673
|
+
payloadWithChecksum.set(entropyWithVersion, 0);
|
|
674
|
+
payloadWithChecksum.set(checksum, entropyWithVersion.byteLength);
|
|
675
|
+
console.assert(payloadWithChecksum.length === tokenSecretByteCount + 4 + 1);
|
|
676
|
+
return payloadWithChecksum;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Function to check if a token is syntactically valid. **Not** used for token validation.
|
|
680
|
+
* You can use this for secret scanning or as a heuristic/optimization before asking some backend whether the token is valid.
|
|
681
|
+
*
|
|
682
|
+
* @param {boolean} value The token candidate to check.
|
|
683
|
+
* @returns `true` if the token is syntactically valid, `false` otherwise.
|
|
684
|
+
*/
|
|
685
|
+
function isTokenString(value) {
|
|
686
|
+
if (!value || typeof value !== "string" || !value.startsWith(prefixWithUnderscore) || !tokenPattern.test(value)) return false;
|
|
687
|
+
const tokenData = parseTokenData(value);
|
|
688
|
+
return !!tokenData && tokenData.isSyntacticallyValid;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
//#endregion
|
|
692
|
+
export { createTokenGenerator as t };
|
package/package.json
CHANGED
|
@@ -1,39 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cybertoken",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.1",
|
|
4
4
|
"description": "A token format for APIs inspired by the GitHub's API token format.",
|
|
5
|
-
"
|
|
5
|
+
"keywords": [
|
|
6
|
+
"api",
|
|
7
|
+
"format",
|
|
8
|
+
"generator",
|
|
9
|
+
"secret",
|
|
10
|
+
"token"
|
|
11
|
+
],
|
|
6
12
|
"license": "ISC",
|
|
7
|
-
"
|
|
8
|
-
"main": "dist/index.mjs",
|
|
9
|
-
"bin": "dist/cli.mjs",
|
|
10
|
-
"types": "dist/index.d.mts",
|
|
13
|
+
"author": "Niklas Mollenhauer",
|
|
11
14
|
"repository": {
|
|
12
15
|
"type": "git",
|
|
13
16
|
"url": "https://github.com/nikeee/cybertoken.git"
|
|
14
17
|
},
|
|
18
|
+
"bin": "dist/cli.mjs",
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "dist/index.mjs",
|
|
21
|
+
"types": "dist/index.d.mts",
|
|
15
22
|
"scripts": {
|
|
16
23
|
"build": "tsdown",
|
|
17
|
-
"ci": "
|
|
24
|
+
"ci": "oxlint --type-aware --type-check --deny-warnings -f github",
|
|
18
25
|
"docs": "typedoc",
|
|
19
|
-
"format": "
|
|
26
|
+
"format": "oxfmt",
|
|
27
|
+
"lint": "oxlint --type-aware",
|
|
28
|
+
"lint:fix": "oxlint --type-aware --fix",
|
|
20
29
|
"test": "tsc --noEmit && node --test",
|
|
21
30
|
"test:coverage": "node --test --experimental-test-coverage",
|
|
22
31
|
"prepublishOnly": "npm run build"
|
|
23
32
|
},
|
|
24
|
-
"keywords": [
|
|
25
|
-
"token",
|
|
26
|
-
"api",
|
|
27
|
-
"format",
|
|
28
|
-
"secret",
|
|
29
|
-
"generator"
|
|
30
|
-
],
|
|
31
33
|
"devDependencies": {
|
|
32
|
-
"@
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
34
|
+
"@types/node": "^25.5.0",
|
|
35
|
+
"expect": "^30.3.0",
|
|
36
|
+
"oxfmt": "^0.41.0",
|
|
37
|
+
"oxlint": "^1.56.0",
|
|
38
|
+
"oxlint-tsgolint": "^0.17.0",
|
|
39
|
+
"tsdown": "^0.21.4",
|
|
40
|
+
"typedoc": "^0.28.17"
|
|
37
41
|
},
|
|
38
42
|
"engines": {
|
|
39
43
|
"node": ">=20"
|