feat: 초기 프로젝트 설정 및 룰.md 파일 추가

This commit is contained in:
2025-07-28 09:53:31 +09:00
commit 09a4d38512
8165 changed files with 1021855 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
/**
* A collection of methods for isomorphic manipulation of trickier data types
*
* The goal with these is to make it easier to replace dependencies later that might not play well
* with specific server-like runtimes that expose global Web APIs (CloudFlare Workers, Deno, Bun,
* etc...), while also supporting execution in Node.
*/
export * as isoBase64URL from './isoBase64URL.js';
export * as isoCBOR from './isoCBOR.js';
export * as isoCrypto from './isoCrypto/index.js';
export * as isoUint8Array from './isoUint8Array.js';
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/helpers/iso/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC"}

View File

@@ -0,0 +1,37 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isoUint8Array = exports.isoCrypto = exports.isoCBOR = exports.isoBase64URL = void 0;
/**
* A collection of methods for isomorphic manipulation of trickier data types
*
* The goal with these is to make it easier to replace dependencies later that might not play well
* with specific server-like runtimes that expose global Web APIs (CloudFlare Workers, Deno, Bun,
* etc...), while also supporting execution in Node.
*/
exports.isoBase64URL = __importStar(require("./isoBase64URL.js"));
exports.isoCBOR = __importStar(require("./isoCBOR.js"));
exports.isoCrypto = __importStar(require("./isoCrypto/index.js"));
exports.isoUint8Array = __importStar(require("./isoUint8Array.js"));

View File

@@ -0,0 +1,43 @@
import type { Base64URLString } from '../../types/index.js';
/**
* Decode from a Base64URL-encoded string to an ArrayBuffer. Best used when converting a
* credential ID from a JSON string to an ArrayBuffer, like in allowCredentials or
* excludeCredentials.
*
* @param buffer Value to decode from base64
* @param to (optional) The decoding to use, in case it's desirable to decode from base64 instead
*/
export declare function toBuffer(base64urlString: string, from?: 'base64' | 'base64url'): Uint8Array;
/**
* Encode the given array buffer into a Base64URL-encoded string. Ideal for converting various
* credential response ArrayBuffers to string for sending back to the server as JSON.
*
* @param buffer Value to encode to base64
* @param to (optional) The encoding to use, in case it's desirable to encode to base64 instead
*/
export declare function fromBuffer(buffer: Uint8Array, to?: 'base64' | 'base64url'): string;
/**
* Convert a base64url string into base64
*/
export declare function toBase64(base64urlString: string): string;
/**
* Encode a UTF-8 string to base64url
*/
export declare function fromUTF8String(utf8String: string): string;
/**
* Decode a base64url string into its original UTF-8 string
*/
export declare function toUTF8String(base64urlString: string): string;
/**
* Confirm that the string is encoded into base64
*/
export declare function isBase64(input: string): boolean;
/**
* Confirm that the string is encoded into base64url, with support for optional padding
*/
export declare function isBase64URL(input: string): boolean;
/**
* Remove optional padding from a base64url-encoded string
*/
export declare function trimPadding(input: Base64URLString): Base64URLString;
//# sourceMappingURL=isoBase64URL.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"isoBase64URL.d.ts","sourceRoot":"","sources":["../../../src/helpers/iso/isoBase64URL.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,eAAe,EAAE,MAAM,EACvB,IAAI,GAAE,QAAQ,GAAG,WAAyB,GACzC,UAAU,CAGZ;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,UAAU,EAClB,EAAE,GAAE,QAAQ,GAAG,WAAyB,GACvC,MAAM,CAER;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAIxD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAIlD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,eAAe,GAAG,eAAe,CAEnE"}

View File

@@ -0,0 +1,80 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.toBuffer = toBuffer;
exports.fromBuffer = fromBuffer;
exports.toBase64 = toBase64;
exports.fromUTF8String = fromUTF8String;
exports.toUTF8String = toUTF8String;
exports.isBase64 = isBase64;
exports.isBase64URL = isBase64URL;
exports.trimPadding = trimPadding;
/**
* A runtime-agnostic collection of methods for working with Base64URL encoding
* @module
*/
const base64_1 = __importDefault(require("@hexagon/base64"));
/**
* Decode from a Base64URL-encoded string to an ArrayBuffer. Best used when converting a
* credential ID from a JSON string to an ArrayBuffer, like in allowCredentials or
* excludeCredentials.
*
* @param buffer Value to decode from base64
* @param to (optional) The decoding to use, in case it's desirable to decode from base64 instead
*/
function toBuffer(base64urlString, from = 'base64url') {
const _buffer = base64_1.default.toArrayBuffer(base64urlString, from === 'base64url');
return new Uint8Array(_buffer);
}
/**
* Encode the given array buffer into a Base64URL-encoded string. Ideal for converting various
* credential response ArrayBuffers to string for sending back to the server as JSON.
*
* @param buffer Value to encode to base64
* @param to (optional) The encoding to use, in case it's desirable to encode to base64 instead
*/
function fromBuffer(buffer, to = 'base64url') {
return base64_1.default.fromArrayBuffer(buffer, to === 'base64url');
}
/**
* Convert a base64url string into base64
*/
function toBase64(base64urlString) {
const fromBase64Url = base64_1.default.toArrayBuffer(base64urlString, true);
const toBase64 = base64_1.default.fromArrayBuffer(fromBase64Url);
return toBase64;
}
/**
* Encode a UTF-8 string to base64url
*/
function fromUTF8String(utf8String) {
return base64_1.default.fromString(utf8String, true);
}
/**
* Decode a base64url string into its original UTF-8 string
*/
function toUTF8String(base64urlString) {
return base64_1.default.toString(base64urlString, true);
}
/**
* Confirm that the string is encoded into base64
*/
function isBase64(input) {
return base64_1.default.validate(input, false);
}
/**
* Confirm that the string is encoded into base64url, with support for optional padding
*/
function isBase64URL(input) {
// Trim padding characters from the string if present
input = trimPadding(input);
return base64_1.default.validate(input, true);
}
/**
* Remove optional padding from a base64url-encoded string
*/
function trimPadding(input) {
return input.replace(/=/g, '');
}

