jsonauthtoken 2.0.0 → 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 +33 -4
- package/dist/index.js +124 -59
- package/dist/lib/functions.lib.d.ts +11 -3
- package/dist/lib/functions.lib.js +71 -40
- package/dist/lib/timeformat.d.ts +1 -0
- package/dist/lib/timeformat.js +42 -0
- package/package.json +6 -9
- package/types.d.ts +51 -27
- package/dist/lib/decryption.lib.d.ts +0 -2
- package/dist/lib/decryption.lib.js +0 -17
- package/dist/lib/encryption.lib.d.ts +0 -2
- package/dist/lib/encryption.lib.js +0 -15
- package/dist/lib/signature.lib.d.ts +0 -5
- package/dist/lib/signature.lib.js +0 -26
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ jsonauthtoken is a JavaScript library to secure authentication.
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
This project demonstrates the usage of the `jsonauthtoken` package to create and verify secure encrypted authentication tokens and store sensitive datas. Tokens are used to
|
|
7
|
+
This project demonstrates the usage of the `jsonauthtoken` package to create and verify secure encrypted authentication tokens and store sensitive datas. Tokens are used to encrypt data for secure communication. The `jsonauthtoken` library provides methods to generate and verify tokens with configurable expiration times, encryption algorithms, payload data and also offer key generation.
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
## Node.js (Install)
|
|
@@ -20,47 +20,26 @@ npm install jsonauthtoken
|
|
|
20
20
|
|
|
21
21
|
### Usage
|
|
22
22
|
|
|
23
|
-
To create jsonauthtoken:
|
|
24
23
|
|
|
25
24
|
```javascript
|
|
26
|
-
import
|
|
27
|
-
|
|
28
|
-
// Create a token
|
|
29
|
-
let encToken = jat().create(
|
|
30
|
-
{
|
|
31
|
-
signKey: process.env.SIGN_KEY, // Signature key
|
|
32
|
-
encKey: process.env.ENC_KEY // Encryption key
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
expiresAt: '4MIN', // Token expiration time
|
|
36
|
-
algorithm: 'sha256' // Optional: Hash algorithms list ['sha256', 'sha384', 'sha512']
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
data: { // Data payload
|
|
40
|
-
status: true,
|
|
41
|
-
name:'Arpan Biswas',
|
|
42
|
-
dob: '15.11.2008'
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
console.log("encToken: ", encToken);
|
|
25
|
+
import { JAT } from "jsonauthtoken";
|
|
48
26
|
|
|
49
|
-
|
|
27
|
+
(async () => {
|
|
28
|
+
|
|
29
|
+
const jat = JAT()
|
|
50
30
|
|
|
51
|
-
|
|
31
|
+
const payload = {
|
|
32
|
+
name: 'jsonauthtoken'
|
|
33
|
+
} as const
|
|
52
34
|
|
|
53
|
-
|
|
54
|
-
|
|
35
|
+
//to create token
|
|
36
|
+
const token = await jat.create({ key: process.env.KEY }, payload)
|
|
55
37
|
|
|
56
|
-
//
|
|
38
|
+
//to verify token
|
|
39
|
+
const verify =await jat.verify<typeof payload>(token, process.env.KEY)
|
|
57
40
|
|
|
58
|
-
|
|
59
|
-
let datas = jat().verify(token, {
|
|
60
|
-
signKey: process.env.SIGN_KEY, // Signature key
|
|
61
|
-
encKey: process.env.ENC_KEY // Encryption key
|
|
62
|
-
});
|
|
41
|
+
console.log(verify)
|
|
63
42
|
|
|
64
|
-
|
|
43
|
+
})()
|
|
65
44
|
|
|
66
45
|
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_ALGORITHM = exports.SUPPORTED_ALGORITHM = void 0;
|
|
4
|
+
exports.SUPPORTED_ALGORITHM = {
|
|
5
|
+
node: [
|
|
6
|
+
{ name: 'AES-256-GCM', value: 'aes-256-gcm', type: 'symmetric' },
|
|
7
|
+
{ name: 'RSA+A256GCM', value: 'rsa+a256gcm', type: 'asymmetric' },
|
|
8
|
+
],
|
|
9
|
+
web: [
|
|
10
|
+
{ name: 'AES-GCM', value: 'AES-GCM', type: 'symmetric' },
|
|
11
|
+
{ name: 'RSA+AES-GCM', value: 'RSA+AES-GCM', type: 'asymmetric' }
|
|
12
|
+
],
|
|
13
|
+
edge: [
|
|
14
|
+
{ name: 'AES-GCM', value: 'AES-GCM', type: 'symmetric' },
|
|
15
|
+
{ name: 'RSA+AES-GCM', value: 'RSA+AES-GCM', type: 'asymmetric' }
|
|
16
|
+
]
|
|
17
|
+
};
|
|
18
|
+
exports.DEFAULT_ALGORITHM = {
|
|
19
|
+
node: [
|
|
20
|
+
{ name: 'AES-256-GCM', value: 'aes-256-gcm', type: 'symmetric' },
|
|
21
|
+
],
|
|
22
|
+
web: [
|
|
23
|
+
{ name: 'AES-GCM', value: 'AES-GCM', type: 'symmetric' },
|
|
24
|
+
],
|
|
25
|
+
edge: [
|
|
26
|
+
{ name: 'AES-GCM', value: 'AES-GCM', type: 'symmetric' },
|
|
27
|
+
]
|
|
28
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const RUNTIME: Runtime[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function detectRuntime(): Runtime;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectRuntime = detectRuntime;
|
|
4
|
+
function detectRuntime() {
|
|
5
|
+
if (typeof process !== 'undefined' && process.versions?.node) {
|
|
6
|
+
return 'node';
|
|
7
|
+
}
|
|
8
|
+
if (typeof window !== 'undefined' && window.crypto?.subtle) {
|
|
9
|
+
return 'web';
|
|
10
|
+
}
|
|
11
|
+
if (typeof globalThis !== 'undefined' && globalThis.crypto?.subtle) {
|
|
12
|
+
return 'edge';
|
|
13
|
+
}
|
|
14
|
+
return 'node';
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class Crypto {
|
|
2
|
+
private node;
|
|
3
|
+
private web;
|
|
4
|
+
private getModule;
|
|
5
|
+
createToken(runtime: Runtime, algo: string, key: string, payload: any, exp: number): Promise<string>;
|
|
6
|
+
verifyToken<T>(currentRuntime: Runtime, token: string, key: string): Promise<{
|
|
7
|
+
payload: T;
|
|
8
|
+
exp: number;
|
|
9
|
+
}>;
|
|
10
|
+
rsaKeyDrivation(runtime: Runtime, type: 'keyPair'): Promise<GenerateKeyPair>;
|
|
11
|
+
rsaKeyDrivation(runtime: Runtime, type: 'publickey', privateKeyPem: string): Promise<string>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.Crypto = void 0;
|
|
37
|
+
const algo_config_1 = require("../config/algo.config");
|
|
38
|
+
const functions_lib_1 = require("../lib/functions.lib");
|
|
39
|
+
class Crypto {
|
|
40
|
+
node;
|
|
41
|
+
web;
|
|
42
|
+
async getModule(runtime) {
|
|
43
|
+
if (runtime === 'node' && this.node === undefined) {
|
|
44
|
+
const { NodeCrypto } = await Promise.resolve().then(() => __importStar(require('./node.crypto')));
|
|
45
|
+
this.node = new NodeCrypto();
|
|
46
|
+
}
|
|
47
|
+
else if (runtime === 'web' && this.web === undefined) {
|
|
48
|
+
const { WebCrypto } = await Promise.resolve().then(() => __importStar(require('./web.crypto')));
|
|
49
|
+
this.web = new WebCrypto();
|
|
50
|
+
}
|
|
51
|
+
else if (runtime === 'edge' && this.web === undefined) {
|
|
52
|
+
const { WebCrypto } = await Promise.resolve().then(() => __importStar(require('./web.crypto')));
|
|
53
|
+
this.web = new WebCrypto();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async createToken(runtime, algo, key, payload, exp) {
|
|
57
|
+
const algorithms = algo_config_1.SUPPORTED_ALGORITHM[runtime];
|
|
58
|
+
const algoData = algorithms.find(({ name }) => { return name == algo; });
|
|
59
|
+
if (!algoData) {
|
|
60
|
+
throw new Error(`Algorithm ${algo} is not supported for ${runtime}`);
|
|
61
|
+
}
|
|
62
|
+
await this.getModule(runtime);
|
|
63
|
+
if (runtime === 'node') {
|
|
64
|
+
if (algoData.type === 'asymmetric') {
|
|
65
|
+
if (algoData.value !== 'ras+a256gcm') {
|
|
66
|
+
throw new Error(`Algorithm ${algoData.name} is not supported for asymmetric encryption`);
|
|
67
|
+
}
|
|
68
|
+
return this.node.encryptRSA(payload, key, exp);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
if (algoData.value !== 'aes-256-gcm') {
|
|
72
|
+
throw new Error(`Algorithm ${algoData.name} is not supported for symmetric encryption`);
|
|
73
|
+
}
|
|
74
|
+
return this.node.encrypt(algoData.value, key, payload, exp);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
if (algoData.type === 'asymmetric') {
|
|
79
|
+
if (algoData.value !== 'RSA+AES-GCM') {
|
|
80
|
+
throw new Error(`Algorithm ${algoData.name} is not supported for asymmetric encryption`);
|
|
81
|
+
}
|
|
82
|
+
return await this.web.encryptRSA(payload, key, exp);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
if (algoData.value !== 'AES-GCM') {
|
|
86
|
+
throw new Error(`Algorithm ${algoData.name} is not supported for symmetric encryption`);
|
|
87
|
+
}
|
|
88
|
+
return await this.web.encrypt(algoData.value, key, payload, exp);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async verifyToken(currentRuntime, token, key) {
|
|
93
|
+
const { meta, encrypted } = (0, functions_lib_1.tokenFormatVerify)(token);
|
|
94
|
+
const { runtime, algo, type, v, iv, tag, encryptedKey } = meta;
|
|
95
|
+
if (currentRuntime !== runtime) {
|
|
96
|
+
throw new Error('Runtime not matching');
|
|
97
|
+
}
|
|
98
|
+
await this.getModule(runtime);
|
|
99
|
+
if (runtime === 'node') {
|
|
100
|
+
if (type === 'asymmetric') {
|
|
101
|
+
if (algo !== 'RSA+A256GCM') {
|
|
102
|
+
throw new Error(`Algorithm ${algo} is not supported for asymmetric encryption`);
|
|
103
|
+
}
|
|
104
|
+
return this.node.decryptRSA(key, encryptedKey, { iv, encrypted, tag });
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
if (algo !== 'AES-256-GCM') {
|
|
108
|
+
throw new Error(`Algorithm ${algo} is not supported for symmetric encryption`);
|
|
109
|
+
}
|
|
110
|
+
return this.node.decrypt("aes-256-gcm", key, { iv, encrypted, tag });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
if (type === 'asymmetric') {
|
|
115
|
+
if (algo !== 'RSA+AES-GCM') {
|
|
116
|
+
throw new Error(`Algorithm ${algo} is not supported for asymmetric encryption`);
|
|
117
|
+
}
|
|
118
|
+
return await this.web.decryptRSA(key, encryptedKey, { iv, encrypted });
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
if (algo !== 'AES-GCM') {
|
|
122
|
+
throw new Error(`Algorithm ${algo} is not supported for symmetric encryption`);
|
|
123
|
+
}
|
|
124
|
+
return await this.web.decrypt('AES-GCM', key, { iv, encrypted });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async rsaKeyDrivation(runtime, type, privateKeyPem) {
|
|
129
|
+
await this.getModule(runtime);
|
|
130
|
+
if (runtime === 'node') {
|
|
131
|
+
if (type === 'keyPair') {
|
|
132
|
+
return this.node.rsaPrivatePublicKeyGeneration();
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
if (!privateKeyPem)
|
|
136
|
+
throw new Error('privateKeyPem is required');
|
|
137
|
+
return this.node.rsaPublicKeyGeneration(privateKeyPem);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
if (type === 'keyPair') {
|
|
142
|
+
return await this.web.rsaPrivatePublicKeyGeneration();
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
if (!privateKeyPem)
|
|
146
|
+
throw new Error('privateKeyPem is required');
|
|
147
|
+
return await this.web.rsaPublicKeyGeneration(privateKeyPem);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
exports.Crypto = Crypto;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare class NodeCrypto {
|
|
2
|
+
private _encrypt;
|
|
3
|
+
private _decrypt;
|
|
4
|
+
private _rsaPublicKeyGeneration;
|
|
5
|
+
private _rsaPrivatePublicKeyGeneration;
|
|
6
|
+
encrypt(algo: 'aes-256-gcm', key: string, payload: any, exp: number): string;
|
|
7
|
+
decrypt<T>(algo: 'aes-256-gcm', key: string, encryptedData: {
|
|
8
|
+
iv: string;
|
|
9
|
+
encrypted: string;
|
|
10
|
+
tag: string;
|
|
11
|
+
}): {
|
|
12
|
+
payload: T;
|
|
13
|
+
exp: number;
|
|
14
|
+
};
|
|
15
|
+
encryptRSA(payload: any, publicKey: string, exp: number): string;
|
|
16
|
+
decryptRSA<T>(privateKey: string, encryptedKey: string, encryptedData: {
|
|
17
|
+
iv: string;
|
|
18
|
+
encrypted: string;
|
|
19
|
+
tag: string;
|
|
20
|
+
}): {
|
|
21
|
+
payload: T;
|
|
22
|
+
exp: number;
|
|
23
|
+
};
|
|
24
|
+
rsaPrivatePublicKeyGeneration(): {
|
|
25
|
+
privateKey: string;
|
|
26
|
+
publicKey: string;
|
|
27
|
+
};
|
|
28
|
+
rsaPublicKeyGeneration(privateKeyPem: string): string | Buffer<ArrayBufferLike>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
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.NodeCrypto = void 0;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
const functions_lib_1 = require("../lib/functions.lib");
|
|
9
|
+
class NodeCrypto {
|
|
10
|
+
_encrypt(algorithm, key, payload) {
|
|
11
|
+
const iv = crypto_1.default.randomBytes(12);
|
|
12
|
+
const cipher = crypto_1.default.createCipheriv(algorithm, key, iv);
|
|
13
|
+
const data = JSON.stringify(payload);
|
|
14
|
+
let encrypted = cipher.update(data, 'utf8', 'base64');
|
|
15
|
+
encrypted += cipher.final('base64');
|
|
16
|
+
const tag = cipher.getAuthTag().toString('base64');
|
|
17
|
+
return {
|
|
18
|
+
iv: iv.toString('base64'),
|
|
19
|
+
encrypted,
|
|
20
|
+
tag
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
_decrypt(algorithm, key, encryptedData) {
|
|
24
|
+
const { iv, encrypted, tag } = encryptedData;
|
|
25
|
+
const decipher = crypto_1.default.createDecipheriv(algorithm, key, Buffer.from(iv, 'base64'));
|
|
26
|
+
decipher.setAuthTag(Buffer.from(tag, 'base64'));
|
|
27
|
+
let decrypted = decipher.update(encrypted, 'base64', 'utf8');
|
|
28
|
+
decrypted += decipher.final('utf8');
|
|
29
|
+
return JSON.parse(decrypted);
|
|
30
|
+
}
|
|
31
|
+
_rsaPublicKeyGeneration(privateKeyPem) {
|
|
32
|
+
const privateKeyObject = crypto_1.default.createPrivateKey({
|
|
33
|
+
key: privateKeyPem.replace(/\\n/g, '\n'),
|
|
34
|
+
format: 'pem',
|
|
35
|
+
type: 'pkcs8'
|
|
36
|
+
});
|
|
37
|
+
const publicKeyObject = crypto_1.default.createPublicKey(privateKeyObject);
|
|
38
|
+
return publicKeyObject.export({ type: 'spki', format: 'pem' });
|
|
39
|
+
}
|
|
40
|
+
_rsaPrivatePublicKeyGeneration() {
|
|
41
|
+
const { publicKey, privateKey } = crypto_1.default.generateKeyPairSync('rsa', {
|
|
42
|
+
modulusLength: 2048,
|
|
43
|
+
publicKeyEncoding: {
|
|
44
|
+
type: 'spki',
|
|
45
|
+
format: 'pem'
|
|
46
|
+
},
|
|
47
|
+
privateKeyEncoding: {
|
|
48
|
+
type: 'pkcs8',
|
|
49
|
+
format: 'pem'
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return { privateKey, publicKey };
|
|
53
|
+
}
|
|
54
|
+
encrypt(algo, key, payload, exp) {
|
|
55
|
+
const keyHash = crypto_1.default.createHash('sha256').update(key).digest();
|
|
56
|
+
const newPayload = { payload: payload, exp: exp };
|
|
57
|
+
const { iv, encrypted, tag } = this._encrypt(algo, keyHash, newPayload);
|
|
58
|
+
return (0, functions_lib_1.tokenFormatCreate)({
|
|
59
|
+
runtime: 'node',
|
|
60
|
+
algo: 'AES-256-GCM',
|
|
61
|
+
type: 'symmetric',
|
|
62
|
+
v: '1',
|
|
63
|
+
iv,
|
|
64
|
+
tag
|
|
65
|
+
}, encrypted);
|
|
66
|
+
}
|
|
67
|
+
decrypt(algo, key, encryptedData) {
|
|
68
|
+
const keyHash = crypto_1.default.createHash('sha256').update(key).digest();
|
|
69
|
+
return this._decrypt(algo, keyHash, encryptedData);
|
|
70
|
+
}
|
|
71
|
+
encryptRSA(payload, publicKey, exp) {
|
|
72
|
+
const symmetricKey = crypto_1.default.randomBytes(32);
|
|
73
|
+
const newPayload = { payload: payload, exp: exp };
|
|
74
|
+
const { iv, encrypted, tag } = this._encrypt('aes-256-gcm', symmetricKey, newPayload);
|
|
75
|
+
const encryptedSymmetricKey = crypto_1.default.publicEncrypt({
|
|
76
|
+
key: publicKey,
|
|
77
|
+
padding: crypto_1.default.constants.RSA_PKCS1_OAEP_PADDING,
|
|
78
|
+
oaepHash: 'sha256'
|
|
79
|
+
}, symmetricKey);
|
|
80
|
+
return (0, functions_lib_1.tokenFormatCreate)({
|
|
81
|
+
runtime: 'node',
|
|
82
|
+
algo: 'RSA+A256GCM',
|
|
83
|
+
type: 'asymmetric',
|
|
84
|
+
v: '1',
|
|
85
|
+
iv,
|
|
86
|
+
tag,
|
|
87
|
+
encryptedKey: encryptedSymmetricKey.toString('base64')
|
|
88
|
+
}, encrypted);
|
|
89
|
+
}
|
|
90
|
+
decryptRSA(privateKey, encryptedKey, encryptedData) {
|
|
91
|
+
const decryptedSymmetricKey = crypto_1.default.privateDecrypt({
|
|
92
|
+
key: privateKey,
|
|
93
|
+
padding: crypto_1.default.constants.RSA_PKCS1_OAEP_PADDING,
|
|
94
|
+
oaepHash: 'sha256'
|
|
95
|
+
}, Buffer.from(encryptedKey, 'base64'));
|
|
96
|
+
return this._decrypt('aes-256-gcm', decryptedSymmetricKey, encryptedData);
|
|
97
|
+
}
|
|
98
|
+
rsaPrivatePublicKeyGeneration() {
|
|
99
|
+
return this._rsaPrivatePublicKeyGeneration();
|
|
100
|
+
}
|
|
101
|
+
rsaPublicKeyGeneration(privateKeyPem) {
|
|
102
|
+
return this._rsaPublicKeyGeneration(privateKeyPem);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
exports.NodeCrypto = NodeCrypto;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare class WebCrypto {
|
|
2
|
+
private textEncoder;
|
|
3
|
+
private textDecoder;
|
|
4
|
+
private __importAESKey;
|
|
5
|
+
private __uint8ArrayToBase64;
|
|
6
|
+
private __base64ToUint8Array;
|
|
7
|
+
private __arrayBufferToBase64;
|
|
8
|
+
private __base64ToArrayBuffer;
|
|
9
|
+
private __pemToArrayBuffer;
|
|
10
|
+
private __arrayBufferToPem;
|
|
11
|
+
private __importPublicKey;
|
|
12
|
+
private __importPrivateKey;
|
|
13
|
+
private _encrypt;
|
|
14
|
+
private _decrypt;
|
|
15
|
+
private _rsaPublicKeyGeneration;
|
|
16
|
+
private _rsaPrivatePublicKeyGeneration;
|
|
17
|
+
encrypt(algo: 'AES-GCM', key: string, payload: any, exp: number): Promise<string>;
|
|
18
|
+
decrypt<T>(algo: 'AES-GCM', key: string, encryptedData: {
|
|
19
|
+
iv: string;
|
|
20
|
+
encrypted: string;
|
|
21
|
+
}): Promise<{
|
|
22
|
+
payload: T;
|
|
23
|
+
exp: number;
|
|
24
|
+
}>;
|
|
25
|
+
encryptRSA(payload: any, publicKeyPem: string, exp: number): Promise<string>;
|
|
26
|
+
decryptRSA<T>(privateKeyPem: string, encryptedKey: string, encryptedData: {
|
|
27
|
+
iv: string;
|
|
28
|
+
encrypted: string;
|
|
29
|
+
}): Promise<{
|
|
30
|
+
payload: T;
|
|
31
|
+
exp: number;
|
|
32
|
+
}>;
|
|
33
|
+
rsaPrivatePublicKeyGeneration(): Promise<{
|
|
34
|
+
privateKey: string;
|
|
35
|
+
publicKey: string;
|
|
36
|
+
}>;
|
|
37
|
+
rsaPublicKeyGeneration(privateKeyPem: string): Promise<string>;
|
|
38
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebCrypto = void 0;
|
|
4
|
+
const functions_lib_1 = require("../lib/functions.lib");
|
|
5
|
+
class WebCrypto {
|
|
6
|
+
textEncoder = new TextEncoder();
|
|
7
|
+
textDecoder = new TextDecoder();
|
|
8
|
+
async __importAESKey(password) {
|
|
9
|
+
const passwordBuffer = this.textEncoder.encode(password);
|
|
10
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', passwordBuffer);
|
|
11
|
+
return await crypto.subtle.importKey('raw', hashBuffer, { name: 'AES-GCM' }, false, ['encrypt', 'decrypt']);
|
|
12
|
+
}
|
|
13
|
+
__uint8ArrayToBase64(uint8Array) {
|
|
14
|
+
let binary = '';
|
|
15
|
+
const len = uint8Array.byteLength;
|
|
16
|
+
for (let i = 0; i < len; i++) {
|
|
17
|
+
binary += String.fromCharCode(uint8Array[i]);
|
|
18
|
+
}
|
|
19
|
+
return btoa(binary);
|
|
20
|
+
}
|
|
21
|
+
__base64ToUint8Array(base64) {
|
|
22
|
+
const binaryString = atob(base64);
|
|
23
|
+
const len = binaryString.length;
|
|
24
|
+
const bytes = new Uint8Array(len);
|
|
25
|
+
for (let i = 0; i < len; i++) {
|
|
26
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
27
|
+
}
|
|
28
|
+
return bytes;
|
|
29
|
+
}
|
|
30
|
+
__arrayBufferToBase64(buffer) {
|
|
31
|
+
const bytes = new Uint8Array(buffer);
|
|
32
|
+
let binary = '';
|
|
33
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
34
|
+
binary += String.fromCharCode(bytes[i]);
|
|
35
|
+
}
|
|
36
|
+
return btoa(binary);
|
|
37
|
+
}
|
|
38
|
+
__base64ToArrayBuffer(base64) {
|
|
39
|
+
const binary = atob(base64);
|
|
40
|
+
const bytes = new Uint8Array(binary.length);
|
|
41
|
+
for (let i = 0; i < binary.length; i++) {
|
|
42
|
+
bytes[i] = binary.charCodeAt(i);
|
|
43
|
+
}
|
|
44
|
+
return bytes.buffer;
|
|
45
|
+
}
|
|
46
|
+
__pemToArrayBuffer(pem, type) {
|
|
47
|
+
const pemHeader = `-----BEGIN ${type} KEY-----`;
|
|
48
|
+
const pemFooter = `-----END ${type} KEY-----`;
|
|
49
|
+
const pemContents = pem
|
|
50
|
+
.replace(pemHeader, '')
|
|
51
|
+
.replace(pemFooter, '')
|
|
52
|
+
.replace(/\\n/g, '')
|
|
53
|
+
.replace(/\s/g, '');
|
|
54
|
+
return this.__base64ToArrayBuffer(pemContents);
|
|
55
|
+
}
|
|
56
|
+
__arrayBufferToPem(buffer, type) {
|
|
57
|
+
const base64 = this.__arrayBufferToBase64(buffer);
|
|
58
|
+
const pemContents = base64.match(/.{1,64}/g)?.join('\n') || base64;
|
|
59
|
+
return `-----BEGIN ${type} KEY-----\n${pemContents}\n-----END ${type} KEY-----`;
|
|
60
|
+
}
|
|
61
|
+
async __importPublicKey(publicKeyPem) {
|
|
62
|
+
const keyData = this.__pemToArrayBuffer(publicKeyPem, 'PUBLIC');
|
|
63
|
+
return await crypto.subtle.importKey('spki', keyData, {
|
|
64
|
+
name: 'RSA-OAEP',
|
|
65
|
+
hash: 'SHA-256'
|
|
66
|
+
}, true, ['encrypt']);
|
|
67
|
+
}
|
|
68
|
+
async __importPrivateKey(privateKeyPem) {
|
|
69
|
+
const keyData = this.__pemToArrayBuffer(privateKeyPem.replace(/\\n/g, '\n'), 'PRIVATE');
|
|
70
|
+
return await crypto.subtle.importKey('pkcs8', keyData, {
|
|
71
|
+
name: 'RSA-OAEP',
|
|
72
|
+
hash: 'SHA-256'
|
|
73
|
+
}, true, ['decrypt']);
|
|
74
|
+
}
|
|
75
|
+
async _encrypt(algo, key, payload) {
|
|
76
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
77
|
+
const data = this.textEncoder.encode(JSON.stringify(payload));
|
|
78
|
+
const encryptedBuffer = await crypto.subtle.encrypt({
|
|
79
|
+
name: algo,
|
|
80
|
+
iv: iv,
|
|
81
|
+
tagLength: 128
|
|
82
|
+
}, key, data);
|
|
83
|
+
const encryptedBytes = new Uint8Array(encryptedBuffer);
|
|
84
|
+
return {
|
|
85
|
+
iv: this.__uint8ArrayToBase64(iv),
|
|
86
|
+
encrypted: this.__uint8ArrayToBase64(encryptedBytes),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async _decrypt(algo, key, encryptedData) {
|
|
90
|
+
const { iv, encrypted } = encryptedData;
|
|
91
|
+
const ivBuffer = this.__base64ToUint8Array(iv);
|
|
92
|
+
const encryptedBuffer = this.__base64ToUint8Array(encrypted);
|
|
93
|
+
const decryptedBuffer = await crypto.subtle.decrypt({
|
|
94
|
+
name: algo,
|
|
95
|
+
iv: ivBuffer,
|
|
96
|
+
tagLength: 128
|
|
97
|
+
}, key, encryptedBuffer);
|
|
98
|
+
return JSON.parse(this.textDecoder.decode(decryptedBuffer));
|
|
99
|
+
}
|
|
100
|
+
async _rsaPublicKeyGeneration(privateKeyPem) {
|
|
101
|
+
const privateKey = await this.__importPrivateKey(privateKeyPem);
|
|
102
|
+
const jwk = await crypto.subtle.exportKey('jwk', privateKey);
|
|
103
|
+
delete jwk.d;
|
|
104
|
+
delete jwk.dp;
|
|
105
|
+
delete jwk.dq;
|
|
106
|
+
delete jwk.q;
|
|
107
|
+
delete jwk.qi;
|
|
108
|
+
jwk.key_ops = ['encrypt'];
|
|
109
|
+
const publicKey = await crypto.subtle.importKey('jwk', jwk, {
|
|
110
|
+
name: 'RSA-OAEP',
|
|
111
|
+
hash: 'SHA-256'
|
|
112
|
+
}, true, ['encrypt']);
|
|
113
|
+
const exportedPublicKey = await crypto.subtle.exportKey('spki', publicKey);
|
|
114
|
+
return this.__arrayBufferToPem(exportedPublicKey, 'PUBLIC');
|
|
115
|
+
}
|
|
116
|
+
async _rsaPrivatePublicKeyGeneration() {
|
|
117
|
+
const keyPair = await crypto.subtle.generateKey({
|
|
118
|
+
name: 'RSA-OAEP',
|
|
119
|
+
modulusLength: 2048,
|
|
120
|
+
publicExponent: new Uint8Array([1, 0, 1]),
|
|
121
|
+
hash: 'SHA-256'
|
|
122
|
+
}, true, ['encrypt', 'decrypt']);
|
|
123
|
+
const privateKeyBuffer = await crypto.subtle.exportKey('pkcs8', keyPair.privateKey);
|
|
124
|
+
const publicKeyBuffer = await crypto.subtle.exportKey('spki', keyPair.publicKey);
|
|
125
|
+
return {
|
|
126
|
+
privateKey: this.__arrayBufferToPem(privateKeyBuffer, 'PRIVATE'),
|
|
127
|
+
publicKey: this.__arrayBufferToPem(publicKeyBuffer, 'PUBLIC')
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
async encrypt(algo, key, payload, exp) {
|
|
131
|
+
const cryptoKey = await this.__importAESKey(key);
|
|
132
|
+
const newPayload = { payload: payload, exp: exp };
|
|
133
|
+
const { iv, encrypted } = await this._encrypt(algo, cryptoKey, newPayload);
|
|
134
|
+
return (0, functions_lib_1.tokenFormatCreate)({
|
|
135
|
+
runtime: 'web',
|
|
136
|
+
algo: 'AES-GCM',
|
|
137
|
+
type: 'symmetric',
|
|
138
|
+
v: '1',
|
|
139
|
+
iv,
|
|
140
|
+
}, encrypted);
|
|
141
|
+
}
|
|
142
|
+
async decrypt(algo, key, encryptedData) {
|
|
143
|
+
const cryptoKey = await this.__importAESKey(key);
|
|
144
|
+
return await this._decrypt(algo, cryptoKey, encryptedData);
|
|
145
|
+
}
|
|
146
|
+
async encryptRSA(payload, publicKeyPem, exp) {
|
|
147
|
+
const symmetricKey = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']);
|
|
148
|
+
const newPayload = { payload: payload, exp: exp };
|
|
149
|
+
const { iv, encrypted } = await this._encrypt('AES-GCM', symmetricKey, newPayload);
|
|
150
|
+
const symmetricKeyBuffer = await crypto.subtle.exportKey('raw', symmetricKey);
|
|
151
|
+
const publicKey = await this.__importPublicKey(publicKeyPem);
|
|
152
|
+
const encryptedSymmetricKey = await crypto.subtle.encrypt({
|
|
153
|
+
name: 'RSA-OAEP'
|
|
154
|
+
}, publicKey, symmetricKeyBuffer);
|
|
155
|
+
return (0, functions_lib_1.tokenFormatCreate)({
|
|
156
|
+
runtime: 'web',
|
|
157
|
+
algo: 'RSA+AES-GCM',
|
|
158
|
+
type: 'asymmetric',
|
|
159
|
+
v: '1',
|
|
160
|
+
iv,
|
|
161
|
+
encryptedKey: this.__arrayBufferToBase64(encryptedSymmetricKey)
|
|
162
|
+
}, encrypted);
|
|
163
|
+
}
|
|
164
|
+
async decryptRSA(privateKeyPem, encryptedKey, encryptedData) {
|
|
165
|
+
const privateKey = await this.__importPrivateKey(privateKeyPem);
|
|
166
|
+
const encryptedKeyBuffer = this.__base64ToArrayBuffer(encryptedKey);
|
|
167
|
+
const decryptedSymmetricKeyBuffer = await crypto.subtle.decrypt({
|
|
168
|
+
name: 'RSA-OAEP'
|
|
169
|
+
}, privateKey, encryptedKeyBuffer);
|
|
170
|
+
const symmetricKey = await crypto.subtle.importKey('raw', decryptedSymmetricKeyBuffer, { name: 'AES-GCM' }, false, ['decrypt']);
|
|
171
|
+
return await this._decrypt('AES-GCM', symmetricKey, encryptedData);
|
|
172
|
+
}
|
|
173
|
+
async rsaPrivatePublicKeyGeneration() {
|
|
174
|
+
return await this._rsaPrivatePublicKeyGeneration();
|
|
175
|
+
}
|
|
176
|
+
async rsaPublicKeyGeneration(privateKeyPem) {
|
|
177
|
+
return await this._rsaPublicKeyGeneration(privateKeyPem);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
exports.WebCrypto = WebCrypto;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
|
-
declare
|
|
2
|
-
|
|
3
|
-
|
|
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>;
|
|
4
20
|
};
|
|
5
|
-
|
|
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
CHANGED
|
@@ -1,68 +1,133 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const decryption_lib_1 = __importDefault(require("./lib/decryption.lib"));
|
|
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");
|
|
11
7
|
const functions_lib_1 = require("./lib/functions.lib");
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
};
|
|
40
|
-
const verify = (encryptedToken, keys) => {
|
|
41
|
-
let token = '';
|
|
42
|
-
let header;
|
|
43
|
-
let payload = '';
|
|
44
|
-
let { signKey, encKey } = keys;
|
|
45
|
-
if (!signKey)
|
|
46
|
-
throw new Error("please provide signkey");
|
|
47
|
-
if (!encKey)
|
|
48
|
-
throw new Error("please provide encKey");
|
|
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) {
|
|
49
35
|
try {
|
|
50
|
-
|
|
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);
|
|
51
43
|
}
|
|
52
44
|
catch (error) {
|
|
53
|
-
|
|
45
|
+
(0, functions_lib_1.print)({ dev: this.dev, color: 'red' }, error);
|
|
46
|
+
throw error;
|
|
54
47
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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;
|
|
59
62
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
throw
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
};
|
|
66
|
-
return { create, verify };
|
|
63
|
+
catch (error) {
|
|
64
|
+
(0, functions_lib_1.print)({ dev: this.dev, color: 'red' }, error);
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
67
68
|
}
|
|
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;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
declare function
|
|
2
|
-
declare function
|
|
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
|
+
};
|
|
3
6
|
declare function isExpired(timeStamp: number): boolean;
|
|
4
|
-
|
|
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 };
|
|
@@ -1,47 +1,57 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.algoMatching = algoMatching;
|
|
4
|
-
exports.parseExpiration = parseExpiration;
|
|
5
6
|
exports.isExpired = isExpired;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return
|
|
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}`;
|
|
15
16
|
}
|
|
16
|
-
function
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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 };
|
|
45
55
|
}
|
|
46
56
|
function isExpired(timeStamp) {
|
|
47
57
|
let currentTime = Math.floor(Date.now() / 1000);
|
|
@@ -52,3 +62,24 @@ function isExpired(timeStamp) {
|
|
|
52
62
|
return false;
|
|
53
63
|
}
|
|
54
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,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jsonauthtoken",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "jsonauthtoken is a JavaScript/TypeScript library to secure authentication.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "https://github.com/iamAyanBiswas/jsonauthtoken"
|
|
8
|
+
"url": "git+https://github.com/iamAyanBiswas/jsonauthtoken.git"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"
|
|
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",
|
|
@@ -27,9 +27,6 @@
|
|
|
27
27
|
"jsonauthtoken",
|
|
28
28
|
"jsonwebtoken",
|
|
29
29
|
"auth",
|
|
30
|
-
"authentication"
|
|
31
|
-
"sha256",
|
|
32
|
-
"sha384",
|
|
33
|
-
"sha512"
|
|
30
|
+
"authentication"
|
|
34
31
|
]
|
|
35
|
-
}
|
|
32
|
+
}
|
package/types.d.ts
CHANGED
|
@@ -1,43 +1,67 @@
|
|
|
1
|
+
import { RUNTIME } from "./src/config/name.config";
|
|
2
|
+
|
|
1
3
|
declare global {
|
|
2
|
-
export type Algorithm = 'sha256' | 'sha384' | 'sha512';
|
|
3
|
-
export type AlgorithmArray = ['sha256', 'sha384', 'sha512']
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
9
12
|
}
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
type Runtime = 'node' | 'web' | 'edge';
|
|
15
|
+
type EncryptionAlgorithmType = 'symmetric' | 'asymmetric';
|
|
16
|
+
|
|
17
|
+
interface AlgorithmDetails {
|
|
18
|
+
name: string;
|
|
19
|
+
value: string
|
|
20
|
+
type: EncryptionAlgorithmType;
|
|
15
21
|
}
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
interface RuntimeWiseAlgorithmMap {
|
|
24
|
+
node: 'AES-256-GCM' | 'RSA+A256GCM'
|
|
25
|
+
edge: 'AES-GCM' | 'RSA+AES-GCM'
|
|
26
|
+
web: 'AES-GCM' | 'RSA+AES-GCM'
|
|
21
27
|
}
|
|
22
28
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
type RuntimeWiseAlgorithm<R extends Runtime> = RuntimeWiseAlgorithmMap[R];
|
|
30
|
+
|
|
31
|
+
interface JATConfig<R extends Runtime = Runtime> {
|
|
32
|
+
runtime?: R
|
|
33
|
+
dev?: boolean
|
|
28
34
|
}
|
|
29
35
|
|
|
30
|
-
interface
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
expiresAt: number;
|
|
36
|
+
interface CreateTokenConfig<R extends Runtime> {
|
|
37
|
+
key: string
|
|
38
|
+
exp?: JATTime
|
|
39
|
+
algo?: RuntimeWiseAlgorithm<R>
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
interface
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
interface BaseTokenMetaData<R extends Runtime> {
|
|
43
|
+
runtime: Runtime;
|
|
44
|
+
algo: RuntimeWiseAlgorithm<R>;
|
|
45
|
+
v: string;
|
|
46
|
+
iv: string;
|
|
40
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
|
+
|
|
41
65
|
}
|
|
42
66
|
|
|
43
67
|
export { };
|
|
@@ -1,17 +0,0 @@
|
|
|
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
|
-
const crypto_1 = __importDefault(require("crypto"));
|
|
7
|
-
function decryption(encryptedToken, password) {
|
|
8
|
-
const parts = encryptedToken.split(':');
|
|
9
|
-
const iv = Buffer.from(parts.shift(), 'hex');
|
|
10
|
-
const encryptedTokenBuffer = Buffer.from(parts.join(':'), 'hex');
|
|
11
|
-
const key = crypto_1.default.scryptSync(password, 'salt', 32);
|
|
12
|
-
const decipher = crypto_1.default.createDecipheriv('aes-256-cbc', key, iv);
|
|
13
|
-
let decrypted = decipher.update(encryptedTokenBuffer, null, 'utf8');
|
|
14
|
-
decrypted += decipher.final('utf8');
|
|
15
|
-
return decrypted;
|
|
16
|
-
}
|
|
17
|
-
exports.default = decryption;
|
|
@@ -1,15 +0,0 @@
|
|
|
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
|
-
const crypto_1 = __importDefault(require("crypto"));
|
|
7
|
-
function encryption(password, token) {
|
|
8
|
-
const iv = crypto_1.default.randomBytes(16);
|
|
9
|
-
const key = crypto_1.default.scryptSync(password, 'salt', 32);
|
|
10
|
-
const cipher = crypto_1.default.createCipheriv('aes-256-cbc', key, iv);
|
|
11
|
-
let encrypted = cipher.update(token, 'utf8', 'hex');
|
|
12
|
-
encrypted += cipher.final('hex');
|
|
13
|
-
return iv.toString('hex') + ':' + encrypted;
|
|
14
|
-
}
|
|
15
|
-
exports.default = encryption;
|
|
@@ -1,26 +0,0 @@
|
|
|
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
|
-
const crypto_1 = __importDefault(require("crypto"));
|
|
7
|
-
const decoading_lib_1 = __importDefault(require("./decoading.lib"));
|
|
8
|
-
const signature = () => {
|
|
9
|
-
const createSign = (algorithm, key, header, payload) => {
|
|
10
|
-
const signature = crypto_1.default
|
|
11
|
-
.createHmac(algorithm, key)
|
|
12
|
-
.update(header + '.' + payload)
|
|
13
|
-
.digest('base64url');
|
|
14
|
-
return signature;
|
|
15
|
-
};
|
|
16
|
-
const verifySign = (tokens, key) => {
|
|
17
|
-
const header = (0, decoading_lib_1.default)(tokens.encodedHeader);
|
|
18
|
-
let newSign = createSign(header.algorithm, key, tokens.encodedHeader, tokens.encodedPayload);
|
|
19
|
-
if (newSign === tokens.sign)
|
|
20
|
-
return true;
|
|
21
|
-
else
|
|
22
|
-
return false;
|
|
23
|
-
};
|
|
24
|
-
return { createSign, verifySign };
|
|
25
|
-
};
|
|
26
|
-
exports.default = signature;
|