@gjsify/webcrypto 0.1.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 +28 -0
- package/globals.mjs +6 -0
- package/lib/esm/crypto-key.js +21 -0
- package/lib/esm/index.js +49 -0
- package/lib/esm/subtle.js +607 -0
- package/lib/esm/util.js +133 -0
- package/lib/types/crypto-key.d.ts +182 -0
- package/lib/types/index.d.ts +17 -0
- package/lib/types/subtle.d.ts +22 -0
- package/lib/types/util.d.ts +27 -0
- package/package.json +43 -0
- package/src/crypto-key.ts +226 -0
- package/src/index.spec.ts +1881 -0
- package/src/index.ts +78 -0
- package/src/subtle.ts +755 -0
- package/src/test.mts +8 -0
- package/src/util.ts +152 -0
- package/tsconfig.json +32 -0
- package/tsconfig.tsbuildinfo +1 -0
package/lib/esm/util.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import "@gjsify/dom-exception";
|
|
2
|
+
function normalizeAlgorithm(algorithm) {
|
|
3
|
+
if (typeof algorithm === "string") {
|
|
4
|
+
return { name: algorithm };
|
|
5
|
+
}
|
|
6
|
+
if (!algorithm || typeof algorithm.name !== "string") {
|
|
7
|
+
throw new TypeError("Algorithm must have a name property");
|
|
8
|
+
}
|
|
9
|
+
return algorithm;
|
|
10
|
+
}
|
|
11
|
+
const HASH_NAMES = {
|
|
12
|
+
"SHA-1": "sha1",
|
|
13
|
+
"SHA-256": "sha256",
|
|
14
|
+
"SHA-384": "sha384",
|
|
15
|
+
"SHA-512": "sha512"
|
|
16
|
+
};
|
|
17
|
+
function toNodeHashName(name) {
|
|
18
|
+
const resolved = HASH_NAMES[name.toUpperCase()] || HASH_NAMES[name];
|
|
19
|
+
if (!resolved) {
|
|
20
|
+
throw new DOMException(`Unrecognized hash name: ${name}`, "NotSupportedError");
|
|
21
|
+
}
|
|
22
|
+
return resolved;
|
|
23
|
+
}
|
|
24
|
+
function toWebCryptoHashName(name) {
|
|
25
|
+
const upper = name.toUpperCase().replace(/[^A-Z0-9]/g, "");
|
|
26
|
+
for (const [web, node] of Object.entries(HASH_NAMES)) {
|
|
27
|
+
if (node === name || upper === web.replace("-", "")) return web;
|
|
28
|
+
}
|
|
29
|
+
throw new DOMException(`Unrecognized hash name: ${name}`, "NotSupportedError");
|
|
30
|
+
}
|
|
31
|
+
const CURVE_NAMES = {
|
|
32
|
+
"P-256": "prime256v1",
|
|
33
|
+
"P-384": "secp384r1",
|
|
34
|
+
"P-521": "secp521r1"
|
|
35
|
+
};
|
|
36
|
+
function toNodeCurveName(name) {
|
|
37
|
+
const resolved = CURVE_NAMES[name];
|
|
38
|
+
if (!resolved) {
|
|
39
|
+
throw new DOMException(`Unrecognized curve name: ${name}`, "NotSupportedError");
|
|
40
|
+
}
|
|
41
|
+
return resolved;
|
|
42
|
+
}
|
|
43
|
+
function hashSize(hash) {
|
|
44
|
+
switch (toNodeHashName(hash)) {
|
|
45
|
+
case "sha1":
|
|
46
|
+
return 20;
|
|
47
|
+
case "sha256":
|
|
48
|
+
return 32;
|
|
49
|
+
case "sha384":
|
|
50
|
+
return 48;
|
|
51
|
+
case "sha512":
|
|
52
|
+
return 64;
|
|
53
|
+
default:
|
|
54
|
+
throw new DOMException(`Unsupported hash: ${hash}`, "NotSupportedError");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function validateUsages(usages, allowed) {
|
|
58
|
+
for (const usage of usages) {
|
|
59
|
+
if (!allowed.includes(usage)) {
|
|
60
|
+
throw new DOMException(`Invalid key usage: ${usage}`, "SyntaxError");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (usages.length === 0) {
|
|
64
|
+
throw new DOMException("Key usages must not be empty", "SyntaxError");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function checkUsage(key, required) {
|
|
68
|
+
if (!key.usages.includes(required)) {
|
|
69
|
+
throw new DOMException(
|
|
70
|
+
`Key does not support the '${required}' usage`,
|
|
71
|
+
"InvalidAccessError"
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const B64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
76
|
+
const B64_LOOKUP = new Uint8Array(128);
|
|
77
|
+
for (let i = 0; i < B64_CHARS.length; i++) B64_LOOKUP[B64_CHARS.charCodeAt(i)] = i;
|
|
78
|
+
function bytesToBase64(bytes) {
|
|
79
|
+
let result = "";
|
|
80
|
+
const len = bytes.length;
|
|
81
|
+
for (let i = 0; i < len; i += 3) {
|
|
82
|
+
const b0 = bytes[i];
|
|
83
|
+
const b1 = i + 1 < len ? bytes[i + 1] : 0;
|
|
84
|
+
const b2 = i + 2 < len ? bytes[i + 2] : 0;
|
|
85
|
+
result += B64_CHARS[b0 >> 2 & 63];
|
|
86
|
+
result += B64_CHARS[(b0 << 4 | b1 >> 4) & 63];
|
|
87
|
+
result += i + 1 < len ? B64_CHARS[(b1 << 2 | b2 >> 6) & 63] : "=";
|
|
88
|
+
result += i + 2 < len ? B64_CHARS[b2 & 63] : "=";
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
function base64ToBytes(str) {
|
|
93
|
+
let s = str;
|
|
94
|
+
while (s.endsWith("=")) s = s.slice(0, -1);
|
|
95
|
+
const out = [];
|
|
96
|
+
let bits = 0;
|
|
97
|
+
let val = 0;
|
|
98
|
+
for (let i = 0; i < s.length; i++) {
|
|
99
|
+
val = val << 6 | B64_LOOKUP[s.charCodeAt(i)];
|
|
100
|
+
bits += 6;
|
|
101
|
+
if (bits >= 8) {
|
|
102
|
+
bits -= 8;
|
|
103
|
+
out.push(val >> bits & 255);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return new Uint8Array(out);
|
|
107
|
+
}
|
|
108
|
+
function base64urlEncode(data) {
|
|
109
|
+
return bytesToBase64(data).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
110
|
+
}
|
|
111
|
+
function base64urlDecode(str) {
|
|
112
|
+
let s = str.replace(/-/g, "+").replace(/_/g, "/");
|
|
113
|
+
while (s.length % 4) s += "=";
|
|
114
|
+
return base64ToBytes(s);
|
|
115
|
+
}
|
|
116
|
+
function toUint8Array(data) {
|
|
117
|
+
if (data instanceof Uint8Array) return data;
|
|
118
|
+
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
|
119
|
+
if (ArrayBuffer.isView(data)) return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
120
|
+
throw new TypeError("Expected BufferSource");
|
|
121
|
+
}
|
|
122
|
+
export {
|
|
123
|
+
base64urlDecode,
|
|
124
|
+
base64urlEncode,
|
|
125
|
+
checkUsage,
|
|
126
|
+
hashSize,
|
|
127
|
+
normalizeAlgorithm,
|
|
128
|
+
toNodeCurveName,
|
|
129
|
+
toNodeHashName,
|
|
130
|
+
toUint8Array,
|
|
131
|
+
toWebCryptoHashName,
|
|
132
|
+
validateUsages
|
|
133
|
+
};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
export type KeyType = 'public' | 'private' | 'secret';
|
|
2
|
+
export type KeyUsage = 'encrypt' | 'decrypt' | 'sign' | 'verify' | 'deriveKey' | 'deriveBits' | 'wrapKey' | 'unwrapKey';
|
|
3
|
+
export interface KeyAlgorithm {
|
|
4
|
+
name: string;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
export interface AesKeyAlgorithm extends KeyAlgorithm {
|
|
8
|
+
length: number;
|
|
9
|
+
}
|
|
10
|
+
export interface HmacKeyAlgorithm extends KeyAlgorithm {
|
|
11
|
+
hash: {
|
|
12
|
+
name: string;
|
|
13
|
+
};
|
|
14
|
+
length: number;
|
|
15
|
+
}
|
|
16
|
+
export interface EcKeyAlgorithm extends KeyAlgorithm {
|
|
17
|
+
namedCurve: string;
|
|
18
|
+
}
|
|
19
|
+
export interface RsaHashedKeyAlgorithm extends KeyAlgorithm {
|
|
20
|
+
hash: {
|
|
21
|
+
name: string;
|
|
22
|
+
};
|
|
23
|
+
modulusLength: number;
|
|
24
|
+
publicExponent: Uint8Array;
|
|
25
|
+
}
|
|
26
|
+
export interface AesKeyGenParams {
|
|
27
|
+
name: string;
|
|
28
|
+
length: number;
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
}
|
|
31
|
+
export interface HmacKeyGenParams {
|
|
32
|
+
name: string;
|
|
33
|
+
hash: string | {
|
|
34
|
+
name: string;
|
|
35
|
+
};
|
|
36
|
+
length?: number;
|
|
37
|
+
[key: string]: unknown;
|
|
38
|
+
}
|
|
39
|
+
export interface EcKeyGenParams {
|
|
40
|
+
name: string;
|
|
41
|
+
namedCurve: string;
|
|
42
|
+
[key: string]: unknown;
|
|
43
|
+
}
|
|
44
|
+
export interface HmacImportParams {
|
|
45
|
+
name: string;
|
|
46
|
+
hash: string | {
|
|
47
|
+
name: string;
|
|
48
|
+
};
|
|
49
|
+
length?: number;
|
|
50
|
+
[key: string]: unknown;
|
|
51
|
+
}
|
|
52
|
+
export interface EcKeyImportParams {
|
|
53
|
+
name: string;
|
|
54
|
+
namedCurve: string;
|
|
55
|
+
[key: string]: unknown;
|
|
56
|
+
}
|
|
57
|
+
export interface AesCbcParams {
|
|
58
|
+
name: string;
|
|
59
|
+
iv: BufferSource;
|
|
60
|
+
[key: string]: unknown;
|
|
61
|
+
}
|
|
62
|
+
export interface AesCtrParams {
|
|
63
|
+
name: string;
|
|
64
|
+
counter: BufferSource;
|
|
65
|
+
length: number;
|
|
66
|
+
[key: string]: unknown;
|
|
67
|
+
}
|
|
68
|
+
export interface AesGcmParams {
|
|
69
|
+
name: string;
|
|
70
|
+
iv: BufferSource;
|
|
71
|
+
additionalData?: BufferSource;
|
|
72
|
+
tagLength?: number;
|
|
73
|
+
[key: string]: unknown;
|
|
74
|
+
}
|
|
75
|
+
export interface RsaOaepParams {
|
|
76
|
+
name: string;
|
|
77
|
+
label?: BufferSource;
|
|
78
|
+
[key: string]: unknown;
|
|
79
|
+
}
|
|
80
|
+
export interface EcdsaParams {
|
|
81
|
+
name: string;
|
|
82
|
+
hash: string | {
|
|
83
|
+
name: string;
|
|
84
|
+
};
|
|
85
|
+
[key: string]: unknown;
|
|
86
|
+
}
|
|
87
|
+
export interface RsaPssParams {
|
|
88
|
+
name: string;
|
|
89
|
+
saltLength: number;
|
|
90
|
+
[key: string]: unknown;
|
|
91
|
+
}
|
|
92
|
+
export interface Pbkdf2Params {
|
|
93
|
+
name: string;
|
|
94
|
+
hash: string | {
|
|
95
|
+
name: string;
|
|
96
|
+
};
|
|
97
|
+
salt: BufferSource;
|
|
98
|
+
iterations: number;
|
|
99
|
+
[key: string]: unknown;
|
|
100
|
+
}
|
|
101
|
+
export interface HkdfParams {
|
|
102
|
+
name: string;
|
|
103
|
+
hash: string | {
|
|
104
|
+
name: string;
|
|
105
|
+
};
|
|
106
|
+
salt: BufferSource;
|
|
107
|
+
info: BufferSource;
|
|
108
|
+
[key: string]: unknown;
|
|
109
|
+
}
|
|
110
|
+
export interface EcdhKeyDeriveParams {
|
|
111
|
+
name: string;
|
|
112
|
+
public: CryptoKey;
|
|
113
|
+
[key: string]: unknown;
|
|
114
|
+
}
|
|
115
|
+
/** Union of all supported algorithm parameter types */
|
|
116
|
+
export type AlgorithmIdentifier = string | {
|
|
117
|
+
name: string;
|
|
118
|
+
[key: string]: unknown;
|
|
119
|
+
};
|
|
120
|
+
/** Handle for EC private keys: contains both public and private bytes */
|
|
121
|
+
export interface EcKeyPairHandle {
|
|
122
|
+
pub: Uint8Array;
|
|
123
|
+
priv: Uint8Array;
|
|
124
|
+
}
|
|
125
|
+
/** Handle for RSA keys: PEM-encoded key */
|
|
126
|
+
export interface RsaPemHandle {
|
|
127
|
+
pem: string;
|
|
128
|
+
}
|
|
129
|
+
export interface HashLike {
|
|
130
|
+
update(data: Uint8Array): void;
|
|
131
|
+
digest(): Uint8Array;
|
|
132
|
+
}
|
|
133
|
+
export interface HmacLike {
|
|
134
|
+
update(data: Uint8Array): void;
|
|
135
|
+
digest(): Uint8Array;
|
|
136
|
+
}
|
|
137
|
+
export interface CipherLike {
|
|
138
|
+
update(data: Uint8Array): Uint8Array;
|
|
139
|
+
final(): Uint8Array;
|
|
140
|
+
setAAD?(aad: Uint8Array): void;
|
|
141
|
+
getAuthTag?(): Uint8Array;
|
|
142
|
+
}
|
|
143
|
+
export interface DecipherLike {
|
|
144
|
+
update(data: Uint8Array): Uint8Array;
|
|
145
|
+
final(): Uint8Array;
|
|
146
|
+
setAuthTag?(tag: Uint8Array): void;
|
|
147
|
+
setAAD?(aad: Uint8Array): void;
|
|
148
|
+
}
|
|
149
|
+
export interface SignerLike {
|
|
150
|
+
update(data: Uint8Array): void;
|
|
151
|
+
sign(key: string): Uint8Array;
|
|
152
|
+
}
|
|
153
|
+
export interface VerifierLike {
|
|
154
|
+
update(data: Uint8Array): void;
|
|
155
|
+
verify(key: string, sig: Uint8Array): boolean;
|
|
156
|
+
}
|
|
157
|
+
export interface EcdhLike {
|
|
158
|
+
generateKeys(): void;
|
|
159
|
+
getPublicKey(): Uint8Array;
|
|
160
|
+
getPrivateKey(): Uint8Array;
|
|
161
|
+
setPrivateKey(key: Uint8Array): void;
|
|
162
|
+
computeSecret(key: Uint8Array): Uint8Array;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* CryptoKey represents a cryptographic key obtained from SubtleCrypto methods.
|
|
166
|
+
* It stores algorithm metadata, key type, extractability, and usage flags
|
|
167
|
+
* alongside the raw key material (internal handle).
|
|
168
|
+
*/
|
|
169
|
+
export declare class CryptoKey {
|
|
170
|
+
readonly type: KeyType;
|
|
171
|
+
readonly extractable: boolean;
|
|
172
|
+
readonly algorithm: KeyAlgorithm;
|
|
173
|
+
readonly usages: KeyUsage[];
|
|
174
|
+
/** @internal Raw key material — not visible to user code */
|
|
175
|
+
_handle: unknown;
|
|
176
|
+
constructor(type: KeyType, extractable: boolean, algorithm: KeyAlgorithm, usages: KeyUsage[], handle: unknown);
|
|
177
|
+
get [Symbol.toStringTag](): string;
|
|
178
|
+
}
|
|
179
|
+
export interface CryptoKeyPair {
|
|
180
|
+
publicKey: CryptoKey;
|
|
181
|
+
privateKey: CryptoKey;
|
|
182
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SubtleCrypto } from './subtle.js';
|
|
2
|
+
import { CryptoKey } from './crypto-key.js';
|
|
3
|
+
export type { CryptoKeyPair, KeyUsage, KeyAlgorithm, KeyType } from './crypto-key.js';
|
|
4
|
+
/**
|
|
5
|
+
* Crypto object per the W3C WebCrypto API.
|
|
6
|
+
* Provides getRandomValues(), randomUUID(), and subtle (SubtleCrypto).
|
|
7
|
+
*/
|
|
8
|
+
declare class CryptoPolyfill {
|
|
9
|
+
readonly subtle: SubtleCrypto;
|
|
10
|
+
getRandomValues<T extends ArrayBufferView>(array: T): T;
|
|
11
|
+
randomUUID(): `${string}-${string}-${string}-${string}-${string}`;
|
|
12
|
+
}
|
|
13
|
+
declare const cryptoInstance: Crypto | CryptoPolyfill;
|
|
14
|
+
declare const subtleInstance: SubtleCrypto | globalThis.SubtleCrypto;
|
|
15
|
+
export { CryptoKey, SubtleCrypto, CryptoPolyfill as Crypto };
|
|
16
|
+
export { subtleInstance as subtle, cryptoInstance as crypto };
|
|
17
|
+
export default cryptoInstance;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CryptoKey, type CryptoKeyPair, type KeyUsage, type AlgorithmIdentifier } from './crypto-key.js';
|
|
2
|
+
/**
|
|
3
|
+
* SubtleCrypto provides cryptographic primitives per the W3C WebCrypto API.
|
|
4
|
+
*/
|
|
5
|
+
export declare class SubtleCrypto {
|
|
6
|
+
digest(algorithm: string | {
|
|
7
|
+
name: string;
|
|
8
|
+
}, data: BufferSource): Promise<ArrayBuffer>;
|
|
9
|
+
generateKey(algorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey | CryptoKeyPair>;
|
|
10
|
+
importKey(format: 'raw' | 'jwk' | 'pkcs8' | 'spki', keyData: BufferSource | JsonWebKey, algorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey>;
|
|
11
|
+
exportKey(format: 'raw' | 'jwk' | 'pkcs8' | 'spki', key: CryptoKey): Promise<ArrayBuffer | JsonWebKey>;
|
|
12
|
+
encrypt(algorithm: AlgorithmIdentifier, key: CryptoKey, data: BufferSource): Promise<ArrayBuffer>;
|
|
13
|
+
decrypt(algorithm: AlgorithmIdentifier, key: CryptoKey, data: BufferSource): Promise<ArrayBuffer>;
|
|
14
|
+
sign(algorithm: AlgorithmIdentifier, key: CryptoKey, data: BufferSource): Promise<ArrayBuffer>;
|
|
15
|
+
verify(algorithm: AlgorithmIdentifier, key: CryptoKey, signature: BufferSource, data: BufferSource): Promise<boolean>;
|
|
16
|
+
/** Internal deriveBits without usage check (used by deriveKey) */
|
|
17
|
+
private _deriveBitsInternal;
|
|
18
|
+
deriveBits(algorithm: AlgorithmIdentifier, baseKey: CryptoKey, length: number): Promise<ArrayBuffer>;
|
|
19
|
+
deriveKey(algorithm: AlgorithmIdentifier, baseKey: CryptoKey, derivedKeyAlgorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey>;
|
|
20
|
+
wrapKey(_format: 'raw' | 'jwk' | 'pkcs8' | 'spki', _key: CryptoKey, _wrappingKey: CryptoKey, _wrapAlgorithm: AlgorithmIdentifier): Promise<ArrayBuffer>;
|
|
21
|
+
unwrapKey(_format: 'raw' | 'jwk' | 'pkcs8' | 'spki', _wrappedKey: BufferSource, _unwrappingKey: CryptoKey, _unwrapAlgorithm: AlgorithmIdentifier, _unwrappedKeyAlgorithm: AlgorithmIdentifier, _extractable: boolean, _keyUsages: KeyUsage[]): Promise<CryptoKey>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { KeyUsage } from './crypto-key.js';
|
|
2
|
+
import '@gjsify/dom-exception';
|
|
3
|
+
/** Normalize algorithm identifier to {name: string, ...} form */
|
|
4
|
+
export declare function normalizeAlgorithm(algorithm: string | {
|
|
5
|
+
name: string;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
}): {
|
|
8
|
+
name: string;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
};
|
|
11
|
+
export declare function toNodeHashName(name: string): string;
|
|
12
|
+
export declare function toWebCryptoHashName(name: string): string;
|
|
13
|
+
export declare function toNodeCurveName(name: string): string;
|
|
14
|
+
/** Get hash output size in bytes */
|
|
15
|
+
export declare function hashSize(hash: string): number;
|
|
16
|
+
/** Validate key usages */
|
|
17
|
+
export declare function validateUsages(usages: KeyUsage[], allowed: KeyUsage[]): void;
|
|
18
|
+
/** Check key has required usage */
|
|
19
|
+
export declare function checkUsage(key: {
|
|
20
|
+
usages: KeyUsage[];
|
|
21
|
+
}, required: KeyUsage): void;
|
|
22
|
+
/** Base64url encode */
|
|
23
|
+
export declare function base64urlEncode(data: Uint8Array): string;
|
|
24
|
+
/** Base64url decode */
|
|
25
|
+
export declare function base64urlDecode(str: string): Uint8Array;
|
|
26
|
+
/** Convert ArrayBuffer or view to Uint8Array */
|
|
27
|
+
export declare function toUint8Array(data: BufferSource): Uint8Array;
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gjsify/webcrypto",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "W3C WebCrypto API (SubtleCrypto) for GJS using @gjsify/crypto primitives",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"module": "lib/esm/index.js",
|
|
7
|
+
"types": "lib/types/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/types/index.d.ts",
|
|
11
|
+
"default": "./lib/esm/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./globals": "./globals.mjs"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"clear": "rm -rf lib tsconfig.tsbuildinfo tsconfig.types.tsbuildinfo test.gjs.mjs test.node.mjs || exit 0",
|
|
17
|
+
"check": "tsc --noEmit",
|
|
18
|
+
"build": "yarn build:gjsify && yarn build:types",
|
|
19
|
+
"build:gjsify": "gjsify build --library 'src/**/*.{ts,js}' --exclude 'src/**/*.spec.{mts,ts}' 'src/test.{mts,ts}'",
|
|
20
|
+
"build:types": "tsc",
|
|
21
|
+
"build:test": "yarn build:test:gjs && yarn build:test:node",
|
|
22
|
+
"build:test:gjs": "gjsify build src/test.mts --app gjs --outfile test.gjs.mjs",
|
|
23
|
+
"build:test:node": "gjsify build src/test.mts --app node --outfile test.node.mjs",
|
|
24
|
+
"test": "yarn build:gjsify && yarn build:test && yarn test:node",
|
|
25
|
+
"test:gjs": "gjs -m test.gjs.mjs",
|
|
26
|
+
"test:node": "node test.node.mjs"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"gjs",
|
|
30
|
+
"webcrypto",
|
|
31
|
+
"subtle",
|
|
32
|
+
"crypto"
|
|
33
|
+
],
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@gjsify/dom-exception": "^0.1.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@gjsify/cli": "^0.1.0",
|
|
39
|
+
"@gjsify/unit": "^0.1.0",
|
|
40
|
+
"@types/node": "^25.5.0",
|
|
41
|
+
"typescript": "^6.0.2"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// W3C CryptoKey for GJS
|
|
2
|
+
// Reference: refs/deno/ext/crypto/00_crypto.js
|
|
3
|
+
// Copyright (c) 2018-2026 the Deno authors. MIT license.
|
|
4
|
+
// Reimplemented for GJS using @gjsify/crypto primitives.
|
|
5
|
+
|
|
6
|
+
export type KeyType = 'public' | 'private' | 'secret';
|
|
7
|
+
export type KeyUsage = 'encrypt' | 'decrypt' | 'sign' | 'verify' | 'deriveKey' | 'deriveBits' | 'wrapKey' | 'unwrapKey';
|
|
8
|
+
|
|
9
|
+
export interface KeyAlgorithm {
|
|
10
|
+
name: string;
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// ---- Specific KeyAlgorithm sub-interfaces ----
|
|
15
|
+
|
|
16
|
+
export interface AesKeyAlgorithm extends KeyAlgorithm {
|
|
17
|
+
length: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface HmacKeyAlgorithm extends KeyAlgorithm {
|
|
21
|
+
hash: { name: string };
|
|
22
|
+
length: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface EcKeyAlgorithm extends KeyAlgorithm {
|
|
26
|
+
namedCurve: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface RsaHashedKeyAlgorithm extends KeyAlgorithm {
|
|
30
|
+
hash: { name: string };
|
|
31
|
+
modulusLength: number;
|
|
32
|
+
publicExponent: Uint8Array;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ---- Algorithm parameter interfaces (W3C WebCrypto) ----
|
|
36
|
+
|
|
37
|
+
export interface AesKeyGenParams {
|
|
38
|
+
name: string;
|
|
39
|
+
length: number;
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface HmacKeyGenParams {
|
|
44
|
+
name: string;
|
|
45
|
+
hash: string | { name: string };
|
|
46
|
+
length?: number;
|
|
47
|
+
[key: string]: unknown;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface EcKeyGenParams {
|
|
51
|
+
name: string;
|
|
52
|
+
namedCurve: string;
|
|
53
|
+
[key: string]: unknown;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface HmacImportParams {
|
|
57
|
+
name: string;
|
|
58
|
+
hash: string | { name: string };
|
|
59
|
+
length?: number;
|
|
60
|
+
[key: string]: unknown;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface EcKeyImportParams {
|
|
64
|
+
name: string;
|
|
65
|
+
namedCurve: string;
|
|
66
|
+
[key: string]: unknown;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface AesCbcParams {
|
|
70
|
+
name: string;
|
|
71
|
+
iv: BufferSource;
|
|
72
|
+
[key: string]: unknown;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface AesCtrParams {
|
|
76
|
+
name: string;
|
|
77
|
+
counter: BufferSource;
|
|
78
|
+
length: number;
|
|
79
|
+
[key: string]: unknown;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface AesGcmParams {
|
|
83
|
+
name: string;
|
|
84
|
+
iv: BufferSource;
|
|
85
|
+
additionalData?: BufferSource;
|
|
86
|
+
tagLength?: number;
|
|
87
|
+
[key: string]: unknown;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface RsaOaepParams {
|
|
91
|
+
name: string;
|
|
92
|
+
label?: BufferSource;
|
|
93
|
+
[key: string]: unknown;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface EcdsaParams {
|
|
97
|
+
name: string;
|
|
98
|
+
hash: string | { name: string };
|
|
99
|
+
[key: string]: unknown;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface RsaPssParams {
|
|
103
|
+
name: string;
|
|
104
|
+
saltLength: number;
|
|
105
|
+
[key: string]: unknown;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface Pbkdf2Params {
|
|
109
|
+
name: string;
|
|
110
|
+
hash: string | { name: string };
|
|
111
|
+
salt: BufferSource;
|
|
112
|
+
iterations: number;
|
|
113
|
+
[key: string]: unknown;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface HkdfParams {
|
|
117
|
+
name: string;
|
|
118
|
+
hash: string | { name: string };
|
|
119
|
+
salt: BufferSource;
|
|
120
|
+
info: BufferSource;
|
|
121
|
+
[key: string]: unknown;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface EcdhKeyDeriveParams {
|
|
125
|
+
name: string;
|
|
126
|
+
public: CryptoKey;
|
|
127
|
+
[key: string]: unknown;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Union of all supported algorithm parameter types */
|
|
131
|
+
export type AlgorithmIdentifier = string | { name: string; [key: string]: unknown };
|
|
132
|
+
|
|
133
|
+
// ---- Internal handle types (not part of public API) ----
|
|
134
|
+
|
|
135
|
+
/** Handle for EC private keys: contains both public and private bytes */
|
|
136
|
+
export interface EcKeyPairHandle {
|
|
137
|
+
pub: Uint8Array;
|
|
138
|
+
priv: Uint8Array;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Handle for RSA keys: PEM-encoded key */
|
|
142
|
+
export interface RsaPemHandle {
|
|
143
|
+
pem: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ---- Lazy-loaded Node.js crypto function types ----
|
|
147
|
+
|
|
148
|
+
export interface HashLike {
|
|
149
|
+
update(data: Uint8Array): void;
|
|
150
|
+
digest(): Uint8Array;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface HmacLike {
|
|
154
|
+
update(data: Uint8Array): void;
|
|
155
|
+
digest(): Uint8Array;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface CipherLike {
|
|
159
|
+
update(data: Uint8Array): Uint8Array;
|
|
160
|
+
final(): Uint8Array;
|
|
161
|
+
setAAD?(aad: Uint8Array): void;
|
|
162
|
+
getAuthTag?(): Uint8Array;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface DecipherLike {
|
|
166
|
+
update(data: Uint8Array): Uint8Array;
|
|
167
|
+
final(): Uint8Array;
|
|
168
|
+
setAuthTag?(tag: Uint8Array): void;
|
|
169
|
+
setAAD?(aad: Uint8Array): void;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface SignerLike {
|
|
173
|
+
update(data: Uint8Array): void;
|
|
174
|
+
sign(key: string): Uint8Array;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export interface VerifierLike {
|
|
178
|
+
update(data: Uint8Array): void;
|
|
179
|
+
verify(key: string, sig: Uint8Array): boolean;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export interface EcdhLike {
|
|
183
|
+
generateKeys(): void;
|
|
184
|
+
getPublicKey(): Uint8Array;
|
|
185
|
+
getPrivateKey(): Uint8Array;
|
|
186
|
+
setPrivateKey(key: Uint8Array): void;
|
|
187
|
+
computeSecret(key: Uint8Array): Uint8Array;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* CryptoKey represents a cryptographic key obtained from SubtleCrypto methods.
|
|
192
|
+
* It stores algorithm metadata, key type, extractability, and usage flags
|
|
193
|
+
* alongside the raw key material (internal handle).
|
|
194
|
+
*/
|
|
195
|
+
export class CryptoKey {
|
|
196
|
+
readonly type: KeyType;
|
|
197
|
+
readonly extractable: boolean;
|
|
198
|
+
readonly algorithm: KeyAlgorithm;
|
|
199
|
+
readonly usages: KeyUsage[];
|
|
200
|
+
|
|
201
|
+
/** @internal Raw key material — not visible to user code */
|
|
202
|
+
_handle: unknown;
|
|
203
|
+
|
|
204
|
+
constructor(
|
|
205
|
+
type: KeyType,
|
|
206
|
+
extractable: boolean,
|
|
207
|
+
algorithm: KeyAlgorithm,
|
|
208
|
+
usages: KeyUsage[],
|
|
209
|
+
handle: unknown,
|
|
210
|
+
) {
|
|
211
|
+
this.type = type;
|
|
212
|
+
this.extractable = extractable;
|
|
213
|
+
this.algorithm = Object.freeze({ ...algorithm });
|
|
214
|
+
this.usages = Object.freeze([...usages]) as unknown as KeyUsage[];
|
|
215
|
+
this._handle = handle;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
get [Symbol.toStringTag](): string {
|
|
219
|
+
return 'CryptoKey';
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export interface CryptoKeyPair {
|
|
224
|
+
publicKey: CryptoKey;
|
|
225
|
+
privateKey: CryptoKey;
|
|
226
|
+
}
|