View File

@@ -0,0 +1,28 @@
/**
* A runtime-agnostic collection of methods for working with CBOR encoding
* @module
*/
import * as tinyCbor from '@levischuck/tiny-cbor';
/**
* Whatever CBOR encoder is used should keep CBOR data the same length when data is re-encoded
*
* MOST CRITICALLY, this means the following needs to be true of whatever CBOR library we use:
* - CBOR Map type values MUST decode to JavaScript Maps
* - CBOR tag 64 (uint8 Typed Array) MUST NOT be used when encoding Uint8Arrays back to CBOR
*
* So long as these requirements are maintained, then CBOR sequences can be encoded and decoded
* freely while maintaining their lengths for the most accurate pointer movement across them.
*/
/**
* Decode and return the first item in a sequence of CBOR-encoded values
*
* @param input The CBOR data to decode
* @param asObject (optional) Whether to convert any CBOR Maps into JavaScript Objects. Defaults to
* `false`
*/
export declare function decodeFirst<Type>(input: Uint8Array): Type;
/**
* Encode data to CBOR
*/
export declare function encode(input: tinyCbor.CBORType): Uint8Array;
//# sourceMappingURL=isoCBOR.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"isoCBOR.d.ts","sourceRoot":"","sources":["../../../src/helpers/iso/isoCBOR.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,QAAQ,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;GASG;AAEH;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAQzD;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,GAAG,UAAU,CAE3D"}

View File

@@ -0,0 +1,62 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.decodeFirst = decodeFirst;
exports.encode = encode;
/**
* A runtime-agnostic collection of methods for working with CBOR encoding
* @module
*/
const tinyCbor = __importStar(require("@levischuck/tiny-cbor"));
/**
* Whatever CBOR encoder is used should keep CBOR data the same length when data is re-encoded
*
* MOST CRITICALLY, this means the following needs to be true of whatever CBOR library we use:
* - CBOR Map type values MUST decode to JavaScript Maps
* - CBOR tag 64 (uint8 Typed Array) MUST NOT be used when encoding Uint8Arrays back to CBOR
*
* So long as these requirements are maintained, then CBOR sequences can be encoded and decoded
* freely while maintaining their lengths for the most accurate pointer movement across them.
*/
/**
* Decode and return the first item in a sequence of CBOR-encoded values
*
* @param input The CBOR data to decode
* @param asObject (optional) Whether to convert any CBOR Maps into JavaScript Objects. Defaults to
* `false`
*/
function decodeFirst(input) {
// Make a copy so we don't mutate the original
const _input = new Uint8Array(input);
const decoded = tinyCbor.decodePartialCBOR(_input, 0);
const [first] = decoded;
return first;
}
/**
* Encode data to CBOR
*/
function encode(input) {
return tinyCbor.encodeCBOR(input);
}

View File

@@ -0,0 +1,9 @@
import { COSEALG } from '../../cose.js';
/**
* Generate a digest of the provided data.
*
* @param data The data to generate a digest of
* @param algorithm A COSE algorithm ID that maps to a desired SHA algorithm
*/
export declare function digest(data: Uint8Array, algorithm: COSEALG): Promise<Uint8Array>;
//# sourceMappingURL=digest.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/digest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAIxC;;;;;GAKG;AACH,wBAAsB,MAAM,CAC1B,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,UAAU,CAAC,CAQrB"}

View File

@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.digest = digest;
const mapCoseAlgToWebCryptoAlg_js_1 = require("./mapCoseAlgToWebCryptoAlg.js");
const getWebCrypto_js_1 = require("./getWebCrypto.js");
/**
* Generate a digest of the provided data.
*
* @param data The data to generate a digest of
* @param algorithm A COSE algorithm ID that maps to a desired SHA algorithm
*/
async function digest(data, algorithm) {
const WebCrypto = await (0, getWebCrypto_js_1.getWebCrypto)();
const subtleAlgorithm = (0, mapCoseAlgToWebCryptoAlg_js_1.mapCoseAlgToWebCryptoAlg)(algorithm);
const hashed = await WebCrypto.subtle.digest(subtleAlgorithm, data);
return new Uint8Array(hashed);
}

View File

@@ -0,0 +1,7 @@
/**
* Fill up the provided bytes array with random bytes equal to its length.
*
* @returns the same bytes array passed into the method
*/
export declare function getRandomValues(array: Uint8Array): Promise<Uint8Array>;
//# sourceMappingURL=getRandomValues.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getRandomValues.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/getRandomValues.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAM5E"}

