// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// @ts-check
///
///
///
///
"use strict";
((window) => {
const core = window.Deno.core;
const webidl = window.__bootstrap.webidl;
const { DOMException } = window.__bootstrap.domException;
const {
ArrayPrototypeFind,
ArrayBufferIsView,
ArrayPrototypeIncludes,
StringPrototypeToUpperCase,
Symbol,
SymbolFor,
SymbolToStringTag,
WeakMap,
WeakMapPrototypeGet,
WeakMapPrototypeSet,
Int8Array,
Uint8Array,
TypedArrayPrototypeSlice,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Uint8ClampedArray,
TypeError,
} = window.__bootstrap.primordials;
// P-521 is not yet supported.
const supportedNamedCurves = ["P-256", "P-384"];
const simpleAlgorithmDictionaries = {
RsaHashedKeyGenParams: { hash: "HashAlgorithmIdentifier" },
EcKeyGenParams: {},
HmacKeyGenParams: { hash: "HashAlgorithmIdentifier" },
RsaPssParams: {},
EcdsaParams: { hash: "HashAlgorithmIdentifier" },
};
const supportedAlgorithms = {
"digest": {
"SHA-1": null,
"SHA-256": null,
"SHA-384": null,
"SHA-512": null,
},
"generateKey": {
"RSASSA-PKCS1-v1_5": "RsaHashedKeyGenParams",
"RSA-PSS": "RsaHashedKeyGenParams",
"ECDSA": "EcKeyGenParams",
"HMAC": "HmacKeyGenParams",
},
"sign": {
"RSASSA-PKCS1-v1_5": null,
"RSA-PSS": "RsaPssParams",
"ECDSA": "EcdsaParams",
"HMAC": null,
},
"verify": {
"RSASSA-PKCS1-v1_5": null,
"RSA-PSS": "RsaPssParams",
},
};
// See https://www.w3.org/TR/WebCryptoAPI/#dfn-normalize-an-algorithm
function normalizeAlgorithm(algorithm, op) {
if (typeof algorithm == "string") {
return normalizeAlgorithm({ name: algorithm }, op);
}
// 1.
const registeredAlgorithms = supportedAlgorithms[op];
// 2. 3.
const initialAlg = webidl.converters.Algorithm(algorithm, {
prefix: "Failed to normalize algorithm",
context: "passed algorithm",
});
// 4.
let algName = initialAlg.name;
// 5.
let desiredType = undefined;
for (const key in registeredAlgorithms) {
if (
StringPrototypeToUpperCase(key) === StringPrototypeToUpperCase(algName)
) {
algName = key;
desiredType = registeredAlgorithms[key];
}
}
if (desiredType === undefined) {
throw new DOMException(
"Unrecognized algorithm name",
"NotSupportedError",
);
}
// Fast path everything below if the registered dictionary is "None".
if (desiredType === null) {
return { name: algName };
}
const normalizedAlgorithm = webidl.converters[desiredType](algorithm, {
prefix: "Failed to normalize algorithm",
context: "passed algorithm",
});
normalizedAlgorithm.name = algName;
const dict = simpleAlgorithmDictionaries[desiredType];
for (const member in dict) {
const idlType = dict[member];
const idlValue = normalizedAlgorithm[member];
if (idlType === "BufferSource") {
normalizedAlgorithm[member] = new Uint8Array(
TypedArrayPrototypeSlice(
(ArrayBufferIsView(idlValue) ? idlValue.buffer : idlValue),
idlValue.byteOffset ?? 0,
idlValue.byteLength,
),
);
} else if (idlType === "HashAlgorithmIdentifier") {
normalizedAlgorithm[member] = normalizeAlgorithm(idlValue, "digest");
} else if (idlType === "AlgorithmIdentifier") {
// TODO(lucacasonato): implement
throw new TypeError("unimplemented");
}
}
return normalizedAlgorithm;
}
const _handle = Symbol("[[handle]]");
const _algorithm = Symbol("[[algorithm]]");
const _extractable = Symbol("[[extractable]]");
const _usages = Symbol("[[usages]]");
const _type = Symbol("[[type]]");
class CryptoKey {
/** @type {string} */
[_type];
/** @type {boolean} */
[_extractable];
/** @type {object} */
[_algorithm];
/** @type {string[]} */
[_usages];
/** @type {object} */
[_handle];
constructor() {
webidl.illegalConstructor();
}
/** @returns {string} */
get type() {
webidl.assertBranded(this, CryptoKey);
return this[_type];
}
/** @returns {boolean} */
get extractable() {
webidl.assertBranded(this, CryptoKey);
return this[_extractable];
}
/** @returns {string[]} */
get usages() {
webidl.assertBranded(this, CryptoKey);
// TODO(lucacasonato): return a SameObject copy
return this[_usages];
}
/** @returns {object} */
get algorithm() {
webidl.assertBranded(this, CryptoKey);
// TODO(lucacasonato): return a SameObject copy
return this[_algorithm];
}
get [Symbol.toStringTag]() {
return "CryptoKey";
}
[SymbolFor("Deno.customInspect")](inspect) {
return `${this.constructor.name} ${
inspect({
type: this.type,
extractable: this.extractable,
algorithm: this.algorithm,
usages: this.usages,
})
}`;
}
}
webidl.configurePrototype(CryptoKey);
/**
* @param {string} type
* @param {boolean} extractable
* @param {string[]} usages
* @param {object} algorithm
* @param {object} handle
* @returns
*/
function constructKey(type, extractable, usages, algorithm, handle) {
const key = webidl.createBranded(CryptoKey);
key[_type] = type;
key[_extractable] = extractable;
key[_usages] = usages;
key[_algorithm] = algorithm;
key[_handle] = handle;
return key;
}
// https://w3c.github.io/webcrypto/#concept-usage-intersection
// TODO(littledivy): When the need arises, make `b` a list.
/**
* @param {string[]} a
* @param {string} b
* @returns
*/
function usageIntersection(a, b) {
return ArrayPrototypeIncludes(a, b) ? [b] : [];
}
// TODO(lucacasonato): this should be moved to rust
/** @type {WeakMap