Skip to content

Commit

Permalink
chore: enable isolatedDeclarations
Browse files Browse the repository at this point in the history
  • Loading branch information
brc-dd committed Jun 27, 2024
1 parent 1f7b3d8 commit 8c1b05e
Show file tree
Hide file tree
Showing 8 changed files with 695 additions and 965 deletions.
60 changes: 20 additions & 40 deletions dist/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ var randomBytes = (_crypto, size) => {
return bytes;
};
var randomBits = (_crypto, bits) => {
if (bits < 1)
throw new Error("Invalid random bits count");
if (bits < 1) throw new Error("Invalid random bits count");
const bytes = Math.ceil(bits / 8);
return randomBytes(_crypto, bytes);
};
Expand All @@ -135,12 +134,9 @@ var pbkdf2 = async (_crypto, password, salt, iterations, keyLength, hash) => {
};
var generateKey = async (_crypto, password, options) => {
var _a;
if (!(password == null ? void 0 : password.length))
throw new Error("Empty password");
if (options == null || typeof options !== "object")
throw new Error("Bad options");
if (!(options.algorithm in algorithms))
throw new Error(`Unknown algorithm: ${options.algorithm}`);
if (!(password == null ? void 0 : password.length)) throw new Error("Empty password");
if (options == null || typeof options !== "object") throw new Error("Bad options");
if (!(options.algorithm in algorithms)) throw new Error(`Unknown algorithm: ${options.algorithm}`);
const algorithm = algorithms[options.algorithm];
const result = {};
const hmac = (_a = options.hmac) != null ? _a : false;
Expand All @@ -154,8 +150,7 @@ var generateKey = async (_crypto, password, options) => {
let { salt = "" } = options;
if (!salt) {
const { saltBits = 0 } = options;
if (!saltBits)
throw new Error("Missing salt and saltBits options");
if (!saltBits) throw new Error("Missing salt and saltBits options");
const randomSalt = randomBits(_crypto, saltBits);
salt = [...new Uint8Array(randomSalt)].map((x) => x.toString(16).padStart(2, "0")).join("");
}
Expand All @@ -177,15 +172,12 @@ var generateKey = async (_crypto, password, options) => {
result.key = importedEncryptionKey;
result.salt = salt;
} else {
if (password.length < algorithm.keyBits / 8)
throw new Error("Key buffer (password) too small");
if (password.length < algorithm.keyBits / 8) throw new Error("Key buffer (password) too small");
result.key = await _crypto.subtle.importKey("raw", password, id, false, usage);
result.salt = "";
}
if (options.iv)
result.iv = options.iv;
else if ("ivBits" in algorithm)
result.iv = randomBits(_crypto, algorithm.ivBits);
if (options.iv) result.iv = options.iv;
else if ("ivBits" in algorithm) result.iv = randomBits(_crypto, algorithm.ivBits);
return result;
};
var getEncryptParams = (algorithm, key, data) => {
Expand Down Expand Up @@ -220,15 +212,13 @@ var normalizePassword = (password) => {
return { id: password.id, encryption: password.encryption, integrity: password.integrity };
};
var seal = async (_crypto, object, password, options) => {
if (!password)
throw new Error("Empty password");
if (!password) throw new Error("Empty password");
const opts = clone(options);
const now = Date.now() + (opts.localtimeOffsetMsec || 0);
const objectString = JSON.stringify(object);
const pass = normalizePassword(password);
const { id = "", encryption, integrity } = pass;
if (id && !/^\w+$/.test(id))
throw new Error("Invalid password id");
if (id && !/^\w+$/.test(id)) throw new Error("Invalid password id");
const { encrypted, key } = await encrypt(_crypto, encryption, opts.encryption, objectString);
const encryptedB64 = base64urlEncode(new Uint8Array(encrypted));
const iv = base64urlEncode(key.iv);
Expand All @@ -240,20 +230,16 @@ var seal = async (_crypto, object, password, options) => {
};
var fixedTimeComparison = (a, b) => {
let mismatch = a.length === b.length ? 0 : 1;
if (mismatch)
b = a;
for (let i = 0; i < a.length; i += 1)
mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);
if (mismatch) b = a;
for (let i = 0; i < a.length; i += 1) mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);
return mismatch === 0;
};
var unseal = async (_crypto, sealed, password, options) => {
if (!password)
throw new Error("Empty password");
if (!password) throw new Error("Empty password");
const opts = clone(options);
const now = Date.now() + (opts.localtimeOffsetMsec || 0);
const parts = sealed.split("*");
if (parts.length !== 8)
throw new Error("Incorrect number of sealed components");
if (parts.length !== 8) throw new Error("Incorrect number of sealed components");
const prefix = parts[0];
let passwordId = parts[1];
const encryptionSalt = parts[2];
Expand All @@ -263,19 +249,15 @@ var unseal = async (_crypto, sealed, password, options) => {
const hmacSalt = parts[6];
const hmac = parts[7];
const macBaseString = `${prefix}*${passwordId}*${encryptionSalt}*${encryptionIv}*${encryptedB64}*${expiration}`;
if (macPrefix !== prefix)
throw new Error("Wrong mac prefix");
if (macPrefix !== prefix) throw new Error("Wrong mac prefix");
if (expiration) {
if (!/^\d+$/.test(expiration))
throw new Error("Invalid expiration");
if (!/^\d+$/.test(expiration)) throw new Error("Invalid expiration");
const exp = Number.parseInt(expiration, 10);
if (exp <= now - opts.timestampSkewSec * 1e3)
throw new Error("Expired seal");
if (exp <= now - opts.timestampSkewSec * 1e3) throw new Error("Expired seal");
}
let pass = "";
passwordId = passwordId || "default";
if (typeof password === "string" || password instanceof Uint8Array)
pass = password;
if (typeof password === "string" || password instanceof Uint8Array) pass = password;
else if (passwordId in password) {
pass = password[passwordId];
} else {
Expand All @@ -285,15 +267,13 @@ var unseal = async (_crypto, sealed, password, options) => {
const macOptions = opts.integrity;
macOptions.salt = hmacSalt;
const mac = await hmacWithPassword(_crypto, pass.integrity, macOptions, macBaseString);
if (!fixedTimeComparison(mac.digest, hmac))
throw new Error("Bad hmac value");
if (!fixedTimeComparison(mac.digest, hmac)) throw new Error("Bad hmac value");
const encrypted = base64urlDecode(encryptedB64);
const decryptOptions = opts.encryption;
decryptOptions.salt = encryptionSalt;
decryptOptions.iv = base64urlDecode(encryptionIv);
const decrypted = await decrypt(_crypto, pass.encryption, decryptOptions, encrypted);
if (decrypted)
return JSON.parse(decrypted);
if (decrypted) return JSON.parse(decrypted);
return null;
};

Expand Down
60 changes: 20 additions & 40 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,7 @@ var randomBytes = (_crypto, size) => {
return bytes;
};
var randomBits = (_crypto, bits) => {
if (bits < 1)
throw new Error("Invalid random bits count");
if (bits < 1) throw new Error("Invalid random bits count");
const bytes = Math.ceil(bits / 8);
return randomBytes(_crypto, bytes);
};
Expand All @@ -133,12 +132,9 @@ var pbkdf2 = async (_crypto, password, salt, iterations, keyLength, hash) => {
};
var generateKey = async (_crypto, password, options) => {
var _a;
if (!(password == null ? void 0 : password.length))
throw new Error("Empty password");
if (options == null || typeof options !== "object")
throw new Error("Bad options");
if (!(options.algorithm in algorithms))
throw new Error(`Unknown algorithm: ${options.algorithm}`);
if (!(password == null ? void 0 : password.length)) throw new Error("Empty password");
if (options == null || typeof options !== "object") throw new Error("Bad options");
if (!(options.algorithm in algorithms)) throw new Error(`Unknown algorithm: ${options.algorithm}`);
const algorithm = algorithms[options.algorithm];
const result = {};
const hmac = (_a = options.hmac) != null ? _a : false;
Expand All @@ -152,8 +148,7 @@ var generateKey = async (_crypto, password, options) => {
let { salt = "" } = options;
if (!salt) {
const { saltBits = 0 } = options;
if (!saltBits)
throw new Error("Missing salt and saltBits options");
if (!saltBits) throw new Error("Missing salt and saltBits options");
const randomSalt = randomBits(_crypto, saltBits);
salt = [...new Uint8Array(randomSalt)].map((x) => x.toString(16).padStart(2, "0")).join("");
}
Expand All @@ -175,15 +170,12 @@ var generateKey = async (_crypto, password, options) => {
result.key = importedEncryptionKey;
result.salt = salt;
} else {
if (password.length < algorithm.keyBits / 8)
throw new Error("Key buffer (password) too small");
if (password.length < algorithm.keyBits / 8) throw new Error("Key buffer (password) too small");
result.key = await _crypto.subtle.importKey("raw", password, id, false, usage);
result.salt = "";
}
if (options.iv)
result.iv = options.iv;
else if ("ivBits" in algorithm)
result.iv = randomBits(_crypto, algorithm.ivBits);
if (options.iv) result.iv = options.iv;
else if ("ivBits" in algorithm) result.iv = randomBits(_crypto, algorithm.ivBits);
return result;
};
var getEncryptParams = (algorithm, key, data) => {
Expand Down Expand Up @@ -218,15 +210,13 @@ var normalizePassword = (password) => {
return { id: password.id, encryption: password.encryption, integrity: password.integrity };
};
var seal = async (_crypto, object, password, options) => {
if (!password)
throw new Error("Empty password");
if (!password) throw new Error("Empty password");
const opts = clone(options);
const now = Date.now() + (opts.localtimeOffsetMsec || 0);
const objectString = JSON.stringify(object);
const pass = normalizePassword(password);
const { id = "", encryption, integrity } = pass;
if (id && !/^\w+$/.test(id))
throw new Error("Invalid password id");
if (id && !/^\w+$/.test(id)) throw new Error("Invalid password id");
const { encrypted, key } = await encrypt(_crypto, encryption, opts.encryption, objectString);
const encryptedB64 = base64urlEncode(new Uint8Array(encrypted));
const iv = base64urlEncode(key.iv);
Expand All @@ -238,20 +228,16 @@ var seal = async (_crypto, object, password, options) => {
};
var fixedTimeComparison = (a, b) => {
let mismatch = a.length === b.length ? 0 : 1;
if (mismatch)
b = a;
for (let i = 0; i < a.length; i += 1)
mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);
if (mismatch) b = a;
for (let i = 0; i < a.length; i += 1) mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);
return mismatch === 0;
};
var unseal = async (_crypto, sealed, password, options) => {
if (!password)
throw new Error("Empty password");
if (!password) throw new Error("Empty password");
const opts = clone(options);
const now = Date.now() + (opts.localtimeOffsetMsec || 0);
const parts = sealed.split("*");
if (parts.length !== 8)
throw new Error("Incorrect number of sealed components");
if (parts.length !== 8) throw new Error("Incorrect number of sealed components");
const prefix = parts[0];
let passwordId = parts[1];
const encryptionSalt = parts[2];
Expand All @@ -261,19 +247,15 @@ var unseal = async (_crypto, sealed, password, options) => {
const hmacSalt = parts[6];
const hmac = parts[7];
const macBaseString = `${prefix}*${passwordId}*${encryptionSalt}*${encryptionIv}*${encryptedB64}*${expiration}`;
if (macPrefix !== prefix)
throw new Error("Wrong mac prefix");
if (macPrefix !== prefix) throw new Error("Wrong mac prefix");
if (expiration) {
if (!/^\d+$/.test(expiration))
throw new Error("Invalid expiration");
if (!/^\d+$/.test(expiration)) throw new Error("Invalid expiration");
const exp = Number.parseInt(expiration, 10);
if (exp <= now - opts.timestampSkewSec * 1e3)
throw new Error("Expired seal");
if (exp <= now - opts.timestampSkewSec * 1e3) throw new Error("Expired seal");
}
let pass = "";
passwordId = passwordId || "default";
if (typeof password === "string" || password instanceof Uint8Array)
pass = password;
if (typeof password === "string" || password instanceof Uint8Array) pass = password;
else if (passwordId in password) {
pass = password[passwordId];
} else {
Expand All @@ -283,15 +265,13 @@ var unseal = async (_crypto, sealed, password, options) => {
const macOptions = opts.integrity;
macOptions.salt = hmacSalt;
const mac = await hmacWithPassword(_crypto, pass.integrity, macOptions, macBaseString);
if (!fixedTimeComparison(mac.digest, hmac))
throw new Error("Bad hmac value");
if (!fixedTimeComparison(mac.digest, hmac)) throw new Error("Bad hmac value");
const encrypted = base64urlDecode(encryptedB64);
const decryptOptions = opts.encryption;
decryptOptions.salt = encryptionSalt;
decryptOptions.iv = base64urlDecode(encryptionIv);
const decrypted = await decrypt(_crypto, pass.encryption, decryptOptions, encrypted);
if (decrypted)
return JSON.parse(decrypted);
if (decrypted) return JSON.parse(decrypted);
return null;
};

Expand Down
30 changes: 15 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"lint:only": "lefthook run pre-commit && publint && attw --pack",
"test": "pnpm test:node && pnpm test:deno && pnpm test:bun",
"test:bun": "bun --cwd=tests/bun test",
"test:deno": "deno test tests/deno/index.test.ts --parallel --no-check",
"test:deno": "DENO_NO_PACKAGE_JSON=1 deno test tests/deno/index.test.ts --parallel --no-check",
"test:node": "tsx --test tests/node/index.test.ts"
},
"devDependencies": {
Expand All @@ -42,10 +42,10 @@
"@commitlint/config-conventional": "^19.2.2",
"@eslint-community/eslint-plugin-eslint-comments": "^4.3.0",
"@release-it/conventional-changelog": "^8.0.1",
"@types/bun": "^1.1.1",
"@types/node": "^20.12.11",
"@typescript-eslint/eslint-plugin": "^7.8.0",
"@typescript-eslint/parser": "^7.8.0",
"@types/bun": "^1.1.6",
"@types/node": "^20.14.9",
"@typescript-eslint/eslint-plugin": "^7.14.1",
"@typescript-eslint/parser": "^7.14.1",
"eslint": "^8.57.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-airbnb-typescript": "^18.0.0",
Expand All @@ -54,19 +54,19 @@
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-security": "^3.0.0",
"eslint-plugin-unicorn": "^52.0.0",
"eslint-plugin-security": "^3.0.1",
"eslint-plugin-unicorn": "^54.0.0",
"jsr": "^0.12.4",
"lefthook": "^1.6.10",
"prettier": "^3.2.5",
"lefthook": "^1.6.18",
"prettier": "^3.3.2",
"prettier-plugin-packagejson": "^2.5.0",
"publint": "^0.2.7",
"release-it": "^17.2.1",
"publint": "^0.2.8",
"release-it": "^17.4.0",
"replace": "^1.2.2",
"tsup": "^8.0.2",
"tsx": "^4.9.3",
"typescript": "^5.4.5"
"tsup": "^8.1.0",
"tsx": "^4.15.7",
"typescript": "^5.5.2"
},
"packageManager": "pnpm@9.1.0",
"packageManager": "pnpm@9.4.0",
"runkitExampleFilename": "dist/example.js"
}
Loading

0 comments on commit 8c1b05e

Please sign in to comment.