View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRandomValues = getRandomValues;
const getWebCrypto_js_1 = require("./getWebCrypto.js");
/**
* Fill up the provided bytes array with random bytes equal to its length.
*
* @returns the same bytes array passed into the method
*/
async function getRandomValues(array) {
const WebCrypto = await (0, getWebCrypto_js_1.getWebCrypto)();
WebCrypto.getRandomValues(array);
return array;
}

View File

@@ -0,0 +1,14 @@
import type { Crypto } from '../../../types/index.js';
/**
* Try to get an instance of the Crypto API from the current runtime. Should support Node,
* as well as others, like Deno, that implement Web APIs.
*/
export declare function getWebCrypto(): Promise<Crypto>;
export declare class MissingWebCrypto extends Error {
constructor();
}
export declare const _getWebCryptoInternals: {
stubThisGlobalThisCrypto: () => import("crypto").webcrypto.Crypto;
setCachedCrypto: (newCrypto: Crypto | undefined) => void;
};
//# sourceMappingURL=getWebCrypto.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getWebCrypto.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/getWebCrypto.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAItD;;;GAGG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAgC9C;AAED,qBAAa,gBAAiB,SAAQ,KAAK;;CAM1C;AAGD,eAAO,MAAM,sBAAsB;;iCAGJ,MAAM,GAAG,SAAS;CAGhD,CAAC"}

View File

@@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports._getWebCryptoInternals = exports.MissingWebCrypto = void 0;
exports.getWebCrypto = getWebCrypto;
let webCrypto = undefined;
/**
* Try to get an instance of the Crypto API from the current runtime. Should support Node,
* as well as others, like Deno, that implement Web APIs.
*/
function getWebCrypto() {
/**
* Hello there! If you came here wondering why this method is asynchronous when use of
* `globalThis.crypto` is not, it's to minimize a bunch of refactor related to making this
* synchronous. For example, `generateRegistrationOptions()` and `generateAuthenticationOptions()`
* become synchronous if we make this synchronous (since nothing else in that method is async)
* which represents a breaking API change in this library's core API.
*
* TODO: If it's after February 2025 when you read this then consider whether it still makes sense
* to keep this method asynchronous.
*/
const toResolve = new Promise((resolve, reject) => {
if (webCrypto) {
return resolve(webCrypto);
}
/**
* Naively attempt to access Crypto as a global object, which popular ESM-centric run-times
* support (and Node v20+)
*/
const _globalThisCrypto = exports._getWebCryptoInternals.stubThisGlobalThisCrypto();
if (_globalThisCrypto) {
webCrypto = _globalThisCrypto;
return resolve(webCrypto);
}
// We tried to access it both in Node and globally, so bail out
return reject(new MissingWebCrypto());
});
return toResolve;
}
class MissingWebCrypto extends Error {
constructor() {
const message = 'An instance of the Crypto API could not be located';
super(message);
this.name = 'MissingWebCrypto';
}
}
exports.MissingWebCrypto = MissingWebCrypto;
// Make it possible to stub return values during testing
exports._getWebCryptoInternals = {
stubThisGlobalThisCrypto: () => globalThis.crypto,
// Make it possible to reset the `webCrypto` at the top of the file
setCachedCrypto: (newCrypto) => {
webCrypto = newCrypto;
},
};

View File

@@ -0,0 +1,5 @@
export declare function importKey(opts: {
keyData: JsonWebKey;
algorithm: AlgorithmIdentifier | RsaHashedImportParams | EcKeyImportParams;
}): Promise<CryptoKey>;
//# sourceMappingURL=importKey.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"importKey.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/importKey.ts"],"names":[],"mappings":"AAEA,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,OAAO,EAAE,UAAU,CAAC;IACpB,SAAS,EAAE,mBAAmB,GAAG,qBAAqB,GAAG,iBAAiB,CAAC;CAC5E,GAAG,OAAO,CAAC,SAAS,CAAC,CAQrB"}

View File

@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.importKey = importKey;
const getWebCrypto_js_1 = require("./getWebCrypto.js");
async function importKey(opts) {
const WebCrypto = await (0, getWebCrypto_js_1.getWebCrypto)();
const { keyData, algorithm } = opts;
return WebCrypto.subtle.importKey('jwk', keyData, algorithm, false, [
'verify',
]);
}

View File

@@ -0,0 +1,8 @@
/**
* A runtime-agnostic collection of methods for working with the WebCrypto API
* @module
*/
export { digest } from './digest.js';
export { getRandomValues } from './getRandomValues.js';
export { verify } from './verify.js';
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}

View File

@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verify = exports.getRandomValues = exports.digest = void 0;
/**
* A runtime-agnostic collection of methods for working with the WebCrypto API
* @module
*/
var digest_js_1 = require("./digest.js");
Object.defineProperty(exports, "digest", { enumerable: true, get: function () { return digest_js_1.digest; } });
var getRandomValues_js_1 = require("./getRandomValues.js");
Object.defineProperty(exports, "getRandomValues", { enumerable: true, get: function () { return getRandomValues_js_1.getRandomValues; } });
var verify_js_1 = require("./verify.js");
Object.defineProperty(exports, "verify", { enumerable: true, get: function () { return verify_js_1.verify; } });

