@anteros/core 0.0.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +143 -0
- package/database/collection.ts +160 -0
- package/database/decorator.ts +172 -0
- package/database/file.ts +93 -0
- package/database/mongodbadapter.ts +1128 -0
- package/database/rest.ts +14 -0
- package/database/schema.ts +160 -0
- package/database/tenant.ts +37 -0
- package/database/workflow.ts +384 -0
- package/index.ts +28 -0
- package/lib/asyncContextStorage.ts +68 -0
- package/lib/define.ts +114 -0
- package/lib/error.ts +21 -0
- package/lib/files.ts +459 -0
- package/lib/middleware.ts +66 -0
- package/lib/routes.ts +44 -0
- package/lib/scripts.ts +47 -0
- package/lib/services.ts +45 -0
- package/lib/sockets.ts +44 -0
- package/lib/workflow.ts +60 -0
- package/package.json +31 -0
- package/server/api.ts +789 -0
- package/server/boot.ts +101 -0
- package/server/config.ts +107 -0
- package/server/env.ts +16 -0
- package/server/hono.ts +176 -0
- package/server/io.ts +15 -0
- package/server/routes.ts +48 -0
- package/server/security.ts +138 -0
- package/tests/api.test.ts +281 -0
- package/tsconfig.json +36 -0
- package/types/activity.d.ts +45 -0
- package/types/api.d.ts +85 -0
- package/types/collection.d.ts +82 -0
- package/types/config.d.ts +55 -0
- package/types/field.d.ts +72 -0
- package/types/file.d.ts +120 -0
- package/types/hook.d.ts +30 -0
- package/types/middleware.d.ts +18 -0
- package/types/mongo.d.ts +61 -0
- package/types/options.d.ts +7 -0
- package/types/rest.d.ts +18 -0
- package/types/route.d.ts +19 -0
- package/types/schema.d.ts +0 -0
- package/types/scripts.d.ts +10 -0
- package/types/service.d.ts +37 -0
- package/types/task.d.ts +12 -0
- package/types/tenant.d.ts +16 -0
- package/types/token.d.ts +14 -0
- package/types/websocket.d.ts +15 -0
- package/types/workflow.d.ts +91 -0
- package/utils/cache.ts +96 -0
- package/utils/crypto.ts +226 -0
- package/utils/func.ts +1037 -0
- package/utils/index.ts +17 -0
package/utils/crypto.ts
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
const IV_LENGTH = 12;
|
|
2
|
+
const TAG_LENGTH = 16;
|
|
3
|
+
const RSA_KEY_SIZE = 256;
|
|
4
|
+
|
|
5
|
+
interface JsonWebKey {
|
|
6
|
+
kty?: string;
|
|
7
|
+
alg?: string;
|
|
8
|
+
key_ops?: string[];
|
|
9
|
+
ext?: boolean;
|
|
10
|
+
// RSA
|
|
11
|
+
n?: string;
|
|
12
|
+
e?: string;
|
|
13
|
+
d?: string;
|
|
14
|
+
p?: string;
|
|
15
|
+
q?: string;
|
|
16
|
+
dp?: string;
|
|
17
|
+
dq?: string;
|
|
18
|
+
qi?: string;
|
|
19
|
+
// EC
|
|
20
|
+
crv?: string;
|
|
21
|
+
x?: string;
|
|
22
|
+
y?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class CryptSym {
|
|
26
|
+
#key: CryptoKey | null = null;
|
|
27
|
+
#secret: string;
|
|
28
|
+
|
|
29
|
+
constructor(options: { secret: string }) {
|
|
30
|
+
this.#secret = options.secret;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async #getKey(): Promise<CryptoKey> {
|
|
34
|
+
if (this.#key) return this.#key;
|
|
35
|
+
const hash = new Bun.CryptoHasher("sha256").update(this.#secret).digest();
|
|
36
|
+
this.#key = await crypto.subtle.importKey(
|
|
37
|
+
"raw",
|
|
38
|
+
new Uint8Array(hash),
|
|
39
|
+
{ name: "AES-GCM" },
|
|
40
|
+
false,
|
|
41
|
+
["encrypt", "decrypt"]
|
|
42
|
+
);
|
|
43
|
+
return this.#key;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async encrypt(data: string | object): Promise<string> {
|
|
47
|
+
const text = typeof data === "object" ? JSON.stringify(data) : data;
|
|
48
|
+
const key = await this.#getKey();
|
|
49
|
+
const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
|
|
50
|
+
const encrypted = await crypto.subtle.encrypt(
|
|
51
|
+
{ name: "AES-GCM", iv, tagLength: TAG_LENGTH * 8 },
|
|
52
|
+
key,
|
|
53
|
+
new TextEncoder().encode(text)
|
|
54
|
+
);
|
|
55
|
+
const buffer = new Uint8Array(IV_LENGTH + encrypted.byteLength);
|
|
56
|
+
buffer.set(iv, 0);
|
|
57
|
+
buffer.set(new Uint8Array(encrypted), IV_LENGTH);
|
|
58
|
+
return Buffer.from(buffer).toString("base64");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async decrypt<T = string>(cipher: string, parseJson?: boolean): Promise<T> {
|
|
62
|
+
try {
|
|
63
|
+
const buffer = new Uint8Array(Buffer.from(cipher, "base64"));
|
|
64
|
+
const iv = buffer.slice(0, IV_LENGTH);
|
|
65
|
+
const data = buffer.slice(IV_LENGTH);
|
|
66
|
+
const key = await this.#getKey();
|
|
67
|
+
const decrypted = await crypto.subtle.decrypt(
|
|
68
|
+
{ name: "AES-GCM", iv, tagLength: TAG_LENGTH * 8 },
|
|
69
|
+
key,
|
|
70
|
+
data
|
|
71
|
+
);
|
|
72
|
+
const text = new TextDecoder().decode(decrypted);
|
|
73
|
+
if (parseJson) return JSON.parse(text) as T;
|
|
74
|
+
return text as T;
|
|
75
|
+
} catch (err: any) {
|
|
76
|
+
throw new Error(`Decryption failed: ${err?.message || 'invalid ciphertext or tampered data'}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
class CryptAsym {
|
|
82
|
+
#keyPair: CryptoKeyPair | null = null;
|
|
83
|
+
#privateJwk: JsonWebKey | null = null;
|
|
84
|
+
|
|
85
|
+
constructor(options?: { privateKey?: JsonWebKey }) {
|
|
86
|
+
if (options?.privateKey) {
|
|
87
|
+
this.#privateJwk = options.privateKey;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async #getKeyPair(): Promise<CryptoKeyPair> {
|
|
92
|
+
if (this.#keyPair) return this.#keyPair;
|
|
93
|
+
|
|
94
|
+
if (this.#privateJwk) {
|
|
95
|
+
const privateKey = await crypto.subtle.importKey(
|
|
96
|
+
"jwk",
|
|
97
|
+
this.#privateJwk,
|
|
98
|
+
{ name: "RSA-OAEP", hash: "SHA-256" },
|
|
99
|
+
true,
|
|
100
|
+
["decrypt"]
|
|
101
|
+
);
|
|
102
|
+
const publicJwk: any = await crypto.subtle.exportKey("jwk", privateKey);
|
|
103
|
+
delete publicJwk.d;
|
|
104
|
+
delete publicJwk.p;
|
|
105
|
+
delete publicJwk.q;
|
|
106
|
+
delete publicJwk.dp;
|
|
107
|
+
delete publicJwk.dq;
|
|
108
|
+
delete publicJwk.qi;
|
|
109
|
+
publicJwk.key_ops = ["encrypt"];
|
|
110
|
+
const publicKey = await crypto.subtle.importKey(
|
|
111
|
+
"jwk",
|
|
112
|
+
publicJwk,
|
|
113
|
+
{ name: "RSA-OAEP", hash: "SHA-256" },
|
|
114
|
+
false,
|
|
115
|
+
["encrypt"]
|
|
116
|
+
);
|
|
117
|
+
this.#keyPair = { privateKey, publicKey };
|
|
118
|
+
return this.#keyPair;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this.#keyPair = await crypto.subtle.generateKey(
|
|
122
|
+
{
|
|
123
|
+
name: "RSA-OAEP",
|
|
124
|
+
modulusLength: 2048,
|
|
125
|
+
publicExponent: new Uint8Array([1, 0, 1]),
|
|
126
|
+
hash: "SHA-256",
|
|
127
|
+
},
|
|
128
|
+
true,
|
|
129
|
+
["encrypt", "decrypt"]
|
|
130
|
+
);
|
|
131
|
+
return this.#keyPair;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async encrypt(data: string | object, publicKey?: CryptoKey): Promise<string> {
|
|
135
|
+
const text = typeof data === "object" ? JSON.stringify(data) : data;
|
|
136
|
+
const rsaKey = publicKey ?? (await this.#getKeyPair()).publicKey;
|
|
137
|
+
|
|
138
|
+
const aesKey = await crypto.subtle.generateKey(
|
|
139
|
+
{ name: "AES-GCM", length: 256 },
|
|
140
|
+
true,
|
|
141
|
+
["encrypt"]
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
|
|
145
|
+
const encrypted = await crypto.subtle.encrypt(
|
|
146
|
+
{ name: "AES-GCM", iv, tagLength: TAG_LENGTH * 8 },
|
|
147
|
+
aesKey,
|
|
148
|
+
new TextEncoder().encode(text)
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const rawAesKey = await crypto.subtle.exportKey("raw", aesKey);
|
|
152
|
+
const wrappedKey = await crypto.subtle.encrypt(
|
|
153
|
+
{ name: "RSA-OAEP" },
|
|
154
|
+
rsaKey,
|
|
155
|
+
rawAesKey
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
const result = new Uint8Array(RSA_KEY_SIZE + IV_LENGTH + encrypted.byteLength);
|
|
159
|
+
result.set(new Uint8Array(wrappedKey), 0);
|
|
160
|
+
result.set(iv, RSA_KEY_SIZE);
|
|
161
|
+
result.set(new Uint8Array(encrypted), RSA_KEY_SIZE + IV_LENGTH);
|
|
162
|
+
return Buffer.from(result).toString("base64");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async decrypt<T = string>(cipher: string, parseJson?: boolean): Promise<T> {
|
|
166
|
+
try {
|
|
167
|
+
const buffer = new Uint8Array(Buffer.from(cipher, "base64"));
|
|
168
|
+
if (buffer.length < RSA_KEY_SIZE + IV_LENGTH + TAG_LENGTH) {
|
|
169
|
+
throw new Error("ciphertext too short");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const wrappedKey = buffer.slice(0, RSA_KEY_SIZE);
|
|
173
|
+
const iv = buffer.slice(RSA_KEY_SIZE, RSA_KEY_SIZE + IV_LENGTH);
|
|
174
|
+
const ciphertext = buffer.slice(RSA_KEY_SIZE + IV_LENGTH);
|
|
175
|
+
|
|
176
|
+
const { privateKey } = await this.#getKeyPair();
|
|
177
|
+
const rawAesKey = await crypto.subtle.decrypt(
|
|
178
|
+
{ name: "RSA-OAEP" },
|
|
179
|
+
privateKey,
|
|
180
|
+
wrappedKey
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
const aesKey = await crypto.subtle.importKey(
|
|
184
|
+
"raw",
|
|
185
|
+
rawAesKey,
|
|
186
|
+
{ name: "AES-GCM" },
|
|
187
|
+
false,
|
|
188
|
+
["decrypt"]
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const decrypted = await crypto.subtle.decrypt(
|
|
192
|
+
{ name: "AES-GCM", iv, tagLength: TAG_LENGTH * 8 },
|
|
193
|
+
aesKey,
|
|
194
|
+
ciphertext
|
|
195
|
+
);
|
|
196
|
+
const text = new TextDecoder().decode(decrypted);
|
|
197
|
+
if (parseJson) return JSON.parse(text) as T;
|
|
198
|
+
return text as T;
|
|
199
|
+
} catch (err: any) {
|
|
200
|
+
throw new Error(`Decryption failed: ${err?.message || 'invalid ciphertext or tampered data'}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async exportPublicKey(): Promise<JsonWebKey> {
|
|
205
|
+
return await crypto.subtle.exportKey("jwk", (await this.#getKeyPair()).publicKey);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async exportPrivateKey(): Promise<JsonWebKey> {
|
|
209
|
+
return await crypto.subtle.exportKey("jwk", (await this.#getKeyPair()).privateKey);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async importPublicKey(jwk: JsonWebKey): Promise<CryptoKey> {
|
|
213
|
+
return await crypto.subtle.importKey(
|
|
214
|
+
"jwk",
|
|
215
|
+
jwk,
|
|
216
|
+
{ name: "RSA-OAEP", hash: "SHA-256" },
|
|
217
|
+
false,
|
|
218
|
+
["encrypt"]
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const sym = (options: { secret: string }) => new CryptSym(options);
|
|
224
|
+
const asym = (options?: { privateKey?: JsonWebKey }) => new CryptAsym(options);
|
|
225
|
+
|
|
226
|
+
export { sym as useSymCrypt, asym as useAsymCrypt };
|