curtain-web-api 1.0.76 → 1.0.78
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/build/classes/curtain-api.d.ts +1 -1
- package/build/classes/curtain-api.js +13 -3
- package/build/classes/curtain-encryption.d.ts +1 -0
- package/build/classes/curtain-encryption.js +21 -0
- package/package.json +1 -1
- package/src/classes/curtain-api.ts +13 -2
- package/src/classes/curtain-encryption.ts +198 -176
|
@@ -178,7 +178,7 @@ export declare class CurtainWebAPI {
|
|
|
178
178
|
addOwner(linkId: string, owner: string): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
179
179
|
removeOwner(linkId: string, owner: string): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
180
180
|
getCurtainLinks(username: string, sessionDescription?: string, offset?: number, sessionType?: string): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
181
|
-
getSiteProperties(): Promise<import("axios").AxiosResponse<SiteProperties, any, {}>>;
|
|
181
|
+
getSiteProperties(appType?: string): Promise<import("axios").AxiosResponse<SiteProperties, any, {}>>;
|
|
182
182
|
saveDataFilterList(name: string, data: string, category?: string): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
183
183
|
getDataFilterListByID(id: number, limit?: number): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
184
184
|
getDataFilterList(title?: string, searchTerm?: string, category?: string, limit?: number, offset?: number): Promise<import("axios").AxiosResponse<any, any, {}>>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { User } from "./curtain-user";
|
|
2
2
|
import axios, { AxiosHeaders } from "axios";
|
|
3
|
-
import { arrayBufferToBase64String, base64ToArrayBuffer, encryptAESData, encryptAESKey, exportAESKey, generateAESKey } from "./curtain-encryption";
|
|
3
|
+
import { arrayBufferToBase64String, base64ToArrayBuffer, decodeJWTPayload, encryptAESData, encryptAESKey, exportAESKey, generateAESKey } from "./curtain-encryption";
|
|
4
4
|
const base = "https://celsus.muttsu.xyz/";
|
|
5
5
|
export const replacer = (key, value) => {
|
|
6
6
|
if (value instanceof Map) {
|
|
@@ -175,6 +175,12 @@ export class CurtainWebAPI {
|
|
|
175
175
|
});
|
|
176
176
|
}
|
|
177
177
|
checkIfRefreshTokenExpired() {
|
|
178
|
+
if (this.user.refresh_token) {
|
|
179
|
+
const payload = decodeJWTPayload(this.user.refresh_token);
|
|
180
|
+
if (payload && payload.exp) {
|
|
181
|
+
return Date.now() >= payload.exp * 1000;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
178
184
|
let now = new Date();
|
|
179
185
|
let diff = (now.getTime() - this.user.lastRefreshTokenUpdate.getTime()) / 1000;
|
|
180
186
|
diff = diff / 60 / 60;
|
|
@@ -414,10 +420,14 @@ export class CurtainWebAPI {
|
|
|
414
420
|
return response;
|
|
415
421
|
});
|
|
416
422
|
}
|
|
417
|
-
getSiteProperties() {
|
|
423
|
+
getSiteProperties(appType) {
|
|
418
424
|
let headers = new AxiosHeaders();
|
|
419
425
|
headers["Accept"] = "application/json";
|
|
420
|
-
|
|
426
|
+
let params = new URLSearchParams();
|
|
427
|
+
if (appType) {
|
|
428
|
+
params.append("app", appType);
|
|
429
|
+
}
|
|
430
|
+
return this.axiosInstance.get(this.baseURL + "site-properties/", { headers: headers, params: params, responseType: "json" });
|
|
421
431
|
}
|
|
422
432
|
saveDataFilterList(name, data, category = "") {
|
|
423
433
|
let headers = new AxiosHeaders();
|
|
@@ -37,3 +37,4 @@ export declare function encryptDataAES(data: string, publicKey: CryptoKey): Prom
|
|
|
37
37
|
}>;
|
|
38
38
|
export declare function decryptDataAES(encryptedKey: ArrayBuffer, encryptedData: string, iv: string, privateKey: CryptoKey): Promise<string>;
|
|
39
39
|
export declare function hashData(data: string): Promise<string>;
|
|
40
|
+
export declare function decodeJWTPayload(token: string): any;
|
|
@@ -137,3 +137,24 @@ export async function hashData(data) {
|
|
|
137
137
|
const hash = await crypto.subtle.digest("SHA-256", encoded);
|
|
138
138
|
return arrayBufferToBase64String(hash);
|
|
139
139
|
}
|
|
140
|
+
export function decodeJWTPayload(token) {
|
|
141
|
+
try {
|
|
142
|
+
const parts = token.split('.');
|
|
143
|
+
if (parts.length !== 3) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
const base64Url = parts[1];
|
|
147
|
+
let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
|
148
|
+
const pad = base64.length % 4;
|
|
149
|
+
if (pad) {
|
|
150
|
+
base64 += new Array(5 - pad).join('=');
|
|
151
|
+
}
|
|
152
|
+
const jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
|
|
153
|
+
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
|
154
|
+
}).join(''));
|
|
155
|
+
return JSON.parse(jsonPayload);
|
|
156
|
+
}
|
|
157
|
+
catch (e) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@ import axios, {AxiosHeaders} from "axios";
|
|
|
3
3
|
import {
|
|
4
4
|
arrayBufferToBase64String, base64ToArrayBuffer,
|
|
5
5
|
CurtainEncryption,
|
|
6
|
+
decodeJWTPayload,
|
|
6
7
|
encryptAESData, encryptAESKey,
|
|
7
8
|
encryptDataRSA, exportAESKey,
|
|
8
9
|
generateAESKey
|
|
@@ -357,6 +358,12 @@ export class CurtainWebAPI {
|
|
|
357
358
|
}
|
|
358
359
|
|
|
359
360
|
checkIfRefreshTokenExpired() {
|
|
361
|
+
if (this.user.refresh_token) {
|
|
362
|
+
const payload = decodeJWTPayload(this.user.refresh_token);
|
|
363
|
+
if (payload && payload.exp) {
|
|
364
|
+
return Date.now() >= payload.exp * 1000;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
360
367
|
let now = new Date();
|
|
361
368
|
let diff = (now.getTime() - this.user.lastRefreshTokenUpdate.getTime()) / 1000;
|
|
362
369
|
diff = diff/60/60;
|
|
@@ -610,10 +617,14 @@ export class CurtainWebAPI {
|
|
|
610
617
|
});
|
|
611
618
|
}
|
|
612
619
|
|
|
613
|
-
getSiteProperties() {
|
|
620
|
+
getSiteProperties(appType?: string) {
|
|
614
621
|
let headers = new AxiosHeaders();
|
|
615
622
|
headers["Accept"] = "application/json";
|
|
616
|
-
|
|
623
|
+
let params = new URLSearchParams();
|
|
624
|
+
if (appType) {
|
|
625
|
+
params.append("app", appType);
|
|
626
|
+
}
|
|
627
|
+
return this.axiosInstance.get<SiteProperties>(this.baseURL + "site-properties/", {headers: headers, params: params, responseType:"json"});
|
|
617
628
|
}
|
|
618
629
|
|
|
619
630
|
saveDataFilterList(name: string, data: string, category: string = "") {
|
|
@@ -1,176 +1,198 @@
|
|
|
1
|
-
export function encryptDataRSA(data: string, publicKey: CryptoKey) {
|
|
2
|
-
return crypto.subtle.encrypt({name: 'RSA-OAEP'}, publicKey, new TextEncoder().encode(data))
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export function decryptDataRSA(data: string, privateKey: CryptoKey) {
|
|
6
|
-
return crypto.subtle.decrypt({name: 'RSA-OAEP'}, privateKey, new TextEncoder().encode(data))
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export async function importPublicKey(key: ArrayBuffer) {
|
|
10
|
-
return await crypto.subtle.importKey('spki', key, {name: 'RSA-OAEP', hash: 'SHA-256'}, true, ['encrypt'])
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export async function importPrivateKey(key: ArrayBuffer) {
|
|
14
|
-
return await crypto.subtle.importKey('pkcs8', key, {name: 'RSA-OAEP', hash: 'SHA-256'}, true, ['decrypt'])
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function generateKeyPair(modulusLength: number = 2048, publicExponent: Uint8Array = new Uint8Array([1, 0, 1])) {
|
|
18
|
-
return await crypto.subtle.generateKey(
|
|
19
|
-
{
|
|
20
|
-
name: "RSA-OAEP",
|
|
21
|
-
modulusLength: modulusLength,
|
|
22
|
-
publicExponent: publicExponent,
|
|
23
|
-
hash: "SHA-256",
|
|
24
|
-
} as RsaHashedKeyGenParams,
|
|
25
|
-
true,
|
|
26
|
-
["encrypt", "decrypt"],
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export async function exportPublicKey(key: CryptoKey) {
|
|
31
|
-
return await crypto.subtle.exportKey('spki', key)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export async function exportPrivateKey(key: CryptoKey) {
|
|
35
|
-
return await crypto.subtle.exportKey('pkcs8', key)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export async function importKey(key: ArrayBuffer, type: "public"|"private") {
|
|
39
|
-
if (type === "public") {
|
|
40
|
-
return await importPublicKey(key)
|
|
41
|
-
} else {
|
|
42
|
-
return await importPrivateKey(key)
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export async function exportKeyString(key: CryptoKey, type: "public"|"private"): Promise<string> {
|
|
47
|
-
if (type === "public") {
|
|
48
|
-
const k = await exportPublicKey(key)
|
|
49
|
-
return arrayBufferToBase64String(k)
|
|
50
|
-
} else {
|
|
51
|
-
const k = await exportPrivateKey(key)
|
|
52
|
-
return arrayBufferToBase64String(k)
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export async function saveToLocalStorage(key: CryptoKey, type: "public"|"private") {
|
|
57
|
-
const k = await exportKeyString(key, type)
|
|
58
|
-
localStorage.setItem(type + "_key", k)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export async function loadFromLocalStorage(type: "public"|"private") {
|
|
62
|
-
const k = localStorage.getItem(type + "_key")
|
|
63
|
-
if (k) {
|
|
64
|
-
return await importKey(pemToArrayBuffer(k), type)
|
|
65
|
-
}
|
|
66
|
-
return undefined
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export interface CurtainEncryption {
|
|
70
|
-
encrypted: boolean,
|
|
71
|
-
publicKey?: CryptoKey,
|
|
72
|
-
e2e: boolean,
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function arrayBufferToBase64String(arrayBuffer: ArrayBuffer) {
|
|
76
|
-
const byteArray = new Uint8Array(arrayBuffer)
|
|
77
|
-
let byteString = ''
|
|
78
|
-
for (let i=0; i<byteArray.byteLength; i++) {
|
|
79
|
-
byteString += String.fromCharCode(byteArray[i])
|
|
80
|
-
}
|
|
81
|
-
return btoa(byteString)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function removeLines(str_data: string) {
|
|
85
|
-
return str_data.replace("\n", "");
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function base64ToArrayBuffer(b64: string): ArrayBuffer {
|
|
89
|
-
const byteString = atob(b64);
|
|
90
|
-
const byteArray = new Uint8Array(byteString.length);
|
|
91
|
-
for(let i=0; i < byteString.length; i++) {
|
|
92
|
-
byteArray[i] = byteString.charCodeAt(i);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return byteArray.buffer;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function pemToArrayBuffer(pem: string) {
|
|
99
|
-
const b64Lines = removeLines(pem);
|
|
100
|
-
let b64Prefix = b64Lines.replace('-----BEGIN PRIVATE KEY-----', '');
|
|
101
|
-
b64Prefix = b64Prefix.replace('-----BEGIN PUBLIC KEY-----', '');
|
|
102
|
-
let b64Final = b64Prefix.replace('-----END PRIVATE KEY-----', '');
|
|
103
|
-
b64Final = b64Final.replace('-----END PUBLIC KEY-----', '');
|
|
104
|
-
|
|
105
|
-
return base64ToArrayBuffer(b64Final);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// a function to generate to encrypt an aes key arraybuffer with a public key
|
|
109
|
-
export async function encryptAESKey(publicKey: CryptoKey, aesKey: ArrayBuffer) {
|
|
110
|
-
return await crypto.subtle.encrypt({name: "RSA-OAEP"}, publicKey, aesKey)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// a function to generate an aes key in GCM mode with a length of 256 bits
|
|
114
|
-
export async function generateAESKey() {
|
|
115
|
-
return await crypto.subtle.generateKey(
|
|
116
|
-
{
|
|
117
|
-
name: "AES-GCM",
|
|
118
|
-
length: 256,
|
|
119
|
-
},
|
|
120
|
-
true,
|
|
121
|
-
["encrypt", "decrypt"],
|
|
122
|
-
)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// a function to encrypt a string with an aes key
|
|
126
|
-
export async function encryptAESData(aesKey: CryptoKey, data: string) {
|
|
127
|
-
const iv = crypto.getRandomValues(new Uint8Array(12))
|
|
128
|
-
const enc = new TextEncoder()
|
|
129
|
-
const encoded = enc.encode(data)
|
|
130
|
-
const encrypted = await crypto.subtle.encrypt({name: "AES-GCM", iv: iv}, aesKey, encoded)
|
|
131
|
-
return {encrypted: arrayBufferToBase64String(encrypted), iv: arrayBufferToBase64String(iv.buffer)}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// a function to decrypt a string with an aes key
|
|
135
|
-
export async function decryptAESData(aesKey: CryptoKey, data: string, iv: string) {
|
|
136
|
-
const dec = new TextDecoder()
|
|
137
|
-
const decrypted = await crypto.subtle.decrypt({name: "AES-GCM", iv: base64ToArrayBuffer(iv)}, aesKey, base64ToArrayBuffer(data))
|
|
138
|
-
return dec.decode(decrypted)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// a function to decrypt an aes key with a private key
|
|
142
|
-
export async function decryptAESKey(privateKey: CryptoKey, encryptedKey: ArrayBuffer) {
|
|
143
|
-
return await crypto.subtle.decrypt({name: "RSA-OAEP"}, privateKey, encryptedKey)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// a function to export an aes key to a string
|
|
147
|
-
export async function exportAESKey(key: CryptoKey) {
|
|
148
|
-
return await crypto.subtle.exportKey("raw", key)
|
|
149
|
-
}
|
|
150
|
-
// a function to import an aes key from a string
|
|
151
|
-
export async function importAESKey(key: ArrayBuffer) {
|
|
152
|
-
return await crypto.subtle.importKey("raw", key, "AES-GCM", true, ["encrypt", "decrypt"])
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// a function to encrypt aes key with a public key and also use the aes key to encrypt a large string then return the encrypted aes key and the encrypted string
|
|
156
|
-
export async function encryptDataAES(data: string, publicKey: CryptoKey) {
|
|
157
|
-
const aesKey = await generateAESKey()
|
|
158
|
-
const encryptedKey = await encryptAESKey(publicKey, await exportAESKey(aesKey))
|
|
159
|
-
const encryptedData = await encryptAESData(aesKey, data)
|
|
160
|
-
return {encryptedKey: arrayBufferToBase64String(encryptedKey), encryptedData: encryptedData}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// a function to decrypt an aes key with a private key and use the aes key to decrypt a large string
|
|
164
|
-
export async function decryptDataAES(encryptedKey: ArrayBuffer, encryptedData: string, iv: string, privateKey: CryptoKey) {
|
|
165
|
-
const aesKey = await decryptAESKey(privateKey, encryptedKey)
|
|
166
|
-
//import aes key
|
|
167
|
-
return await decryptAESData(await importAESKey(aesKey), encryptedData, iv)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// a function to calculate sha-256 hash of a large string
|
|
171
|
-
export async function hashData(data: string) {
|
|
172
|
-
const enc = new TextEncoder()
|
|
173
|
-
const encoded = enc.encode(data)
|
|
174
|
-
const hash = await crypto.subtle.digest("SHA-256", encoded)
|
|
175
|
-
return arrayBufferToBase64String(hash)
|
|
176
|
-
}
|
|
1
|
+
export function encryptDataRSA(data: string, publicKey: CryptoKey) {
|
|
2
|
+
return crypto.subtle.encrypt({name: 'RSA-OAEP'}, publicKey, new TextEncoder().encode(data))
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function decryptDataRSA(data: string, privateKey: CryptoKey) {
|
|
6
|
+
return crypto.subtle.decrypt({name: 'RSA-OAEP'}, privateKey, new TextEncoder().encode(data))
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function importPublicKey(key: ArrayBuffer) {
|
|
10
|
+
return await crypto.subtle.importKey('spki', key, {name: 'RSA-OAEP', hash: 'SHA-256'}, true, ['encrypt'])
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function importPrivateKey(key: ArrayBuffer) {
|
|
14
|
+
return await crypto.subtle.importKey('pkcs8', key, {name: 'RSA-OAEP', hash: 'SHA-256'}, true, ['decrypt'])
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function generateKeyPair(modulusLength: number = 2048, publicExponent: Uint8Array = new Uint8Array([1, 0, 1])) {
|
|
18
|
+
return await crypto.subtle.generateKey(
|
|
19
|
+
{
|
|
20
|
+
name: "RSA-OAEP",
|
|
21
|
+
modulusLength: modulusLength,
|
|
22
|
+
publicExponent: publicExponent,
|
|
23
|
+
hash: "SHA-256",
|
|
24
|
+
} as RsaHashedKeyGenParams,
|
|
25
|
+
true,
|
|
26
|
+
["encrypt", "decrypt"],
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function exportPublicKey(key: CryptoKey) {
|
|
31
|
+
return await crypto.subtle.exportKey('spki', key)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function exportPrivateKey(key: CryptoKey) {
|
|
35
|
+
return await crypto.subtle.exportKey('pkcs8', key)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function importKey(key: ArrayBuffer, type: "public"|"private") {
|
|
39
|
+
if (type === "public") {
|
|
40
|
+
return await importPublicKey(key)
|
|
41
|
+
} else {
|
|
42
|
+
return await importPrivateKey(key)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function exportKeyString(key: CryptoKey, type: "public"|"private"): Promise<string> {
|
|
47
|
+
if (type === "public") {
|
|
48
|
+
const k = await exportPublicKey(key)
|
|
49
|
+
return arrayBufferToBase64String(k)
|
|
50
|
+
} else {
|
|
51
|
+
const k = await exportPrivateKey(key)
|
|
52
|
+
return arrayBufferToBase64String(k)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function saveToLocalStorage(key: CryptoKey, type: "public"|"private") {
|
|
57
|
+
const k = await exportKeyString(key, type)
|
|
58
|
+
localStorage.setItem(type + "_key", k)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function loadFromLocalStorage(type: "public"|"private") {
|
|
62
|
+
const k = localStorage.getItem(type + "_key")
|
|
63
|
+
if (k) {
|
|
64
|
+
return await importKey(pemToArrayBuffer(k), type)
|
|
65
|
+
}
|
|
66
|
+
return undefined
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface CurtainEncryption {
|
|
70
|
+
encrypted: boolean,
|
|
71
|
+
publicKey?: CryptoKey,
|
|
72
|
+
e2e: boolean,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function arrayBufferToBase64String(arrayBuffer: ArrayBuffer) {
|
|
76
|
+
const byteArray = new Uint8Array(arrayBuffer)
|
|
77
|
+
let byteString = ''
|
|
78
|
+
for (let i=0; i<byteArray.byteLength; i++) {
|
|
79
|
+
byteString += String.fromCharCode(byteArray[i])
|
|
80
|
+
}
|
|
81
|
+
return btoa(byteString)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function removeLines(str_data: string) {
|
|
85
|
+
return str_data.replace("\n", "");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function base64ToArrayBuffer(b64: string): ArrayBuffer {
|
|
89
|
+
const byteString = atob(b64);
|
|
90
|
+
const byteArray = new Uint8Array(byteString.length);
|
|
91
|
+
for(let i=0; i < byteString.length; i++) {
|
|
92
|
+
byteArray[i] = byteString.charCodeAt(i);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return byteArray.buffer;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function pemToArrayBuffer(pem: string) {
|
|
99
|
+
const b64Lines = removeLines(pem);
|
|
100
|
+
let b64Prefix = b64Lines.replace('-----BEGIN PRIVATE KEY-----', '');
|
|
101
|
+
b64Prefix = b64Prefix.replace('-----BEGIN PUBLIC KEY-----', '');
|
|
102
|
+
let b64Final = b64Prefix.replace('-----END PRIVATE KEY-----', '');
|
|
103
|
+
b64Final = b64Final.replace('-----END PUBLIC KEY-----', '');
|
|
104
|
+
|
|
105
|
+
return base64ToArrayBuffer(b64Final);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// a function to generate to encrypt an aes key arraybuffer with a public key
|
|
109
|
+
export async function encryptAESKey(publicKey: CryptoKey, aesKey: ArrayBuffer) {
|
|
110
|
+
return await crypto.subtle.encrypt({name: "RSA-OAEP"}, publicKey, aesKey)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// a function to generate an aes key in GCM mode with a length of 256 bits
|
|
114
|
+
export async function generateAESKey() {
|
|
115
|
+
return await crypto.subtle.generateKey(
|
|
116
|
+
{
|
|
117
|
+
name: "AES-GCM",
|
|
118
|
+
length: 256,
|
|
119
|
+
},
|
|
120
|
+
true,
|
|
121
|
+
["encrypt", "decrypt"],
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// a function to encrypt a string with an aes key
|
|
126
|
+
export async function encryptAESData(aesKey: CryptoKey, data: string) {
|
|
127
|
+
const iv = crypto.getRandomValues(new Uint8Array(12))
|
|
128
|
+
const enc = new TextEncoder()
|
|
129
|
+
const encoded = enc.encode(data)
|
|
130
|
+
const encrypted = await crypto.subtle.encrypt({name: "AES-GCM", iv: iv}, aesKey, encoded)
|
|
131
|
+
return {encrypted: arrayBufferToBase64String(encrypted), iv: arrayBufferToBase64String(iv.buffer)}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// a function to decrypt a string with an aes key
|
|
135
|
+
export async function decryptAESData(aesKey: CryptoKey, data: string, iv: string) {
|
|
136
|
+
const dec = new TextDecoder()
|
|
137
|
+
const decrypted = await crypto.subtle.decrypt({name: "AES-GCM", iv: base64ToArrayBuffer(iv)}, aesKey, base64ToArrayBuffer(data))
|
|
138
|
+
return dec.decode(decrypted)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// a function to decrypt an aes key with a private key
|
|
142
|
+
export async function decryptAESKey(privateKey: CryptoKey, encryptedKey: ArrayBuffer) {
|
|
143
|
+
return await crypto.subtle.decrypt({name: "RSA-OAEP"}, privateKey, encryptedKey)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// a function to export an aes key to a string
|
|
147
|
+
export async function exportAESKey(key: CryptoKey) {
|
|
148
|
+
return await crypto.subtle.exportKey ("raw", key)
|
|
149
|
+
}
|
|
150
|
+
// a function to import an aes key from a string
|
|
151
|
+
export async function importAESKey(key: ArrayBuffer) {
|
|
152
|
+
return await crypto.subtle.importKey("raw", key, "AES-GCM", true, ["encrypt", "decrypt"])
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// a function to encrypt aes key with a public key and also use the aes key to encrypt a large string then return the encrypted aes key and the encrypted string
|
|
156
|
+
export async function encryptDataAES(data: string, publicKey: CryptoKey) {
|
|
157
|
+
const aesKey = await generateAESKey()
|
|
158
|
+
const encryptedKey = await encryptAESKey(publicKey, await exportAESKey(aesKey))
|
|
159
|
+
const encryptedData = await encryptAESData(aesKey, data)
|
|
160
|
+
return {encryptedKey: arrayBufferToBase64String(encryptedKey), encryptedData: encryptedData}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// a function to decrypt an aes key with a private key and use the aes key to decrypt a large string
|
|
164
|
+
export async function decryptDataAES(encryptedKey: ArrayBuffer, encryptedData: string, iv: string, privateKey: CryptoKey) {
|
|
165
|
+
const aesKey = await decryptAESKey(privateKey, encryptedKey)
|
|
166
|
+
//import aes key
|
|
167
|
+
return await decryptAESData(await importAESKey(aesKey), encryptedData, iv)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// a function to calculate sha-256 hash of a large string
|
|
171
|
+
export async function hashData(data: string) {
|
|
172
|
+
const enc = new TextEncoder()
|
|
173
|
+
const encoded = enc.encode(data)
|
|
174
|
+
const hash = await crypto.subtle.digest("SHA-256", encoded)
|
|
175
|
+
return arrayBufferToBase64String(hash)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function decodeJWTPayload(token: string) {
|
|
179
|
+
try {
|
|
180
|
+
const parts = token.split('.');
|
|
181
|
+
if (parts.length !== 3) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
const base64Url = parts[1];
|
|
185
|
+
let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
|
186
|
+
const pad = base64.length % 4;
|
|
187
|
+
if (pad) {
|
|
188
|
+
base64 += new Array(5 - pad).join('=');
|
|
189
|
+
}
|
|
190
|
+
const jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
|
|
191
|
+
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
|
192
|
+
}).join(''));
|
|
193
|
+
|
|
194
|
+
return JSON.parse(jsonPayload);
|
|
195
|
+
} catch (e) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|