View File

@@ -0,0 +1,7 @@
import { SubtleCryptoAlg } from './structs.js';
import { COSEALG } from '../../cose.js';
/**
* Convert a COSE alg ID into a corresponding string value that WebCrypto APIs expect
*/
export declare function mapCoseAlgToWebCryptoAlg(alg: COSEALG): SubtleCryptoAlg;
//# sourceMappingURL=mapCoseAlgToWebCryptoAlg.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"mapCoseAlgToWebCryptoAlg.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoAlg.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,CAetE"}

View File

@@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapCoseAlgToWebCryptoAlg = mapCoseAlgToWebCryptoAlg;
const cose_js_1 = require("../../cose.js");
/**
* Convert a COSE alg ID into a corresponding string value that WebCrypto APIs expect
*/
function mapCoseAlgToWebCryptoAlg(alg) {
if ([cose_js_1.COSEALG.RS1].indexOf(alg) >= 0) {
return 'SHA-1';
}
else if ([cose_js_1.COSEALG.ES256, cose_js_1.COSEALG.PS256, cose_js_1.COSEALG.RS256].indexOf(alg) >= 0) {
return 'SHA-256';
}
else if ([cose_js_1.COSEALG.ES384, cose_js_1.COSEALG.PS384, cose_js_1.COSEALG.RS384].indexOf(alg) >= 0) {
return 'SHA-384';
}
else if ([cose_js_1.COSEALG.ES512, cose_js_1.COSEALG.PS512, cose_js_1.COSEALG.RS512, cose_js_1.COSEALG.EdDSA].indexOf(alg) >=
0) {
return 'SHA-512';
}
throw new Error(`Could not map COSE alg value of ${alg} to a WebCrypto alg`);
}

View File

@@ -0,0 +1,7 @@
import { COSEALG } from '../../cose.js';
import { SubtleCryptoKeyAlgName } from './structs.js';
/**
* Convert a COSE alg ID into a corresponding key algorithm string value that WebCrypto APIs expect
*/
export declare function mapCoseAlgToWebCryptoKeyAlgName(alg: COSEALG): SubtleCryptoKeyAlgName;
//# sourceMappingURL=mapCoseAlgToWebCryptoKeyAlgName.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"mapCoseAlgToWebCryptoKeyAlgName.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoKeyAlgName.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAEtD;;GAEG;AACH,wBAAgB,+BAA+B,CAC7C,GAAG,EAAE,OAAO,GACX,sBAAsB,CAoBxB"}

View File

@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapCoseAlgToWebCryptoKeyAlgName = mapCoseAlgToWebCryptoKeyAlgName;
const cose_js_1 = require("../../cose.js");
/**
* Convert a COSE alg ID into a corresponding key algorithm string value that WebCrypto APIs expect
*/
function mapCoseAlgToWebCryptoKeyAlgName(alg) {
if ([cose_js_1.COSEALG.EdDSA].indexOf(alg) >= 0) {
return 'Ed25519';
}
else if ([cose_js_1.COSEALG.ES256, cose_js_1.COSEALG.ES384, cose_js_1.COSEALG.ES512, cose_js_1.COSEALG.ES256K].indexOf(alg) >= 0) {
return 'ECDSA';
}
else if ([cose_js_1.COSEALG.RS256, cose_js_1.COSEALG.RS384, cose_js_1.COSEALG.RS512, cose_js_1.COSEALG.RS1].indexOf(alg) >= 0) {
return 'RSASSA-PKCS1-v1_5';
}
else if ([cose_js_1.COSEALG.PS256, cose_js_1.COSEALG.PS384, cose_js_1.COSEALG.PS512].indexOf(alg) >= 0) {
return 'RSA-PSS';
}
throw new Error(`Could not map COSE alg value of ${alg} to a WebCrypto key alg name`);
}

View File

@@ -0,0 +1,4 @@
export type SubtleCryptoAlg = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
export type SubtleCryptoCrv = 'P-256' | 'P-384' | 'P-521' | 'Ed25519';
export type SubtleCryptoKeyAlgName = 'ECDSA' | 'Ed25519' | 'RSASSA-PKCS1-v1_5' | 'RSA-PSS';
//# sourceMappingURL=structs.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"structs.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/structs.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAC1E,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AACtE,MAAM,MAAM,sBAAsB,GAC9B,OAAO,GACP,SAAS,GACT,mBAAmB,GACnB,SAAS,CAAC"}

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,8 @@
import { COSECRV } from '../../cose.js';
/**
* In WebAuthn, EC2 signatures are wrapped in ASN.1 structure so we need to peel r and s apart.
*
* See https://www.w3.org/TR/webauthn-2/#sctn-signature-attestation-types
*/
export declare function unwrapEC2Signature(signature: Uint8Array, crv: COSECRV): Uint8Array;
//# sourceMappingURL=unwrapEC2Signature.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"unwrapEC2Signature.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/unwrapEC2Signature.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxC;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,GAAG,UAAU,CAelF"}

View File

