jsonauthtoken 1.0.1 → 3.0.0
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/README.md +14 -35
- package/dist/config/algo.config.d.ts +2 -0
- package/dist/config/algo.config.js +28 -0
- package/dist/config/name.config.d.ts +1 -0
- package/dist/config/name.config.js +4 -0
- package/dist/config/runtime.config.d.ts +1 -0
- package/dist/config/runtime.config.js +15 -0
- package/dist/crypto/crypto.d.ts +12 -0
- package/dist/crypto/crypto.js +152 -0
- package/dist/crypto/node.crypto.d.ts +29 -0
- package/dist/crypto/node.crypto.js +105 -0
- package/dist/crypto/web.crypto.d.ts +38 -0
- package/dist/crypto/web.crypto.js +180 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +133 -0
- package/dist/lib/decoading.lib.d.ts +2 -0
- package/dist/lib/decoading.lib.js +9 -0
- package/dist/lib/encoading.lib.d.ts +2 -0
- package/{lib → dist/lib}/encoading.lib.js +8 -7
- package/dist/lib/functions.lib.d.ts +12 -0
- package/dist/lib/functions.lib.js +85 -0
- package/dist/lib/timeformat.d.ts +1 -0
- package/dist/lib/timeformat.js +42 -0
- package/package.json +15 -10
- package/types.d.ts +67 -0
- package/index.js +0 -84
- package/lib/decoading.lib.js +0 -14
- package/lib/decryption.lib.js +0 -18
- package/lib/encryption.lib.js +0 -15
- package/lib/functions.lib.js +0 -66
- package/lib/signature.lib.js +0 -26
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
declare class JATClass<R extends Runtime = Runtime> {
|
|
2
|
+
private runtime;
|
|
3
|
+
private dev;
|
|
4
|
+
private crypto;
|
|
5
|
+
constructor(config?: JATConfig<R>);
|
|
6
|
+
create(header: CreateTokenConfig<R>, payload: any): Promise<string>;
|
|
7
|
+
verify<T>(token: string, key: string): Promise<T>;
|
|
8
|
+
}
|
|
9
|
+
export declare const JAT: <R extends Runtime = Runtime>(config?: JATConfig<R>) => JATClass<R>;
|
|
10
|
+
export declare const getSupportedAlgorithm: () => Record<Runtime, AlgorithmDetails[]>;
|
|
11
|
+
export declare const P2KG: {
|
|
12
|
+
generateKeyPair: (options?: {
|
|
13
|
+
runtime?: Runtime;
|
|
14
|
+
dev?: boolean;
|
|
15
|
+
}) => Promise<GenerateKeyPair>;
|
|
16
|
+
generatePublicKey: (privateKeyPem: string, options?: {
|
|
17
|
+
runtime?: Runtime;
|
|
18
|
+
dev?: boolean;
|
|
19
|
+
}) => Promise<string>;
|
|
20
|
+
};
|
|
21
|
+
declare const jsonauthtoken: {
|
|
22
|
+
JAT: <R extends Runtime = Runtime>(config?: JATConfig<R>) => JATClass<R>;
|
|
23
|
+
P2KG: {
|
|
24
|
+
generateKeyPair: (options?: {
|
|
25
|
+
runtime?: Runtime;
|
|
26
|
+
dev?: boolean;
|
|
27
|
+
}) => Promise<GenerateKeyPair>;
|
|
28
|
+
generatePublicKey: (privateKeyPem: string, options?: {
|
|
29
|
+
runtime?: Runtime;
|
|
30
|
+
dev?: boolean;
|
|
31
|
+
}) => Promise<string>;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export default jsonauthtoken;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.P2KG = exports.getSupportedAlgorithm = exports.JAT = void 0;
|
|
4
|
+
const name_config_1 = require("./config/name.config");
|
|
5
|
+
const runtime_config_1 = require("./config/runtime.config");
|
|
6
|
+
const algo_config_1 = require("./config/algo.config");
|
|
7
|
+
const functions_lib_1 = require("./lib/functions.lib");
|
|
8
|
+
const timeformat_1 = require("./lib/timeformat");
|
|
9
|
+
const crypto_1 = require("./crypto/crypto");
|
|
10
|
+
class JATClass {
|
|
11
|
+
runtime;
|
|
12
|
+
dev = false;
|
|
13
|
+
crypto = new crypto_1.Crypto();
|
|
14
|
+
constructor(config) {
|
|
15
|
+
try {
|
|
16
|
+
if (config && config.dev == true)
|
|
17
|
+
this.dev = true;
|
|
18
|
+
if (config && config.runtime) {
|
|
19
|
+
if (!name_config_1.RUNTIME.includes(config.runtime)) {
|
|
20
|
+
throw new Error("Unsupported runtime");
|
|
21
|
+
}
|
|
22
|
+
this.runtime = config.runtime;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
this.runtime = (0, runtime_config_1.detectRuntime)();
|
|
26
|
+
}
|
|
27
|
+
(0, functions_lib_1.print)({ dev: this.dev }, 'Current Runtime: ', this.runtime);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
(0, functions_lib_1.print)({ dev: this.dev, color: 'red' }, error);
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async create(header, payload) {
|
|
35
|
+
try {
|
|
36
|
+
if (!header.key) {
|
|
37
|
+
throw new Error('key is required to create token');
|
|
38
|
+
}
|
|
39
|
+
const key = header.key;
|
|
40
|
+
const exp = header.exp ? (0, timeformat_1.jatTimeFormatter)(header.exp) : (0, timeformat_1.jatTimeFormatter)('5MIN');
|
|
41
|
+
const algo = header.algo || (algo_config_1.DEFAULT_ALGORITHM[this.runtime][0].name);
|
|
42
|
+
return await this.crypto.createToken(this.runtime, algo, key, payload, exp);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
(0, functions_lib_1.print)({ dev: this.dev, color: 'red' }, error);
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async verify(token, key) {
|
|
50
|
+
try {
|
|
51
|
+
if (!token) {
|
|
52
|
+
throw new Error('Token is required to verify token');
|
|
53
|
+
}
|
|
54
|
+
if (!key) {
|
|
55
|
+
throw new Error('key is required to verify token');
|
|
56
|
+
}
|
|
57
|
+
const unfilterPayload = await this.crypto.verifyToken(this.runtime, token, key);
|
|
58
|
+
if ((0, functions_lib_1.isExpired)(unfilterPayload.exp)) {
|
|
59
|
+
throw new Error('Token expired');
|
|
60
|
+
}
|
|
61
|
+
return unfilterPayload.payload;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
(0, functions_lib_1.print)({ dev: this.dev, color: 'red' }, error);
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
class PrivatePublicKeyGeneration {
|
|
70
|
+
crypto = new crypto_1.Crypto();
|
|
71
|
+
async generateKeyPair(runtime, dev) {
|
|
72
|
+
let finalRuntime = (0, runtime_config_1.detectRuntime)();
|
|
73
|
+
const development = dev === true ? true : false;
|
|
74
|
+
try {
|
|
75
|
+
if (runtime) {
|
|
76
|
+
if (!name_config_1.RUNTIME.includes(runtime)) {
|
|
77
|
+
throw new Error("Unsupported runtime");
|
|
78
|
+
}
|
|
79
|
+
finalRuntime = runtime;
|
|
80
|
+
}
|
|
81
|
+
const { privateKey, publicKey } = await this.crypto.rsaKeyDrivation(finalRuntime, 'keyPair');
|
|
82
|
+
(0, functions_lib_1.print)({ dev: development, color: 'green' }, 'Current Runtime: ', finalRuntime);
|
|
83
|
+
(0, functions_lib_1.print)({ dev: development, color: 'green' }, { privateKey, publicKey });
|
|
84
|
+
return { privateKey, publicKey };
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
(0, functions_lib_1.print)({ dev: development, color: 'red' }, error);
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async generatePublicKey(privateKeyPem, runtime, dev) {
|
|
92
|
+
let finalRuntime = (0, runtime_config_1.detectRuntime)();
|
|
93
|
+
const development = dev === true ? true : false;
|
|
94
|
+
try {
|
|
95
|
+
if (runtime) {
|
|
96
|
+
if (!name_config_1.RUNTIME.includes(runtime)) {
|
|
97
|
+
throw new Error("Unsupported runtime");
|
|
98
|
+
}
|
|
99
|
+
finalRuntime = runtime;
|
|
100
|
+
}
|
|
101
|
+
const publicKey = await this.crypto.rsaKeyDrivation(finalRuntime, 'publickey', privateKeyPem);
|
|
102
|
+
(0, functions_lib_1.print)({ dev: development, color: 'green' }, 'Current Runtime: ', finalRuntime);
|
|
103
|
+
(0, functions_lib_1.print)({ dev: development, color: 'green' }, publicKey);
|
|
104
|
+
return publicKey;
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
(0, functions_lib_1.print)({ dev: development, color: 'red' }, error);
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const p2kgObject = new PrivatePublicKeyGeneration();
|
|
113
|
+
const generateKeyPair = (options) => {
|
|
114
|
+
const { runtime, dev } = options || {};
|
|
115
|
+
return p2kgObject.generateKeyPair(runtime, dev);
|
|
116
|
+
};
|
|
117
|
+
const generatePublicKey = (privateKeyPem, options) => {
|
|
118
|
+
const { runtime, dev } = options || {};
|
|
119
|
+
return p2kgObject.generatePublicKey(privateKeyPem, runtime, dev);
|
|
120
|
+
};
|
|
121
|
+
const JAT = (config) => new JATClass(config);
|
|
122
|
+
exports.JAT = JAT;
|
|
123
|
+
const getSupportedAlgorithm = () => algo_config_1.SUPPORTED_ALGORITHM;
|
|
124
|
+
exports.getSupportedAlgorithm = getSupportedAlgorithm;
|
|
125
|
+
exports.P2KG = {
|
|
126
|
+
generateKeyPair: generateKeyPair,
|
|
127
|
+
generatePublicKey: generatePublicKey
|
|
128
|
+
};
|
|
129
|
+
const jsonauthtoken = {
|
|
130
|
+
JAT: exports.JAT,
|
|
131
|
+
P2KG: exports.P2KG
|
|
132
|
+
};
|
|
133
|
+
exports.default = jsonauthtoken;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const decoading = (str) => {
|
|
4
|
+
const base64 = str.replace(/-/g, '+').replace(/_/g, '/');
|
|
5
|
+
const padding = '='.repeat((4 - base64.length % 4) % 4);
|
|
6
|
+
const decoded = Buffer.from(base64 + padding, 'base64').toString('utf8');
|
|
7
|
+
return JSON.parse(decoded);
|
|
8
|
+
};
|
|
9
|
+
exports.default = decoading;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
function encoading(data) {
|
|
4
|
+
const json = JSON.stringify(data);
|
|
5
|
+
const base64 = Buffer.from(json).toString('base64');
|
|
6
|
+
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
7
|
+
}
|
|
8
|
+
exports.default = encoading;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare function tokenFormatCreate<R extends Runtime = Runtime>(meta: TokenMetaData<R>, encrypted: string): string;
|
|
2
|
+
declare function tokenFormatVerify<R extends Runtime = Runtime>(token: string): {
|
|
3
|
+
meta: TokenMetaData<R>;
|
|
4
|
+
encrypted: string;
|
|
5
|
+
};
|
|
6
|
+
declare function isExpired(timeStamp: number): boolean;
|
|
7
|
+
type Color = 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white';
|
|
8
|
+
declare function print({ dev, color }: {
|
|
9
|
+
dev?: boolean;
|
|
10
|
+
color?: Color;
|
|
11
|
+
}, ...args: unknown[]): void;
|
|
12
|
+
export { isExpired, tokenFormatCreate, tokenFormatVerify, print };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isExpired = isExpired;
|
|
7
|
+
exports.tokenFormatCreate = tokenFormatCreate;
|
|
8
|
+
exports.tokenFormatVerify = tokenFormatVerify;
|
|
9
|
+
exports.print = print;
|
|
10
|
+
const algo_config_1 = require("../config/algo.config");
|
|
11
|
+
const encoading_lib_1 = __importDefault(require("./encoading.lib"));
|
|
12
|
+
const decoading_lib_1 = __importDefault(require("./decoading.lib"));
|
|
13
|
+
const name_config_1 = require("../config/name.config");
|
|
14
|
+
function tokenFormatCreate(meta, encrypted) {
|
|
15
|
+
return `${(0, encoading_lib_1.default)(meta)}:${encrypted}`;
|
|
16
|
+
}
|
|
17
|
+
function tokenFormatVerify(token) {
|
|
18
|
+
const index = token.indexOf(":");
|
|
19
|
+
if (index === -1) {
|
|
20
|
+
throw new Error("Invalid token format");
|
|
21
|
+
}
|
|
22
|
+
const metaPart = token.substring(0, index);
|
|
23
|
+
const encryptedPart = token.substring(index + 1);
|
|
24
|
+
const meta = (0, decoading_lib_1.default)(metaPart);
|
|
25
|
+
if (!meta) {
|
|
26
|
+
throw new Error("Invalid token format");
|
|
27
|
+
}
|
|
28
|
+
const algorithm = algo_config_1.SUPPORTED_ALGORITHM[meta.runtime]?.find(e => e.name === meta.algo);
|
|
29
|
+
if (!algorithm) {
|
|
30
|
+
throw new Error("Invalid token format");
|
|
31
|
+
}
|
|
32
|
+
if (algorithm.type !== meta.type) {
|
|
33
|
+
throw new Error("Invalid token format");
|
|
34
|
+
}
|
|
35
|
+
if (meta.type === 'asymmetric') {
|
|
36
|
+
if (!meta.encryptedKey) {
|
|
37
|
+
throw new Error("Invalid token format");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (!meta.iv) {
|
|
41
|
+
throw new Error("Invalid token format");
|
|
42
|
+
}
|
|
43
|
+
if (!name_config_1.RUNTIME.includes(meta.runtime)) {
|
|
44
|
+
throw new Error("Invalid token format");
|
|
45
|
+
}
|
|
46
|
+
if (meta.runtime === 'node') {
|
|
47
|
+
if (!meta.tag) {
|
|
48
|
+
throw new Error("Invalid token format");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!meta.v) {
|
|
52
|
+
throw new Error("Invalid token format");
|
|
53
|
+
}
|
|
54
|
+
return { meta, encrypted: encryptedPart };
|
|
55
|
+
}
|
|
56
|
+
function isExpired(timeStamp) {
|
|
57
|
+
let currentTime = Math.floor(Date.now() / 1000);
|
|
58
|
+
if (timeStamp < currentTime) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function print({ dev = false, color = 'green' }, ...args) {
|
|
66
|
+
if (!dev)
|
|
67
|
+
return;
|
|
68
|
+
const colors = {
|
|
69
|
+
red: '\x1b[31m',
|
|
70
|
+
green: '\x1b[32m',
|
|
71
|
+
yellow: '\x1b[33m',
|
|
72
|
+
blue: '\x1b[34m',
|
|
73
|
+
magenta: '\x1b[35m',
|
|
74
|
+
cyan: '\x1b[36m',
|
|
75
|
+
white: '\x1b[37m',
|
|
76
|
+
reset: '\x1b[0m',
|
|
77
|
+
};
|
|
78
|
+
if (typeof window !== 'undefined') {
|
|
79
|
+
console.log(`%c[jsonauthtoken]`, `color:${color}`, ...args);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
const colorCode = colors[color] ?? colors.green;
|
|
83
|
+
console.log(`${colorCode}[jsonauthtoken]`, ...args, '\x1b[0m');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function jatTimeFormatter(input: JATTime): number;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.jatTimeFormatter = jatTimeFormatter;
|
|
4
|
+
function jatTimeFormatter(input) {
|
|
5
|
+
if (typeof input === 'number') {
|
|
6
|
+
if (input <= 0) {
|
|
7
|
+
throw new Error('Expiration time must be greater than zero.');
|
|
8
|
+
}
|
|
9
|
+
return Math.floor(Date.now() / 1000) + input;
|
|
10
|
+
}
|
|
11
|
+
const regex = /^(\d+)(S|MIN|H|D|M|Y)$/i;
|
|
12
|
+
const match = input.match(regex);
|
|
13
|
+
if (!match) {
|
|
14
|
+
throw new Error('Invalid format. Use number or formats like 1S, 1MIN, 1H, 1D, 1M, or 1Y.');
|
|
15
|
+
}
|
|
16
|
+
const amount = parseInt(match[1], 10);
|
|
17
|
+
const unit = match[2].toUpperCase();
|
|
18
|
+
let seconds;
|
|
19
|
+
switch (unit) {
|
|
20
|
+
case 'S':
|
|
21
|
+
seconds = amount;
|
|
22
|
+
break;
|
|
23
|
+
case 'MIN':
|
|
24
|
+
seconds = amount * 60;
|
|
25
|
+
break;
|
|
26
|
+
case 'H':
|
|
27
|
+
seconds = amount * 60 * 60;
|
|
28
|
+
break;
|
|
29
|
+
case 'D':
|
|
30
|
+
seconds = amount * 24 * 60 * 60;
|
|
31
|
+
break;
|
|
32
|
+
case 'M':
|
|
33
|
+
seconds = amount * 30 * 24 * 60 * 60;
|
|
34
|
+
break;
|
|
35
|
+
case 'Y':
|
|
36
|
+
seconds = amount * 365 * 24 * 60 * 60;
|
|
37
|
+
break;
|
|
38
|
+
default:
|
|
39
|
+
throw new Error(`Unsupported time unit: ${unit}`);
|
|
40
|
+
}
|
|
41
|
+
return Math.floor(Date.now() / 1000) + seconds;
|
|
42
|
+
}
|
package/package.json
CHANGED
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jsonauthtoken",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "jsonauthtoken is a JavaScript library to secure authentication.",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"type": "module",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "jsonauthtoken is a JavaScript/TypeScript library to secure authentication.",
|
|
5
|
+
"main": "dist/index.js",
|
|
7
6
|
"repository": {
|
|
8
7
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/iamAyanBiswas/jsonauthtoken"
|
|
8
|
+
"url": "git+https://github.com/iamAyanBiswas/jsonauthtoken.git"
|
|
10
9
|
},
|
|
11
10
|
"scripts": {
|
|
12
|
-
"
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "nodemon --watch src --ext ts --exec \"npm run build && node dist/test.js\""
|
|
13
13
|
},
|
|
14
14
|
"author": "Ayan Biswas",
|
|
15
15
|
"license": "ISC",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/iamAyanBiswas/jsonauthtoken/issues"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/iamAyanBiswas/jsonauthtoken#readme",
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "^22.9.0",
|
|
22
|
+
"typescript": "^5.6.3"
|
|
23
|
+
},
|
|
16
24
|
"keywords": [
|
|
17
25
|
"jat",
|
|
18
26
|
"jwt",
|
|
19
27
|
"jsonauthtoken",
|
|
20
28
|
"jsonwebtoken",
|
|
21
29
|
"auth",
|
|
22
|
-
"authentication"
|
|
23
|
-
"sha256",
|
|
24
|
-
"sha384",
|
|
25
|
-
"sha512"
|
|
30
|
+
"authentication"
|
|
26
31
|
]
|
|
27
32
|
}
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { RUNTIME } from "./src/config/name.config";
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
|
|
5
|
+
type TimeUnit = 'S' | 'MIN' | 'H' | 'D' | 'M' | 'Y';
|
|
6
|
+
type ExpirationString = `${number}${TimeUnit}` | `${number}${Lowercase<TimeUnit>}`;
|
|
7
|
+
type JATTime = number | ExpirationString;
|
|
8
|
+
|
|
9
|
+
interface GenerateKeyPair {
|
|
10
|
+
privateKey: string
|
|
11
|
+
publicKey: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type Runtime = 'node' | 'web' | 'edge';
|
|
15
|
+
type EncryptionAlgorithmType = 'symmetric' | 'asymmetric';
|
|
16
|
+
|
|
17
|
+
interface AlgorithmDetails {
|
|
18
|
+
name: string;
|
|
19
|
+
value: string
|
|
20
|
+
type: EncryptionAlgorithmType;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface RuntimeWiseAlgorithmMap {
|
|
24
|
+
node: 'AES-256-GCM' | 'RSA+A256GCM'
|
|
25
|
+
edge: 'AES-GCM' | 'RSA+AES-GCM'
|
|
26
|
+
web: 'AES-GCM' | 'RSA+AES-GCM'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type RuntimeWiseAlgorithm<R extends Runtime> = RuntimeWiseAlgorithmMap[R];
|
|
30
|
+
|
|
31
|
+
interface JATConfig<R extends Runtime = Runtime> {
|
|
32
|
+
runtime?: R
|
|
33
|
+
dev?: boolean
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface CreateTokenConfig<R extends Runtime> {
|
|
37
|
+
key: string
|
|
38
|
+
exp?: JATTime
|
|
39
|
+
algo?: RuntimeWiseAlgorithm<R>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface BaseTokenMetaData<R extends Runtime> {
|
|
43
|
+
runtime: Runtime;
|
|
44
|
+
algo: RuntimeWiseAlgorithm<R>;
|
|
45
|
+
v: string;
|
|
46
|
+
iv: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type TokenMetaData<R extends Runtime> =
|
|
50
|
+
| (BaseTokenMetaData<R> & {
|
|
51
|
+
runtime: 'node';
|
|
52
|
+
tag: string;
|
|
53
|
+
} & (
|
|
54
|
+
| { type: 'symmetric'; encryptedKey?: never }
|
|
55
|
+
| { type: 'asymmetric'; encryptedKey: string }
|
|
56
|
+
))
|
|
57
|
+
| (BaseTokenMetaData<R> & {
|
|
58
|
+
runtime: 'web' | 'edge';
|
|
59
|
+
tag?: never;
|
|
60
|
+
} & (
|
|
61
|
+
| { type: 'symmetric'; encryptedKey?: never }
|
|
62
|
+
| { type: 'asymmetric'; encryptedKey: string }
|
|
63
|
+
));
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export { };
|
package/index.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import encoading from './lib/encoading.lib.js'
|
|
2
|
-
import decoading from './lib/decoading.lib.js'
|
|
3
|
-
import signature from './lib/signature.lib.js'
|
|
4
|
-
import encryption from './lib/encryption.lib.js'
|
|
5
|
-
import decryption from './lib/decryption.lib.js'
|
|
6
|
-
import { algoMatching, parseExpiration, isExpired } from './lib/functions.lib.js'
|
|
7
|
-
|
|
8
|
-
function jat() {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const algorithms = ['sha256', 'sha384', 'sha512']
|
|
12
|
-
|
|
13
|
-
/////////////////////--------------- create token ---------------------/////////////////////////
|
|
14
|
-
const create = (keys, headers = {}, payloads = {}) => {
|
|
15
|
-
|
|
16
|
-
let {signKey, encKey} = keys
|
|
17
|
-
if(!signKey) throw new Error("please provide signkey");
|
|
18
|
-
if(!encKey) throw new Error("please provide encKey");
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
let exp = ''
|
|
22
|
-
if (headers.expiresAt) exp = parseExpiration(headers.expiresAt)
|
|
23
|
-
else throw new Error("please provide token expire")
|
|
24
|
-
|
|
25
|
-
let algo = algoMatching(algorithms, 'sha512', headers.algo)
|
|
26
|
-
|
|
27
|
-
let header = encoading({
|
|
28
|
-
token: 'JAT',
|
|
29
|
-
algorithm: algo,
|
|
30
|
-
createAt: Math.floor(Date.now() / 1000),
|
|
31
|
-
expiresAt: exp,
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
if (typeof (payloads) != 'object') throw new Error("payload should be Object");
|
|
35
|
-
let payload = encoading(payloads)
|
|
36
|
-
|
|
37
|
-
let sign = signature().createSign(algo, signKey, header, payload)
|
|
38
|
-
|
|
39
|
-
let token = header + '.' + payload + '.' + sign
|
|
40
|
-
let encryptedToken = encryption(encKey, token)
|
|
41
|
-
return encryptedToken
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
/////////////////////--------------- verify token ---------------------/////////////////////////
|
|
46
|
-
const verify = (encryptedToken, keys) => {
|
|
47
|
-
let token = ''
|
|
48
|
-
let header = ''
|
|
49
|
-
let payload = ''
|
|
50
|
-
|
|
51
|
-
let {signKey, encKey} = keys
|
|
52
|
-
if(!signKey) throw new Error("please provide signkey");
|
|
53
|
-
if(!encKey) throw new Error("please provide encKey");
|
|
54
|
-
|
|
55
|
-
//decrypt token
|
|
56
|
-
try {
|
|
57
|
-
token = decryption(encryptedToken, encKey)
|
|
58
|
-
} catch (error) {
|
|
59
|
-
throw new Error('unable to decrypt token')
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
//verify token signature
|
|
63
|
-
let isSignVerified = signature().verifySign(token, signKey)
|
|
64
|
-
if (isSignVerified === false) {
|
|
65
|
-
throw new Error('Invalid signature')
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
//
|
|
69
|
-
const [encodedHeader, encodedPayload, sign] = token.split('.');
|
|
70
|
-
|
|
71
|
-
header = decoading(encodedHeader)
|
|
72
|
-
if(isExpired(header.expiresAt)) throw new Error('token is expired')
|
|
73
|
-
|
|
74
|
-
payload = decoading(encodedPayload)
|
|
75
|
-
|
|
76
|
-
return {header,payload}
|
|
77
|
-
}
|
|
78
|
-
return { create, verify }
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
export default jat
|
package/lib/decoading.lib.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
const decoading = (str) => {
|
|
2
|
-
// Replace URL-safe characters with standard Base64 characters
|
|
3
|
-
const base64 = str.replace(/-/g, '+').replace(/_/g, '/');
|
|
4
|
-
|
|
5
|
-
// Add padding if necessary
|
|
6
|
-
const padding = '='.repeat((4 - base64.length % 4) % 4);
|
|
7
|
-
|
|
8
|
-
// Decode the Base64 string
|
|
9
|
-
const decoded = Buffer.from(base64 + padding, 'base64').toString('utf8');
|
|
10
|
-
|
|
11
|
-
return JSON.parse(decoded);
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export default decoading
|
package/lib/decryption.lib.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import exp from 'constants';
|
|
2
|
-
import crypto from 'crypto'
|
|
3
|
-
|
|
4
|
-
function decryption(encryptedToken, password) {
|
|
5
|
-
const parts = encryptedToken.split(':');
|
|
6
|
-
const iv = Buffer.from(parts.shift(), 'hex'); // Get the IV
|
|
7
|
-
const encryptedTokenBuffer = Buffer.from(parts.join(':'), 'hex');
|
|
8
|
-
const key = crypto.scryptSync(password, 'salt', 32);
|
|
9
|
-
|
|
10
|
-
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
|
|
11
|
-
|
|
12
|
-
let decrypted = decipher.update(encryptedTokenBuffer, 'binary', 'utf8');
|
|
13
|
-
decrypted += decipher.final('utf8');
|
|
14
|
-
|
|
15
|
-
return decrypted;
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
export default decryption
|
package/lib/encryption.lib.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import crypto from 'crypto'
|
|
2
|
-
|
|
3
|
-
function encryption(password,token){
|
|
4
|
-
const iv = crypto.randomBytes(16); // Initialization vector
|
|
5
|
-
const key = crypto.scryptSync(password, 'salt', 32); // Key derivation
|
|
6
|
-
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
|
|
7
|
-
|
|
8
|
-
let encrypted = cipher.update(token, 'utf8', 'hex');
|
|
9
|
-
encrypted += cipher.final('hex');
|
|
10
|
-
|
|
11
|
-
// Return the IV and encrypted text
|
|
12
|
-
return iv.toString('hex') + ':' + encrypted;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export default encryption
|
package/lib/functions.lib.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
function algoMatching(algorithms, defaultOutput, input) {
|
|
2
|
-
|
|
3
|
-
//check defaultOutput parameter
|
|
4
|
-
if (!defaultOutput) throw new Error('defaultOutput parameter can not be empty')
|
|
5
|
-
|
|
6
|
-
//find the correct algorithm name is given as 'input' or not , if is't return defaultOutput
|
|
7
|
-
for (let i in algorithms) {
|
|
8
|
-
if (String(algorithms[i]) === String(input)) defaultOutput = algorithms[i]
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return defaultOutput
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
function parseExpiration(input) {
|
|
16
|
-
const regex = /^(\d+)([mhdMHDyY]|MIN)$/; // Regex to match number + unit
|
|
17
|
-
const match = input.match(regex);
|
|
18
|
-
|
|
19
|
-
if (!match) {
|
|
20
|
-
throw new Error('Invalid format. Use formats like 1M, 1Y, 1D, 1MIN.');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const amount = parseInt(match[1], 10);
|
|
24
|
-
const unit = match[2].toLowerCase(); // Normalize to lowercase
|
|
25
|
-
|
|
26
|
-
let seconds;
|
|
27
|
-
|
|
28
|
-
switch (unit) {
|
|
29
|
-
case 'y':
|
|
30
|
-
seconds = amount * 365 * 24 * 60 * 60; // Years to seconds
|
|
31
|
-
break;
|
|
32
|
-
case 'm':
|
|
33
|
-
seconds = amount * 30 * 24 * 60 * 60; // Months to seconds (approximation)
|
|
34
|
-
break;
|
|
35
|
-
case 'd':
|
|
36
|
-
seconds = amount * 24 * 60 * 60; // Days to seconds
|
|
37
|
-
break;
|
|
38
|
-
case 'h':
|
|
39
|
-
seconds = amount * 60 * 60; // Hours to seconds
|
|
40
|
-
break;
|
|
41
|
-
case 'min':
|
|
42
|
-
seconds = amount * 60; // Minutes to seconds
|
|
43
|
-
break;
|
|
44
|
-
default:
|
|
45
|
-
throw new Error('Unsupported time unit. Use M, Y, D, H, or MIN.');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return Math.floor(Date.now() / 1000) + seconds; // Current time + expiration time
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
function isExpired(timeStamp) {
|
|
54
|
-
let currentTime = Math.floor(Date.now() / 1000)
|
|
55
|
-
if (timeStamp < currentTime) {
|
|
56
|
-
return true
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
return false
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
export { algoMatching, parseExpiration, isExpired }
|