@batalabs/virlow-crypto 3.11.4 → 3.11.6
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/dist/blob.js +2 -2
- package/dist/blob.js.map +1 -1
- package/dist/cjs/base64.d.ts +3 -0
- package/dist/cjs/base64.js +27 -0
- package/dist/cjs/blob.d.ts +6 -0
- package/dist/cjs/blob.js +34 -0
- package/dist/cjs/constants.d.ts +12 -0
- package/dist/cjs/constants.js +15 -0
- package/dist/cjs/index.d.ts +7 -0
- package/dist/cjs/index.js +27 -0
- package/dist/cjs/keys.d.ts +12 -0
- package/dist/cjs/keys.js +39 -0
- package/dist/cjs/notes.d.ts +13 -0
- package/dist/cjs/notes.js +51 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/verifier.d.ts +23 -0
- package/dist/cjs/verifier.js +52 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/keys.js +2 -2
- package/dist/keys.js.map +1 -1
- package/dist/notes.js +2 -2
- package/dist/notes.js.map +1 -1
- package/dist/verifier.js +2 -2
- package/dist/verifier.js.map +1 -1
- package/package.json +11 -5
package/dist/blob.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { base64ToArrayBuffer, base64ToBytes, bytesToBase64 } from './base64';
|
|
2
|
-
import { ENCRYPTION_CONFIG } from './constants';
|
|
1
|
+
import { base64ToArrayBuffer, base64ToBytes, bytesToBase64 } from './base64.js';
|
|
2
|
+
import { ENCRYPTION_CONFIG } from './constants.js';
|
|
3
3
|
/** Encrypt bytes into a self-describing "v2:<ivB64>:<ciphertextB64>" blob. */
|
|
4
4
|
export async function encryptBytesBlob(key, bytes) {
|
|
5
5
|
const iv = crypto.getRandomValues(new Uint8Array(ENCRYPTION_CONFIG.IV_LENGTH));
|
package/dist/blob.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blob.js","sourceRoot":"","sources":["../src/blob.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"blob.js","sourceRoot":"","sources":["../src/blob.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAc,EACd,KAAiB;IAEjB,MAAM,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC;IAC/E,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAC5C,EAAE,IAAI,EAAE,iBAAiB,CAAC,SAAS,EAAE,EAAE,EAAE,EACzC,GAAG,EACH,KAAqB,CACtB,CAAC;IACF,OAAO,KAAK,GAAG,aAAa,CAAC,EAAE,CAAC,GAAG,GAAG,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;AACrE,CAAC;AAED,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAc,EACd,IAAY;IAEZ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAC3C,EAAE,IAAI,EAAE,iBAAiB,CAAC,SAAS,EAAE,EAAE,EAAE,EAAkB,EAAE,EAC7D,GAAG,EACH,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CACzC,CAAC;IACF,OAAO,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAc,EACd,SAAiB;IAEjB,OAAO,gBAAgB,CAAC,GAAG,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAc,EACd,IAAY;IAEZ,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bytesToBase64 = bytesToBase64;
|
|
4
|
+
exports.base64ToBytes = base64ToBytes;
|
|
5
|
+
exports.base64ToArrayBuffer = base64ToArrayBuffer;
|
|
6
|
+
const CHUNK_SIZE = 0x8000;
|
|
7
|
+
function bytesToBase64(input) {
|
|
8
|
+
const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
9
|
+
const chunks = [];
|
|
10
|
+
for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {
|
|
11
|
+
const chunk = bytes.subarray(i, Math.min(i + CHUNK_SIZE, bytes.length));
|
|
12
|
+
chunks.push(String.fromCharCode.apply(null, Array.from(chunk)));
|
|
13
|
+
}
|
|
14
|
+
return btoa(chunks.join(''));
|
|
15
|
+
}
|
|
16
|
+
function base64ToBytes(base64) {
|
|
17
|
+
const binary = atob(base64);
|
|
18
|
+
const bytes = new Uint8Array(binary.length);
|
|
19
|
+
for (let i = 0; i < binary.length; i++) {
|
|
20
|
+
bytes[i] = binary.charCodeAt(i);
|
|
21
|
+
}
|
|
22
|
+
return bytes;
|
|
23
|
+
}
|
|
24
|
+
function base64ToArrayBuffer(base64) {
|
|
25
|
+
const bytes = base64ToBytes(base64);
|
|
26
|
+
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
27
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Encrypt bytes into a self-describing "v2:<ivB64>:<ciphertextB64>" blob. */
|
|
2
|
+
export declare function encryptBytesBlob(key: CryptoKey, bytes: Uint8Array): Promise<string>;
|
|
3
|
+
/** Decrypt a "v2:<ivB64>:<ciphertextB64>" blob back to bytes. */
|
|
4
|
+
export declare function decryptBytesBlob(key: CryptoKey, blob: string): Promise<Uint8Array>;
|
|
5
|
+
export declare function encryptStringBlob(key: CryptoKey, plaintext: string): Promise<string>;
|
|
6
|
+
export declare function decryptStringBlob(key: CryptoKey, blob: string): Promise<string>;
|
package/dist/cjs/blob.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.encryptBytesBlob = encryptBytesBlob;
|
|
4
|
+
exports.decryptBytesBlob = decryptBytesBlob;
|
|
5
|
+
exports.encryptStringBlob = encryptStringBlob;
|
|
6
|
+
exports.decryptStringBlob = decryptStringBlob;
|
|
7
|
+
const base64_js_1 = require("./base64.js");
|
|
8
|
+
const constants_js_1 = require("./constants.js");
|
|
9
|
+
/** Encrypt bytes into a self-describing "v2:<ivB64>:<ciphertextB64>" blob. */
|
|
10
|
+
async function encryptBytesBlob(key, bytes) {
|
|
11
|
+
const iv = crypto.getRandomValues(new Uint8Array(constants_js_1.ENCRYPTION_CONFIG.IV_LENGTH));
|
|
12
|
+
const ciphertext = await crypto.subtle.encrypt({ name: constants_js_1.ENCRYPTION_CONFIG.ALGORITHM, iv }, key, bytes);
|
|
13
|
+
return 'v2:' + (0, base64_js_1.bytesToBase64)(iv) + ':' + (0, base64_js_1.bytesToBase64)(ciphertext);
|
|
14
|
+
}
|
|
15
|
+
/** Decrypt a "v2:<ivB64>:<ciphertextB64>" blob back to bytes. */
|
|
16
|
+
async function decryptBytesBlob(key, blob) {
|
|
17
|
+
if (!blob.startsWith('v2:')) {
|
|
18
|
+
throw new Error('Malformed encrypted blob: missing v2 prefix');
|
|
19
|
+
}
|
|
20
|
+
const rest = blob.slice(3);
|
|
21
|
+
const sep = rest.indexOf(':');
|
|
22
|
+
if (sep === -1) {
|
|
23
|
+
throw new Error('Malformed encrypted blob: missing IV separator');
|
|
24
|
+
}
|
|
25
|
+
const iv = (0, base64_js_1.base64ToBytes)(rest.slice(0, sep));
|
|
26
|
+
const decrypted = await crypto.subtle.decrypt({ name: constants_js_1.ENCRYPTION_CONFIG.ALGORITHM, iv: iv }, key, (0, base64_js_1.base64ToArrayBuffer)(rest.slice(sep + 1)));
|
|
27
|
+
return new Uint8Array(decrypted);
|
|
28
|
+
}
|
|
29
|
+
async function encryptStringBlob(key, plaintext) {
|
|
30
|
+
return encryptBytesBlob(key, new TextEncoder().encode(plaintext));
|
|
31
|
+
}
|
|
32
|
+
async function decryptStringBlob(key, blob) {
|
|
33
|
+
return new TextDecoder().decode(await decryptBytesBlob(key, blob));
|
|
34
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const ENCRYPTION_CONFIG: {
|
|
2
|
+
readonly ALGORITHM: "AES-GCM";
|
|
3
|
+
readonly KEY_LENGTH: 256;
|
|
4
|
+
readonly IV_LENGTH: 16;
|
|
5
|
+
readonly ITERATIONS: 250000;
|
|
6
|
+
readonly SALT_LENGTH: 32;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Known constant encrypted under the master key to form the verifier blob.
|
|
10
|
+
* Verification = GCM-decrypt succeeds (auth tag) AND plaintext equals this.
|
|
11
|
+
*/
|
|
12
|
+
export declare const VERIFIER_CONSTANT = "virlow-mp-verifier-v1";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VERIFIER_CONSTANT = exports.ENCRYPTION_CONFIG = void 0;
|
|
4
|
+
exports.ENCRYPTION_CONFIG = {
|
|
5
|
+
ALGORITHM: 'AES-GCM',
|
|
6
|
+
KEY_LENGTH: 256,
|
|
7
|
+
IV_LENGTH: 16,
|
|
8
|
+
ITERATIONS: 250000,
|
|
9
|
+
SALT_LENGTH: 32,
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Known constant encrypted under the master key to form the verifier blob.
|
|
13
|
+
* Verification = GCM-decrypt succeeds (auth tag) AND plaintext equals this.
|
|
14
|
+
*/
|
|
15
|
+
exports.VERIFIER_CONSTANT = 'virlow-mp-verifier-v1';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { base64ToArrayBuffer, base64ToBytes, bytesToBase64 } from './base64.js';
|
|
2
|
+
export { decryptBytesBlob, decryptStringBlob, encryptBytesBlob, encryptStringBlob, } from './blob.js';
|
|
3
|
+
export { ENCRYPTION_CONFIG, VERIFIER_CONSTANT } from './constants.js';
|
|
4
|
+
export { deriveMasterKey, importMasterKey } from './keys.js';
|
|
5
|
+
export { decryptNoteFields, decryptTitleField, encryptNoteFields, type EncryptedNoteFields, } from './notes.js';
|
|
6
|
+
export { canDecryptWithKey, createVerifierBlob, verifyVerifierBlob, type VerifierBlob, } from './verifier.js';
|
|
7
|
+
export declare const PACKAGE_NAME = "@batalabs/virlow-crypto";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PACKAGE_NAME = exports.verifyVerifierBlob = exports.createVerifierBlob = exports.canDecryptWithKey = exports.encryptNoteFields = exports.decryptTitleField = exports.decryptNoteFields = exports.importMasterKey = exports.deriveMasterKey = exports.VERIFIER_CONSTANT = exports.ENCRYPTION_CONFIG = exports.encryptStringBlob = exports.encryptBytesBlob = exports.decryptStringBlob = exports.decryptBytesBlob = exports.bytesToBase64 = exports.base64ToBytes = exports.base64ToArrayBuffer = void 0;
|
|
4
|
+
var base64_js_1 = require("./base64.js");
|
|
5
|
+
Object.defineProperty(exports, "base64ToArrayBuffer", { enumerable: true, get: function () { return base64_js_1.base64ToArrayBuffer; } });
|
|
6
|
+
Object.defineProperty(exports, "base64ToBytes", { enumerable: true, get: function () { return base64_js_1.base64ToBytes; } });
|
|
7
|
+
Object.defineProperty(exports, "bytesToBase64", { enumerable: true, get: function () { return base64_js_1.bytesToBase64; } });
|
|
8
|
+
var blob_js_1 = require("./blob.js");
|
|
9
|
+
Object.defineProperty(exports, "decryptBytesBlob", { enumerable: true, get: function () { return blob_js_1.decryptBytesBlob; } });
|
|
10
|
+
Object.defineProperty(exports, "decryptStringBlob", { enumerable: true, get: function () { return blob_js_1.decryptStringBlob; } });
|
|
11
|
+
Object.defineProperty(exports, "encryptBytesBlob", { enumerable: true, get: function () { return blob_js_1.encryptBytesBlob; } });
|
|
12
|
+
Object.defineProperty(exports, "encryptStringBlob", { enumerable: true, get: function () { return blob_js_1.encryptStringBlob; } });
|
|
13
|
+
var constants_js_1 = require("./constants.js");
|
|
14
|
+
Object.defineProperty(exports, "ENCRYPTION_CONFIG", { enumerable: true, get: function () { return constants_js_1.ENCRYPTION_CONFIG; } });
|
|
15
|
+
Object.defineProperty(exports, "VERIFIER_CONSTANT", { enumerable: true, get: function () { return constants_js_1.VERIFIER_CONSTANT; } });
|
|
16
|
+
var keys_js_1 = require("./keys.js");
|
|
17
|
+
Object.defineProperty(exports, "deriveMasterKey", { enumerable: true, get: function () { return keys_js_1.deriveMasterKey; } });
|
|
18
|
+
Object.defineProperty(exports, "importMasterKey", { enumerable: true, get: function () { return keys_js_1.importMasterKey; } });
|
|
19
|
+
var notes_js_1 = require("./notes.js");
|
|
20
|
+
Object.defineProperty(exports, "decryptNoteFields", { enumerable: true, get: function () { return notes_js_1.decryptNoteFields; } });
|
|
21
|
+
Object.defineProperty(exports, "decryptTitleField", { enumerable: true, get: function () { return notes_js_1.decryptTitleField; } });
|
|
22
|
+
Object.defineProperty(exports, "encryptNoteFields", { enumerable: true, get: function () { return notes_js_1.encryptNoteFields; } });
|
|
23
|
+
var verifier_js_1 = require("./verifier.js");
|
|
24
|
+
Object.defineProperty(exports, "canDecryptWithKey", { enumerable: true, get: function () { return verifier_js_1.canDecryptWithKey; } });
|
|
25
|
+
Object.defineProperty(exports, "createVerifierBlob", { enumerable: true, get: function () { return verifier_js_1.createVerifierBlob; } });
|
|
26
|
+
Object.defineProperty(exports, "verifyVerifierBlob", { enumerable: true, get: function () { return verifier_js_1.verifyVerifierBlob; } });
|
|
27
|
+
exports.PACKAGE_NAME = '@batalabs/virlow-crypto';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive the master key from (password, userId) exactly as the web app does:
|
|
3
|
+
* PBKDF2(password, salt = UTF8(`typelets-salt-${userId}-v1`), 250000, SHA-256)
|
|
4
|
+
* -> AES-GCM 256. Returned key is EXTRACTABLE so callers can obtain keyString
|
|
5
|
+
* for later importMasterKey; commit paths should re-import non-extractably.
|
|
6
|
+
*/
|
|
7
|
+
export declare function deriveMasterKey(masterPassword: string | Uint8Array, userId: string): Promise<{
|
|
8
|
+
key: CryptoKey;
|
|
9
|
+
keyString: string;
|
|
10
|
+
}>;
|
|
11
|
+
/** Import raw AES key bytes as a NON-extractable CryptoKey. */
|
|
12
|
+
export declare function importMasterKey(keyString: string): Promise<CryptoKey>;
|
package/dist/cjs/keys.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deriveMasterKey = deriveMasterKey;
|
|
4
|
+
exports.importMasterKey = importMasterKey;
|
|
5
|
+
const base64_js_1 = require("./base64.js");
|
|
6
|
+
const constants_js_1 = require("./constants.js");
|
|
7
|
+
/**
|
|
8
|
+
* Derive the master key from (password, userId) exactly as the web app does:
|
|
9
|
+
* PBKDF2(password, salt = UTF8(`typelets-salt-${userId}-v1`), 250000, SHA-256)
|
|
10
|
+
* -> AES-GCM 256. Returned key is EXTRACTABLE so callers can obtain keyString
|
|
11
|
+
* for later importMasterKey; commit paths should re-import non-extractably.
|
|
12
|
+
*/
|
|
13
|
+
async function deriveMasterKey(masterPassword, userId) {
|
|
14
|
+
if (!userId) {
|
|
15
|
+
throw new Error('deriveMasterKey requires a userId');
|
|
16
|
+
}
|
|
17
|
+
const encoder = new TextEncoder();
|
|
18
|
+
const passwordBytes = typeof masterPassword === 'string'
|
|
19
|
+
? encoder.encode(masterPassword)
|
|
20
|
+
: masterPassword;
|
|
21
|
+
const userSalt = encoder.encode(`typelets-salt-${userId}-v1`);
|
|
22
|
+
const keyMaterial = await crypto.subtle.importKey('raw', passwordBytes, { name: 'PBKDF2' }, false, ['deriveKey']);
|
|
23
|
+
const key = await crypto.subtle.deriveKey({
|
|
24
|
+
name: 'PBKDF2',
|
|
25
|
+
salt: userSalt,
|
|
26
|
+
iterations: constants_js_1.ENCRYPTION_CONFIG.ITERATIONS,
|
|
27
|
+
hash: 'SHA-256',
|
|
28
|
+
}, keyMaterial, {
|
|
29
|
+
name: constants_js_1.ENCRYPTION_CONFIG.ALGORITHM,
|
|
30
|
+
length: constants_js_1.ENCRYPTION_CONFIG.KEY_LENGTH,
|
|
31
|
+
}, true, ['encrypt', 'decrypt']);
|
|
32
|
+
const exportedKey = await crypto.subtle.exportKey('raw', key);
|
|
33
|
+
return { key, keyString: (0, base64_js_1.bytesToBase64)(new Uint8Array(exportedKey)) };
|
|
34
|
+
}
|
|
35
|
+
/** Import raw AES key bytes as a NON-extractable CryptoKey. */
|
|
36
|
+
async function importMasterKey(keyString) {
|
|
37
|
+
const keyData = (0, base64_js_1.base64ToBytes)(keyString);
|
|
38
|
+
return crypto.subtle.importKey('raw', keyData, { name: constants_js_1.ENCRYPTION_CONFIG.ALGORITHM }, false, ['encrypt', 'decrypt']);
|
|
39
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface EncryptedNoteFields {
|
|
2
|
+
encryptedTitle: string;
|
|
3
|
+
/** "v2:<ivB64>:<ciphertextB64>" — carries its own IV. */
|
|
4
|
+
encryptedContent: string;
|
|
5
|
+
/** Title IV (v1 column back-compat). */
|
|
6
|
+
iv: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function encryptNoteFields(key: CryptoKey, title: string, content: string): Promise<EncryptedNoteFields>;
|
|
9
|
+
export declare function decryptNoteFields(key: CryptoKey, encryptedTitle: string, encryptedContent: string, ivBase64: string): Promise<{
|
|
10
|
+
title: string;
|
|
11
|
+
content: string;
|
|
12
|
+
}>;
|
|
13
|
+
export declare function decryptTitleField(key: CryptoKey, encryptedTitle: string, ivBase64: string): Promise<string>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.encryptNoteFields = encryptNoteFields;
|
|
4
|
+
exports.decryptNoteFields = decryptNoteFields;
|
|
5
|
+
exports.decryptTitleField = decryptTitleField;
|
|
6
|
+
const base64_js_1 = require("./base64.js");
|
|
7
|
+
const constants_js_1 = require("./constants.js");
|
|
8
|
+
async function encryptNoteFields(key, title, content) {
|
|
9
|
+
// VIR-7: AES-GCM must NEVER reuse a (key, IV) pair. Distinct IV for title
|
|
10
|
+
// and content; the `iv` field carries the title IV (v1 back-compat) and the
|
|
11
|
+
// content carries its own IV inline.
|
|
12
|
+
const ivTitle = crypto.getRandomValues(new Uint8Array(constants_js_1.ENCRYPTION_CONFIG.IV_LENGTH));
|
|
13
|
+
const ivContent = crypto.getRandomValues(new Uint8Array(constants_js_1.ENCRYPTION_CONFIG.IV_LENGTH));
|
|
14
|
+
const encoder = new TextEncoder();
|
|
15
|
+
const encryptedTitleBuffer = await crypto.subtle.encrypt({ name: constants_js_1.ENCRYPTION_CONFIG.ALGORITHM, iv: ivTitle }, key, encoder.encode(title || ''));
|
|
16
|
+
const encryptedContentBuffer = await crypto.subtle.encrypt({ name: constants_js_1.ENCRYPTION_CONFIG.ALGORITHM, iv: ivContent }, key, encoder.encode(content || ''));
|
|
17
|
+
return {
|
|
18
|
+
encryptedTitle: (0, base64_js_1.bytesToBase64)(encryptedTitleBuffer),
|
|
19
|
+
encryptedContent: 'v2:' +
|
|
20
|
+
(0, base64_js_1.bytesToBase64)(ivContent) +
|
|
21
|
+
':' +
|
|
22
|
+
(0, base64_js_1.bytesToBase64)(encryptedContentBuffer),
|
|
23
|
+
iv: (0, base64_js_1.bytesToBase64)(ivTitle),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async function decryptNoteFields(key, encryptedTitle, encryptedContent, ivBase64) {
|
|
27
|
+
const ivTitle = (0, base64_js_1.base64ToBytes)(ivBase64);
|
|
28
|
+
// v2 content carries its own IV ("v2:<ivB64>:<ctB64>"); v1 content is plain
|
|
29
|
+
// base64 and shares the column IV with the title. base64 never contains ':',
|
|
30
|
+
// so detection is unambiguous.
|
|
31
|
+
let ivContent = ivTitle;
|
|
32
|
+
let contentCipher = encryptedContent;
|
|
33
|
+
if (encryptedContent.startsWith('v2:')) {
|
|
34
|
+
const rest = encryptedContent.slice(3);
|
|
35
|
+
const sep = rest.indexOf(':');
|
|
36
|
+
ivContent = (0, base64_js_1.base64ToBytes)(rest.slice(0, sep));
|
|
37
|
+
contentCipher = rest.slice(sep + 1);
|
|
38
|
+
}
|
|
39
|
+
const decryptedTitleBuffer = await crypto.subtle.decrypt({ name: constants_js_1.ENCRYPTION_CONFIG.ALGORITHM, iv: ivTitle }, key, (0, base64_js_1.base64ToArrayBuffer)(encryptedTitle));
|
|
40
|
+
const decryptedContentBuffer = await crypto.subtle.decrypt({ name: constants_js_1.ENCRYPTION_CONFIG.ALGORITHM, iv: ivContent }, key, (0, base64_js_1.base64ToArrayBuffer)(contentCipher));
|
|
41
|
+
const decoder = new TextDecoder();
|
|
42
|
+
return {
|
|
43
|
+
title: decoder.decode(decryptedTitleBuffer),
|
|
44
|
+
content: decoder.decode(decryptedContentBuffer),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async function decryptTitleField(key, encryptedTitle, ivBase64) {
|
|
48
|
+
const iv = (0, base64_js_1.base64ToBytes)(ivBase64);
|
|
49
|
+
const decrypted = await crypto.subtle.decrypt({ name: constants_js_1.ENCRYPTION_CONFIG.ALGORITHM, iv: iv }, key, (0, base64_js_1.base64ToArrayBuffer)(encryptedTitle));
|
|
50
|
+
return new TextDecoder().decode(decrypted);
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type VerifierBlob = {
|
|
2
|
+
ciphertext: string;
|
|
3
|
+
iv: string;
|
|
4
|
+
salt: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Build a verifier blob: encrypt the known constant with the derived master
|
|
8
|
+
* key using the SAME AES-GCM primitive used for notes. `salt` is a fresh
|
|
9
|
+
* random value stored alongside the blob; it is NOT used to derive the master
|
|
10
|
+
* key (derivation stays password+userId).
|
|
11
|
+
*/
|
|
12
|
+
export declare function createVerifierBlob(key: CryptoKey): Promise<VerifierBlob>;
|
|
13
|
+
/**
|
|
14
|
+
* Verify a verifier blob: GCM-decrypt (the auth tag guarantees integrity) and
|
|
15
|
+
* confirm the plaintext equals the known constant. False on any failure.
|
|
16
|
+
*/
|
|
17
|
+
export declare function verifyVerifierBlob(key: CryptoKey, blob: VerifierBlob): Promise<boolean>;
|
|
18
|
+
/**
|
|
19
|
+
* True iff the key GCM-decrypts the given ciphertext (auth tag validates).
|
|
20
|
+
* Used to verify a migrated user's password against existing data when no
|
|
21
|
+
* verifier blob exists.
|
|
22
|
+
*/
|
|
23
|
+
export declare function canDecryptWithKey(key: CryptoKey, ciphertextBase64: string, ivBase64: string): Promise<boolean>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createVerifierBlob = createVerifierBlob;
|
|
4
|
+
exports.verifyVerifierBlob = verifyVerifierBlob;
|
|
5
|
+
exports.canDecryptWithKey = canDecryptWithKey;
|
|
6
|
+
const base64_js_1 = require("./base64.js");
|
|
7
|
+
const constants_js_1 = require("./constants.js");
|
|
8
|
+
/**
|
|
9
|
+
* Build a verifier blob: encrypt the known constant with the derived master
|
|
10
|
+
* key using the SAME AES-GCM primitive used for notes. `salt` is a fresh
|
|
11
|
+
* random value stored alongside the blob; it is NOT used to derive the master
|
|
12
|
+
* key (derivation stays password+userId).
|
|
13
|
+
*/
|
|
14
|
+
async function createVerifierBlob(key) {
|
|
15
|
+
const iv = crypto.getRandomValues(new Uint8Array(constants_js_1.ENCRYPTION_CONFIG.IV_LENGTH));
|
|
16
|
+
const salt = crypto.getRandomValues(new Uint8Array(constants_js_1.ENCRYPTION_CONFIG.SALT_LENGTH));
|
|
17
|
+
const ciphertextBuffer = await crypto.subtle.encrypt({ name: constants_js_1.ENCRYPTION_CONFIG.ALGORITHM, iv }, key, new TextEncoder().encode(constants_js_1.VERIFIER_CONSTANT));
|
|
18
|
+
return {
|
|
19
|
+
ciphertext: (0, base64_js_1.bytesToBase64)(ciphertextBuffer),
|
|
20
|
+
iv: (0, base64_js_1.bytesToBase64)(iv),
|
|
21
|
+
salt: (0, base64_js_1.bytesToBase64)(salt),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Verify a verifier blob: GCM-decrypt (the auth tag guarantees integrity) and
|
|
26
|
+
* confirm the plaintext equals the known constant. False on any failure.
|
|
27
|
+
*/
|
|
28
|
+
async function verifyVerifierBlob(key, blob) {
|
|
29
|
+
try {
|
|
30
|
+
const iv = (0, base64_js_1.base64ToBytes)(blob.iv);
|
|
31
|
+
const decrypted = await crypto.subtle.decrypt({ name: constants_js_1.ENCRYPTION_CONFIG.ALGORITHM, iv: iv }, key, (0, base64_js_1.base64ToArrayBuffer)(blob.ciphertext));
|
|
32
|
+
return new TextDecoder().decode(decrypted) === constants_js_1.VERIFIER_CONSTANT;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* True iff the key GCM-decrypts the given ciphertext (auth tag validates).
|
|
40
|
+
* Used to verify a migrated user's password against existing data when no
|
|
41
|
+
* verifier blob exists.
|
|
42
|
+
*/
|
|
43
|
+
async function canDecryptWithKey(key, ciphertextBase64, ivBase64) {
|
|
44
|
+
try {
|
|
45
|
+
const iv = (0, base64_js_1.base64ToBytes)(ivBase64);
|
|
46
|
+
await crypto.subtle.decrypt({ name: constants_js_1.ENCRYPTION_CONFIG.ALGORITHM, iv: iv }, key, (0, base64_js_1.base64ToArrayBuffer)(ciphertextBase64));
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { base64ToArrayBuffer, base64ToBytes, bytesToBase64 } from './base64';
|
|
2
|
-
export { decryptBytesBlob, decryptStringBlob, encryptBytesBlob, encryptStringBlob, } from './blob';
|
|
3
|
-
export { ENCRYPTION_CONFIG, VERIFIER_CONSTANT } from './constants';
|
|
4
|
-
export { deriveMasterKey, importMasterKey } from './keys';
|
|
5
|
-
export { decryptNoteFields, decryptTitleField, encryptNoteFields, type EncryptedNoteFields, } from './notes';
|
|
6
|
-
export { canDecryptWithKey, createVerifierBlob, verifyVerifierBlob, type VerifierBlob, } from './verifier';
|
|
1
|
+
export { base64ToArrayBuffer, base64ToBytes, bytesToBase64 } from './base64.js';
|
|
2
|
+
export { decryptBytesBlob, decryptStringBlob, encryptBytesBlob, encryptStringBlob, } from './blob.js';
|
|
3
|
+
export { ENCRYPTION_CONFIG, VERIFIER_CONSTANT } from './constants.js';
|
|
4
|
+
export { deriveMasterKey, importMasterKey } from './keys.js';
|
|
5
|
+
export { decryptNoteFields, decryptTitleField, encryptNoteFields, type EncryptedNoteFields, } from './notes.js';
|
|
6
|
+
export { canDecryptWithKey, createVerifierBlob, verifyVerifierBlob, type VerifierBlob, } from './verifier.js';
|
|
7
7
|
export declare const PACKAGE_NAME = "@batalabs/virlow-crypto";
|
|
8
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,mBAAmB,GACzB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,YAAY,GAClB,MAAM,eAAe,CAAC;AACvB,eAAO,MAAM,YAAY,4BAA4B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { base64ToArrayBuffer, base64ToBytes, bytesToBase64 } from './base64';
|
|
2
|
-
export { decryptBytesBlob, decryptStringBlob, encryptBytesBlob, encryptStringBlob, } from './blob';
|
|
3
|
-
export { ENCRYPTION_CONFIG, VERIFIER_CONSTANT } from './constants';
|
|
4
|
-
export { deriveMasterKey, importMasterKey } from './keys';
|
|
5
|
-
export { decryptNoteFields, decryptTitleField, encryptNoteFields, } from './notes';
|
|
6
|
-
export { canDecryptWithKey, createVerifierBlob, verifyVerifierBlob, } from './verifier';
|
|
1
|
+
export { base64ToArrayBuffer, base64ToBytes, bytesToBase64 } from './base64.js';
|
|
2
|
+
export { decryptBytesBlob, decryptStringBlob, encryptBytesBlob, encryptStringBlob, } from './blob.js';
|
|
3
|
+
export { ENCRYPTION_CONFIG, VERIFIER_CONSTANT } from './constants.js';
|
|
4
|
+
export { deriveMasterKey, importMasterKey } from './keys.js';
|
|
5
|
+
export { decryptNoteFields, decryptTitleField, encryptNoteFields, } from './notes.js';
|
|
6
|
+
export { canDecryptWithKey, createVerifierBlob, verifyVerifierBlob, } from './verifier.js';
|
|
7
7
|
export const PACKAGE_NAME = '@batalabs/virlow-crypto';
|
|
8
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,GAElB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,GAEnB,MAAM,eAAe,CAAC;AACvB,MAAM,CAAC,MAAM,YAAY,GAAG,yBAAyB,CAAC"}
|
package/dist/keys.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { base64ToBytes, bytesToBase64 } from './base64';
|
|
2
|
-
import { ENCRYPTION_CONFIG } from './constants';
|
|
1
|
+
import { base64ToBytes, bytesToBase64 } from './base64.js';
|
|
2
|
+
import { ENCRYPTION_CONFIG } from './constants.js';
|
|
3
3
|
/**
|
|
4
4
|
* Derive the master key from (password, userId) exactly as the web app does:
|
|
5
5
|
* PBKDF2(password, salt = UTF8(`typelets-salt-${userId}-v1`), 250000, SHA-256)
|
package/dist/keys.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,cAAmC,EACnC,MAAc;IAEd,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,aAAa,GACjB,OAAO,cAAc,KAAK,QAAQ;QAChC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC;QAChC,CAAC,CAAC,cAAc,CAAC;IACrB,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,iBAAiB,MAAM,KAAK,CAAC,CAAC;IAE9D,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAC/C,KAAK,EACL,aAA6B,EAC7B,EAAE,IAAI,EAAE,QAAQ,EAAE,EAClB,KAAK,EACL,CAAC,WAAW,CAAC,CACd,CAAC;IAEF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CACvC;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,iBAAiB,CAAC,UAAU;QACxC,IAAI,EAAE,SAAS;KAChB,EACD,WAAW,EACX;QACE,IAAI,EAAE,iBAAiB,CAAC,SAAS;QACjC,MAAM,EAAE,iBAAiB,CAAC,UAAU;KACrC,EACD,IAAI,EACJ,CAAC,SAAS,EAAE,SAAS,CAAC,CACvB,CAAC;IAEF,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC9D,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,aAAa,CAAC,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;AACxE,CAAC;AAED,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,SAAiB;IACrD,MAAM,OAAO,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAC5B,KAAK,EACL,OAAuB,EACvB,EAAE,IAAI,EAAE,iBAAiB,CAAC,SAAS,EAAE,EACrC,KAAK,EACL,CAAC,SAAS,EAAE,SAAS,CAAC,CACvB,CAAC;AACJ,CAAC"}
|
package/dist/notes.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { base64ToArrayBuffer, base64ToBytes, bytesToBase64 } from './base64';
|
|
2
|
-
import { ENCRYPTION_CONFIG } from './constants';
|
|
1
|
+
import { base64ToArrayBuffer, base64ToBytes, bytesToBase64 } from './base64.js';
|
|
2
|
+
import { ENCRYPTION_CONFIG } from './constants.js';
|
|
3
3
|
export async function encryptNoteFields(key, title, content) {
|
|
4
4
|
// VIR-7: AES-GCM must NEVER reuse a (key, IV) pair. Distinct IV for title
|
|
5
5
|
// and content; the `iv` field carries the title IV (v1 back-compat) and the
|
package/dist/notes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notes.js","sourceRoot":"","sources":["../src/notes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"notes.js","sourceRoot":"","sources":["../src/notes.ts"],"names":[],"mappings":"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"}
|
package/dist/verifier.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { base64ToArrayBuffer, base64ToBytes, bytesToBase64 } from './base64';
|
|
2
|
-
import { ENCRYPTION_CONFIG, VERIFIER_CONSTANT } from './constants';
|
|
1
|
+
import { base64ToArrayBuffer, base64ToBytes, bytesToBase64 } from './base64.js';
|
|
2
|
+
import { ENCRYPTION_CONFIG, VERIFIER_CONSTANT } from './constants.js';
|
|
3
3
|
/**
|
|
4
4
|
* Build a verifier blob: encrypt the known constant with the derived master
|
|
5
5
|
* key using the SAME AES-GCM primitive used for notes. `salt` is a fresh
|
package/dist/verifier.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verifier.js","sourceRoot":"","sources":["../src/verifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"verifier.js","sourceRoot":"","sources":["../src/verifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAQtE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAc;IACrD,MAAM,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC;IAC/E,MAAM,IAAI,GAAG,MAAM,CAAC,eAAe,CACjC,IAAI,UAAU,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAC9C,CAAC;IACF,MAAM,gBAAgB,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAClD,EAAE,IAAI,EAAE,iBAAiB,CAAC,SAAS,EAAE,EAAE,EAAE,EACzC,GAAG,EACH,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAC5C,CAAC;IACF,OAAO;QACL,UAAU,EAAE,aAAa,CAAC,gBAAgB,CAAC;QAC3C,EAAE,EAAE,aAAa,CAAC,EAAE,CAAC;QACrB,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC;KAC1B,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,GAAc,EACd,IAAkB;IAElB,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAC3C,EAAE,IAAI,EAAE,iBAAiB,CAAC,SAAS,EAAE,EAAE,EAAE,EAAkB,EAAE,EAC7D,GAAG,EACH,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CACrC,CAAC;QACF,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,iBAAiB,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAc,EACd,gBAAwB,EACxB,QAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CACzB,EAAE,IAAI,EAAE,iBAAiB,CAAC,SAAS,EAAE,EAAE,EAAE,EAAkB,EAAE,EAC7D,GAAG,EACH,mBAAmB,CAAC,gBAAgB,CAAC,CACtC,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@batalabs/virlow-crypto",
|
|
3
|
-
"version": "3.11.
|
|
3
|
+
"version": "3.11.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Virlow client-side encryption primitives (PBKDF2 + AES-256-GCM). Framework-free; browser and Node 20+.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
|
-
"
|
|
10
|
-
|
|
9
|
+
"import": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"require": {
|
|
14
|
+
"types": "./dist/cjs/index.d.ts",
|
|
15
|
+
"default": "./dist/cjs/index.js"
|
|
16
|
+
}
|
|
11
17
|
}
|
|
12
18
|
},
|
|
13
19
|
"devDependencies": {
|
|
@@ -15,7 +21,7 @@
|
|
|
15
21
|
"typescript": "^5.8.0",
|
|
16
22
|
"vitest": "^3.0.0"
|
|
17
23
|
},
|
|
18
|
-
"main": "./dist/index.js",
|
|
24
|
+
"main": "./dist/cjs/index.js",
|
|
19
25
|
"types": "./dist/index.d.ts",
|
|
20
26
|
"files": [
|
|
21
27
|
"LICENSE",
|
|
@@ -33,6 +39,6 @@
|
|
|
33
39
|
"scripts": {
|
|
34
40
|
"test": "vitest run",
|
|
35
41
|
"type-check": "tsc --noEmit",
|
|
36
|
-
"build": "tsc -p tsconfig.build.json"
|
|
42
|
+
"build": "tsc -p tsconfig.build.json && tsc -p tsconfig.cjs.json && node -e \"require('fs').writeFileSync('dist/cjs/package.json','{\\\"type\\\":\\\"commonjs\\\"}')\""
|
|
37
43
|
}
|
|
38
44
|
}
|