@@ -0,0 +1,76 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.unwrapEC2Signature = unwrapEC2Signature;
const asn1_schema_1 = require("@peculiar/asn1-schema");
const asn1_ecc_1 = require("@peculiar/asn1-ecc");
const cose_js_1 = require("../../cose.js");
const index_js_1 = require("../index.js");
/**
* In WebAuthn, EC2 signatures are wrapped in ASN.1 structure so we need to peel r and s apart.
*
* See https://www.w3.org/TR/webauthn-2/#sctn-signature-attestation-types
*/
function unwrapEC2Signature(signature, crv) {
const parsedSignature = asn1_schema_1.AsnParser.parse(signature, asn1_ecc_1.ECDSASigValue);
const rBytes = new Uint8Array(parsedSignature.r);
const sBytes = new Uint8Array(parsedSignature.s);
const componentLength = getSignatureComponentLength(crv);
const rNormalizedBytes = toNormalizedBytes(rBytes, componentLength);
const sNormalizedBytes = toNormalizedBytes(sBytes, componentLength);
const finalSignature = index_js_1.isoUint8Array.concat([
rNormalizedBytes,
sNormalizedBytes,
]);
return finalSignature;
}
/**
* The SubtleCrypto Web Crypto API expects ECDSA signatures with `r` and `s` values to be encoded
* to a specific length depending on the order of the curve. This function returns the expected
* byte-length for each of the `r` and `s` signature components.
*
* See <https://www.w3.org/TR/WebCryptoAPI/#ecdsa-operations>
*/
function getSignatureComponentLength(crv) {
switch (crv) {
case cose_js_1.COSECRV.P256:
return 32;
case cose_js_1.COSECRV.P384:
return 48;
case cose_js_1.COSECRV.P521:
return 66;
default:
throw new Error(`Unexpected COSE crv value of ${crv} (EC2)`);
}
}
/**
* Converts the ASN.1 integer representation to bytes of a specific length `n`.
*
* DER encodes integers as big-endian byte arrays, with as small as possible representation and
* requires a leading `0` byte to disambiguate between negative and positive numbers. This means
* that `r` and `s` can potentially not be the expected byte-length that is needed by the
* SubtleCrypto Web Crypto API: if there are leading `0`s it can be shorter than expected, and if
* it has a leading `1` bit, it can be one byte longer.
*
* See <https://www.itu.int/rec/T-REC-X.690-202102-I/en>
* See <https://www.w3.org/TR/WebCryptoAPI/#ecdsa-operations>
*/
function toNormalizedBytes(bytes, componentLength) {
let normalizedBytes;
if (bytes.length < componentLength) {
// In case the bytes are shorter than expected, we need to pad it with leading `0`s.
normalizedBytes = new Uint8Array(componentLength);
normalizedBytes.set(bytes, componentLength - bytes.length);
}
else if (bytes.length === componentLength) {
normalizedBytes = bytes;
}
else if (bytes.length === componentLength + 1 && bytes[0] === 0 && (bytes[1] & 0x80) === 0x80) {
// The bytes contain a leading `0` to encode that the integer is positive. This leading `0`
// needs to be removed for compatibility with the SubtleCrypto Web Crypto API.
normalizedBytes = bytes.subarray(1);
}
else {
throw new Error(`Invalid signature component length ${bytes.length}, expected ${componentLength}`);
}
return normalizedBytes;
}

View File

@@ -0,0 +1,11 @@
import { COSEALG, COSEPublicKey } from '../../cose.js';
/**
* Verify signatures with their public key. Supports EC2 and RSA public keys.
*/
export declare function verify(opts: {
cosePublicKey: COSEPublicKey;
signature: Uint8Array;
data: Uint8Array;
shaHashOverride?: COSEALG;
}): Promise<boolean>;
//# sourceMappingURL=verify.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAEP,aAAa,EAKd,MAAM,eAAe,CAAC;AAMvB;;GAEG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE;IAC3B,aAAa,EAAE,aAAa,CAAC;IAC7B,SAAS,EAAE,UAAU,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GAAG,OAAO,CAAC,OAAO,CAAC,CAyBnB"}

View File

@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verify = verify;
const cose_js_1 = require("../../cose.js");
const verifyEC2_js_1 = require("./verifyEC2.js");
const verifyRSA_js_1 = require("./verifyRSA.js");
const verifyOKP_js_1 = require("./verifyOKP.js");
const unwrapEC2Signature_js_1 = require("./unwrapEC2Signature.js");
/**
* Verify signatures with their public key. Supports EC2 and RSA public keys.
*/
function verify(opts) {
const { cosePublicKey, signature, data, shaHashOverride } = opts;
if ((0, cose_js_1.isCOSEPublicKeyEC2)(cosePublicKey)) {
const crv = cosePublicKey.get(cose_js_1.COSEKEYS.crv);
if (!(0, cose_js_1.isCOSECrv)(crv)) {
throw new Error(`unknown COSE curve ${crv}`);
}
const unwrappedSignature = (0, unwrapEC2Signature_js_1.unwrapEC2Signature)(signature, crv);
return (0, verifyEC2_js_1.verifyEC2)({
cosePublicKey,
signature: unwrappedSignature,
data,
shaHashOverride,
});
}
else if ((0, cose_js_1.isCOSEPublicKeyRSA)(cosePublicKey)) {
return (0, verifyRSA_js_1.verifyRSA)({ cosePublicKey, signature, data, shaHashOverride });
}
else if ((0, cose_js_1.isCOSEPublicKeyOKP)(cosePublicKey)) {
return (0, verifyOKP_js_1.verifyOKP)({ cosePublicKey, signature, data });
}
const kty = cosePublicKey.get(cose_js_1.COSEKEYS.kty);
throw new Error(`Signature verification with public key of kty ${kty} is not supported by this method`);
}

View File

@@ -0,0 +1,11 @@
import { COSEALG, COSEPublicKeyEC2 } from '../../cose.js';
/**
* Verify a signature using an EC2 public key
*/
export declare function verifyEC2(opts: {
cosePublicKey: COSEPublicKeyEC2;
signature: Uint8Array;
data: Uint8Array;
shaHashOverride?: COSEALG;
}): Promise<boolean>;
//# sourceMappingURL=verifyEC2.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"verifyEC2.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/verifyEC2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAqB,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAO7E;;GAEG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,aAAa,EAAE,gBAAgB,CAAC;IAChC,SAAS,EAAE,UAAU,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GAAG,OAAO,CAAC,OAAO,CAAC,CA0EnB"}

View File

@@ -0,0 +1,76 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyEC2 = verifyEC2;
const cose_js_1 = require("../../cose.js");
const mapCoseAlgToWebCryptoAlg_js_1 = require("./mapCoseAlgToWebCryptoAlg.js");
const importKey_js_1 = require("./importKey.js");
const index_js_1 = require("../index.js");
const getWebCrypto_js_1 = require("./getWebCrypto.js");
/**
* Verify a signature using an EC2 public key
*/
async function verifyEC2(opts) {
const { cosePublicKey, signature, data, shaHashOverride } = opts;
const WebCrypto = await (0, getWebCrypto_js_1.getWebCrypto)();
// Import the public key
const alg = cosePublicKey.get(cose_js_1.COSEKEYS.alg);
const crv = cosePublicKey.get(cose_js_1.COSEKEYS.crv);
const x = cosePublicKey.get(cose_js_1.COSEKEYS.x);
const y = cosePublicKey.get(cose_js_1.COSEKEYS.y);
if (!alg) {
throw new Error('Public key was missing alg (EC2)');
}
if (!crv) {
throw new Error('Public key was missing crv (EC2)');
}
if (!x) {
throw new Error('Public key was missing x (EC2)');
}
if (!y) {
throw new Error('Public key was missing y (EC2)');
}
let _crv;
if (crv === cose_js_1.COSECRV.P256) {
_crv = 'P-256';
}
else if (crv === cose_js_1.COSECRV.P384) {
_crv = 'P-384';
}
else if (crv === cose_js_1.COSECRV.P521) {
_crv = 'P-521';
}
else {
throw new Error(`Unexpected COSE crv value of ${crv} (EC2)`);
}
const keyData = {
kty: 'EC',
crv: _crv,
x: index_js_1.isoBase64URL.fromBuffer(x),
y: index_js_1.isoBase64URL.fromBuffer(y),
ext: false,
};
const keyAlgorithm = {
/**
* Note to future self: you can't use `mapCoseAlgToWebCryptoKeyAlgName()` here because some
* leaf certs from actual devices specified an RSA SHA value for `alg` (e.g. `-257`) which
* would then map here to `'RSASSA-PKCS1-v1_5'`. We always want `'ECDSA'` here so we'll
* hard-code this.
*/
name: 'ECDSA',
namedCurve: _crv,
};
const key = await (0, importKey_js_1.importKey)({
keyData,
algorithm: keyAlgorithm,
});
// Determine which SHA algorithm to use for signature verification
let subtleAlg = (0, mapCoseAlgToWebCryptoAlg_js_1.mapCoseAlgToWebCryptoAlg)(alg);
if (shaHashOverride) {
subtleAlg = (0, mapCoseAlgToWebCryptoAlg_js_1.mapCoseAlgToWebCryptoAlg)(shaHashOverride);
}
const verifyAlgorithm = {
name: 'ECDSA',
hash: { name: subtleAlg },
};
return WebCrypto.subtle.verify(verifyAlgorithm, key, signature, data);
}

View File

@@ -0,0 +1,7 @@
import { COSEPublicKeyOKP } from '../../cose.js';
export declare function verifyOKP(opts: {
cosePublicKey: COSEPublicKeyOKP;
signature: Uint8Array;
data: Uint8Array;
}): Promise<boolean>;
//# sourceMappingURL=verifyOKP.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"verifyOKP.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/verifyOKP.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,gBAAgB,EAAa,MAAM,eAAe,CAAC;AAM/E,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,aAAa,EAAE,gBAAgB,CAAC;IAChC,SAAS,EAAE,UAAU,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;CAClB,GAAG,OAAO,CAAC,OAAO,CAAC,CAyDnB"}

View File

@@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyOKP = verifyOKP;
const cose_js_1 = require("../../cose.js");
const index_js_1 = require("../../index.js");
const importKey_js_1 = require("./importKey.js");
const getWebCrypto_js_1 = require("./getWebCrypto.js");
async function verifyOKP(opts) {
const { cosePublicKey, signature, data } = opts;
const WebCrypto = await (0, getWebCrypto_js_1.getWebCrypto)();
const alg = cosePublicKey.get(cose_js_1.COSEKEYS.alg);
const crv = cosePublicKey.get(cose_js_1.COSEKEYS.crv);
const x = cosePublicKey.get(cose_js_1.COSEKEYS.x);
if (!alg) {
throw new Error('Public key was missing alg (OKP)');
}
if (!(0, cose_js_1.isCOSEAlg)(alg)) {
throw new Error(`Public key had invalid alg ${alg} (OKP)`);
}
if (!crv) {
throw new Error('Public key was missing crv (OKP)');
}
if (!x) {
throw new Error('Public key was missing x (OKP)');
}
// Pulled key import steps from here:
// https://wicg.github.io/webcrypto-secure-curves/#ed25519-operations
let _crv;
if (crv === cose_js_1.COSECRV.ED25519) {
_crv = 'Ed25519';
}
else {
throw new Error(`Unexpected COSE crv value of ${crv} (OKP)`);
}
const keyData = {
kty: 'OKP',
crv: _crv,
alg: 'EdDSA',
x: index_js_1.isoBase64URL.fromBuffer(x),
ext: false,
};
const keyAlgorithm = {
name: _crv,
namedCurve: _crv,
};
const key = await (0, importKey_js_1.importKey)({
keyData,
algorithm: keyAlgorithm,
});
const verifyAlgorithm = {
name: _crv,
};
return WebCrypto.subtle.verify(verifyAlgorithm, key, signature, data);
}

View File

@@ -0,0 +1,11 @@
import { COSEALG, COSEPublicKeyRSA } from '../../cose.js';
/**
* Verify a signature using an RSA public key
*/
export declare function verifyRSA(opts: {
cosePublicKey: COSEPublicKeyRSA;
signature: Uint8Array;
data: Uint8Array;
shaHashOverride?: COSEALG;
}): Promise<boolean>;
//# sourceMappingURL=verifyRSA.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"verifyRSA.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/verifyRSA.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAY,gBAAgB,EAAa,MAAM,eAAe,CAAC;AAO/E;;GAEG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,aAAa,EAAE,gBAAgB,CAAC;IAChC,SAAS,EAAE,UAAU,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GAAG,OAAO,CAAC,OAAO,CAAC,CA2FnB"}

View File

@@ -0,0 +1,94 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyRSA = verifyRSA;
const cose_js_1 = require("../../cose.js");
const mapCoseAlgToWebCryptoAlg_js_1 = require("./mapCoseAlgToWebCryptoAlg.js");
const importKey_js_1 = require("./importKey.js");
const index_js_1 = require("../index.js");
const mapCoseAlgToWebCryptoKeyAlgName_js_1 = require("./mapCoseAlgToWebCryptoKeyAlgName.js");
const getWebCrypto_js_1 = require("./getWebCrypto.js");
/**
* Verify a signature using an RSA public key
*/
async function verifyRSA(opts) {
const { cosePublicKey, signature, data, shaHashOverride } = opts;
const WebCrypto = await (0, getWebCrypto_js_1.getWebCrypto)();
const alg = cosePublicKey.get(cose_js_1.COSEKEYS.alg);
const n = cosePublicKey.get(cose_js_1.COSEKEYS.n);
const e = cosePublicKey.get(cose_js_1.COSEKEYS.e);
if (!alg) {
throw new Error('Public key was missing alg (RSA)');
}
if (!(0, cose_js_1.isCOSEAlg)(alg)) {
throw new Error(`Public key had invalid alg ${alg} (RSA)`);
}
if (!n) {
throw new Error('Public key was missing n (RSA)');
}
if (!e) {
throw new Error('Public key was missing e (RSA)');
}
const keyData = {
kty: 'RSA',
alg: '',
n: index_js_1.isoBase64URL.fromBuffer(n),
e: index_js_1.isoBase64URL.fromBuffer(e),
ext: false,
};
const keyAlgorithm = {
name: (0, mapCoseAlgToWebCryptoKeyAlgName_js_1.mapCoseAlgToWebCryptoKeyAlgName)(alg),
hash: { name: (0, mapCoseAlgToWebCryptoAlg_js_1.mapCoseAlgToWebCryptoAlg)(alg) },
};
const verifyAlgorithm = {
name: (0, mapCoseAlgToWebCryptoKeyAlgName_js_1.mapCoseAlgToWebCryptoKeyAlgName)(alg),
};
if (shaHashOverride) {
keyAlgorithm.hash.name = (0, mapCoseAlgToWebCryptoAlg_js_1.mapCoseAlgToWebCryptoAlg)(shaHashOverride);
}
if (keyAlgorithm.name === 'RSASSA-PKCS1-v1_5') {
if (keyAlgorithm.hash.name === 'SHA-256') {
keyData.alg = 'RS256';
}
else if (keyAlgorithm.hash.name === 'SHA-384') {
keyData.alg = 'RS384';
}
else if (keyAlgorithm.hash.name === 'SHA-512') {
keyData.alg = 'RS512';
}
else if (keyAlgorithm.hash.name === 'SHA-1') {
keyData.alg = 'RS1';
}
}
else if (keyAlgorithm.name === 'RSA-PSS') {
/**
* salt length. The default value is 20 but the convention is to use hLen, the length of the
* output of the hash function in bytes. A salt length of zero is permitted and will result in
* a deterministic signature value. The actual salt length used can be determined from the
* signature value.
*
* From https://www.cryptosys.net/pki/manpki/pki_rsaschemes.html
*/
let saltLength = 0;
if (keyAlgorithm.hash.name === 'SHA-256') {
keyData.alg = 'PS256';
saltLength = 32; // 256 bits => 32 bytes
}
else if (keyAlgorithm.hash.name === 'SHA-384') {
keyData.alg = 'PS384';
saltLength = 48; // 384 bits => 48 bytes
}
else if (keyAlgorithm.hash.name === 'SHA-512') {
keyData.alg = 'PS512';
saltLength = 64; // 512 bits => 64 bytes
}
verifyAlgorithm.saltLength = saltLength;
}
else {
throw new Error(`Unexpected RSA key algorithm ${alg} (${keyAlgorithm.name})`);
}
const key = await (0, importKey_js_1.importKey)({
keyData,
algorithm: keyAlgorithm,
});
return WebCrypto.subtle.verify(verifyAlgorithm, key, signature, data);
}

View File

@@ -0,0 +1,41 @@
/**
* A runtime-agnostic collection of methods for working with Uint8Arrays
* @module
*/
/**
* Make sure two Uint8Arrays are deeply equivalent
*/
export declare function areEqual(array1: Uint8Array, array2: Uint8Array): boolean;
/**
* Convert a Uint8Array to Hexadecimal.
*
* A replacement for `Buffer.toString('hex')`
*/
export declare function toHex(array: Uint8Array): string;
/**
* Convert a hexadecimal string to isoUint8Array.
*
* A replacement for `Buffer.from('...', 'hex')`
*/
export declare function fromHex(hex: string): Uint8Array;
/**
* Combine multiple Uint8Arrays into a single Uint8Array
*/
export declare function concat(arrays: Uint8Array[]): Uint8Array;
/**
* Convert bytes into a UTF-8 string
*/
export declare function toUTF8String(array: Uint8Array): string;
/**
* Convert a UTF-8 string back into bytes
*/
export declare function fromUTF8String(utf8String: string): Uint8Array;
/**
* Convert an ASCII string to Uint8Array
*/
export declare function fromASCIIString(value: string): Uint8Array;
/**
* Prepare a DataView we can slice our way around in as we parse the bytes in a Uint8Array
*/
export declare function toDataView(array: Uint8Array): DataView;
//# sourceMappingURL=isoUint8Array.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"isoUint8Array.d.ts","sourceRoot":"","sources":["../../../src/helpers/iso/isoUint8Array.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAMxE;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAK/C;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAe/C;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,UAAU,CAYvD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAGtD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,CAG7D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAEzD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,QAAQ,CAEtD"}

View File

@@ -0,0 +1,89 @@
"use strict";
/**
* A runtime-agnostic collection of methods for working with Uint8Arrays
* @module
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.areEqual = areEqual;
exports.toHex = toHex;
exports.fromHex = fromHex;
exports.concat = concat;
exports.toUTF8String = toUTF8String;
exports.fromUTF8String = fromUTF8String;
exports.fromASCIIString = fromASCIIString;
exports.toDataView = toDataView;
/**
* Make sure two Uint8Arrays are deeply equivalent
*/
function areEqual(array1, array2) {
if (array1.length != array2.length) {
return false;
}
return array1.every((val, i) => val === array2[i]);
}
/**
* Convert a Uint8Array to Hexadecimal.
*
* A replacement for `Buffer.toString('hex')`
*/
function toHex(array) {
const hexParts = Array.from(array, (i) => i.toString(16).padStart(2, '0'));
// adce000235bcc60a648b0b25f1f05503
return hexParts.join('');
}
/**
* Convert a hexadecimal string to isoUint8Array.
*
* A replacement for `Buffer.from('...', 'hex')`
*/
function fromHex(hex) {
if (!hex) {
return Uint8Array.from([]);
}
const isValid = hex.length !== 0 && hex.length % 2 === 0 &&
!/[^a-fA-F0-9]/u.test(hex);
if (!isValid) {
throw new Error('Invalid hex string');
}
const byteStrings = hex.match(/.{1,2}/g) ?? [];
return Uint8Array.from(byteStrings.map((byte) => parseInt(byte, 16)));
}
/**
* Combine multiple Uint8Arrays into a single Uint8Array
*/
function concat(arrays) {
let pointer = 0;
const totalLength = arrays.reduce((prev, curr) => prev + curr.length, 0);
const toReturn = new Uint8Array(totalLength);
arrays.forEach((arr) => {
toReturn.set(arr, pointer);
pointer += arr.length;
});
return toReturn;
}
/**
* Convert bytes into a UTF-8 string
*/
function toUTF8String(array) {
const decoder = new globalThis.TextDecoder('utf-8');
return decoder.decode(array);
}
/**
* Convert a UTF-8 string back into bytes
*/
function fromUTF8String(utf8String) {
const encoder = new globalThis.TextEncoder();
return encoder.encode(utf8String);
}
/**
* Convert an ASCII string to Uint8Array
*/
function fromASCIIString(value) {
return Uint8Array.from(value.split('').map((x) => x.charCodeAt(0)));
}
/**
* Prepare a DataView we can slice our way around in as we parse the bytes in a Uint8Array
*/
function toDataView(array) {
return new DataView(array.buffer, array.byteOffset, array.length);
}