update electron to v43

This commit is contained in:
olcxja 2026-07-09 22:38:33 +02:00
commit fb6c8b6ee9
5385 changed files with 513060 additions and 123058 deletions

21
electron/node_modules/@peculiar/asn1-schema/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

51
electron/node_modules/@peculiar/asn1-schema/README.md generated vendored Normal file
View file

@ -0,0 +1,51 @@
# `@peculiar/asn1-schema`
[![License](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/PeculiarVentures/asn1-schema/blob/master/packages/schema/LICENSE)
[![npm version](https://badge.fury.io/js/%40peculiar%2Fasn1-schema.svg)](https://badge.fury.io/js/%40peculiar%2Fasn1-schema)
[![NPM](https://nodei.co/npm/@peculiar/asn1-schema.png)](https://nodei.co/npm/@peculiar/asn1-schema/)
Decorators and helper APIs for declaring ASN.1 schemas in TypeScript.
This is the core package used by the schema modules in this repository. It lets you describe DER structures with decorators and convert them with `AsnConvert`, `AsnParser`, and `AsnSerializer`.
## Installation
```bash
npm install @peculiar/asn1-schema
```
## Overview
Abstract Syntax Notation One (ASN.1) is widely used across X.509, PKCS, CMS, OCSP, and related standards. This package keeps those mappings declarative and type-friendly by attaching schema metadata directly to classes.
## TypeScript Example
```ts
import {
AsnConvert,
AsnProp,
AsnPropTypes,
AsnType,
AsnTypeTypes,
} from "@peculiar/asn1-schema";
@AsnType({ type: AsnTypeTypes.Sequence })
class BasicConstraints {
@AsnProp({ type: AsnPropTypes.Boolean, defaultValue: false })
public cA = false;
}
const basicConstraints = new BasicConstraints();
basicConstraints.cA = true;
const encoded = AsnConvert.serialize(basicConstraints);
const decoded = AsnConvert.parse(encoded, BasicConstraints);
console.log(decoded.cA);
```
## Related Links
- [Decorators overview](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841)
- [ASN.1 playground](http://lapo.it/asn1js/)

View file

@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsnConvert = void 0;
const tslib_1 = require("tslib");
const asn1js = tslib_1.__importStar(require("asn1js"));
const bytes_1 = require("@peculiar/utils/bytes");
const parser_1 = require("./parser");
const serializer_1 = require("./serializer");
class AsnConvert {
static serialize(obj) {
return serializer_1.AsnSerializer.serialize(obj);
}
static parse(data, target, options) {
return parser_1.AsnParser.parse(data, target, options);
}
static toString(data, options) {
const buf = (0, bytes_1.isBufferSource)(data)
? (0, bytes_1.toArrayBuffer)(data)
: AsnConvert.serialize(data);
const asn = asn1js.fromBER(buf, options?.berOptions);
if (asn.offset === -1) {
throw new Error(`Cannot decode ASN.1 data. ${asn.result.error}`);
}
return asn.result.toString();
}
}
exports.AsnConvert = AsnConvert;

View file

@ -0,0 +1,144 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsnNullConverter = exports.AsnGeneralizedTimeConverter = exports.AsnUTCTimeConverter = exports.AsnCharacterStringConverter = exports.AsnGeneralStringConverter = exports.AsnVisibleStringConverter = exports.AsnGraphicStringConverter = exports.AsnIA5StringConverter = exports.AsnVideotexStringConverter = exports.AsnTeletexStringConverter = exports.AsnPrintableStringConverter = exports.AsnNumericStringConverter = exports.AsnUniversalStringConverter = exports.AsnBmpStringConverter = exports.AsnUtf8StringConverter = exports.AsnConstructedOctetStringConverter = exports.AsnOctetStringConverter = exports.AsnBooleanConverter = exports.AsnObjectIdentifierConverter = exports.AsnBitStringConverter = exports.AsnIntegerBigIntConverter = exports.AsnIntegerArrayBufferConverter = exports.AsnEnumeratedConverter = exports.AsnIntegerConverter = exports.AsnAnyConverter = void 0;
exports.defaultConverter = defaultConverter;
const tslib_1 = require("tslib");
const asn1js = tslib_1.__importStar(require("asn1js"));
const bytes_1 = require("@peculiar/utils/bytes");
const enums_1 = require("./enums");
const index_1 = require("./types/index");
exports.AsnAnyConverter = {
fromASN: (value) => value instanceof asn1js.Null
? null
: (0, bytes_1.toArrayBuffer)(value.valueBeforeDecodeView),
toASN: (value) => {
if (value === null) {
return new asn1js.Null();
}
const schema = asn1js.fromBER(value);
if (schema.result.error) {
throw new Error(schema.result.error);
}
return schema.result;
},
};
exports.AsnIntegerConverter = {
fromASN: (value) => value.valueBlock.valueHexView.byteLength >= 4
? value.valueBlock.toString()
: value.valueBlock.valueDec,
toASN: (value) => new asn1js.Integer({ value: +value }),
};
exports.AsnEnumeratedConverter = {
fromASN: (value) => value.valueBlock.valueDec,
toASN: (value) => new asn1js.Enumerated({ value }),
};
exports.AsnIntegerArrayBufferConverter = {
fromASN: (value) => (0, bytes_1.toArrayBuffer)(value.valueBlock.valueHexView),
toASN: (value) => new asn1js.Integer({ valueHex: value }),
};
exports.AsnIntegerBigIntConverter = {
fromASN: (value) => value.toBigInt(),
toASN: (value) => asn1js.Integer.fromBigInt(value),
};
exports.AsnBitStringConverter = {
fromASN: (value) => (0, bytes_1.toArrayBuffer)(value.valueBlock.valueHexView),
toASN: (value) => new asn1js.BitString({ valueHex: value }),
};
exports.AsnObjectIdentifierConverter = {
fromASN: (value) => value.valueBlock.toString(),
toASN: (value) => new asn1js.ObjectIdentifier({ value }),
};
exports.AsnBooleanConverter = {
fromASN: (value) => value.valueBlock.value,
toASN: (value) => new asn1js.Boolean({ value }),
};
exports.AsnOctetStringConverter = {
fromASN: (value) => (0, bytes_1.toArrayBuffer)(value.valueBlock.valueHexView),
toASN: (value) => new asn1js.OctetString({ valueHex: value }),
};
exports.AsnConstructedOctetStringConverter = {
fromASN: (value) => new index_1.OctetString(value.getValue()),
toASN: (value) => value.toASN(),
};
function createStringConverter(Asn1Type) {
return {
fromASN: (value) => value.valueBlock.value,
toASN: (value) => new Asn1Type({ value }),
};
}
exports.AsnUtf8StringConverter = createStringConverter(asn1js.Utf8String);
exports.AsnBmpStringConverter = createStringConverter(asn1js.BmpString);
exports.AsnUniversalStringConverter = createStringConverter(asn1js.UniversalString);
exports.AsnNumericStringConverter = createStringConverter(asn1js.NumericString);
exports.AsnPrintableStringConverter = createStringConverter(asn1js.PrintableString);
exports.AsnTeletexStringConverter = createStringConverter(asn1js.TeletexString);
exports.AsnVideotexStringConverter = createStringConverter(asn1js.VideotexString);
exports.AsnIA5StringConverter = createStringConverter(asn1js.IA5String);
exports.AsnGraphicStringConverter = createStringConverter(asn1js.GraphicString);
exports.AsnVisibleStringConverter = createStringConverter(asn1js.VisibleString);
exports.AsnGeneralStringConverter = createStringConverter(asn1js.GeneralString);
exports.AsnCharacterStringConverter = createStringConverter(asn1js.CharacterString);
exports.AsnUTCTimeConverter = {
fromASN: (value) => value.toDate(),
toASN: (value) => new asn1js.UTCTime({ valueDate: value }),
};
exports.AsnGeneralizedTimeConverter = {
fromASN: (value) => value.toDate(),
toASN: (value) => new asn1js.GeneralizedTime({ valueDate: value }),
};
exports.AsnNullConverter = {
fromASN: () => null,
toASN: () => {
return new asn1js.Null();
},
};
function defaultConverter(type) {
switch (type) {
case enums_1.AsnPropTypes.Any:
return exports.AsnAnyConverter;
case enums_1.AsnPropTypes.BitString:
return exports.AsnBitStringConverter;
case enums_1.AsnPropTypes.BmpString:
return exports.AsnBmpStringConverter;
case enums_1.AsnPropTypes.Boolean:
return exports.AsnBooleanConverter;
case enums_1.AsnPropTypes.CharacterString:
return exports.AsnCharacterStringConverter;
case enums_1.AsnPropTypes.Enumerated:
return exports.AsnEnumeratedConverter;
case enums_1.AsnPropTypes.GeneralString:
return exports.AsnGeneralStringConverter;
case enums_1.AsnPropTypes.GeneralizedTime:
return exports.AsnGeneralizedTimeConverter;
case enums_1.AsnPropTypes.GraphicString:
return exports.AsnGraphicStringConverter;
case enums_1.AsnPropTypes.IA5String:
return exports.AsnIA5StringConverter;
case enums_1.AsnPropTypes.Integer:
return exports.AsnIntegerConverter;
case enums_1.AsnPropTypes.Null:
return exports.AsnNullConverter;
case enums_1.AsnPropTypes.NumericString:
return exports.AsnNumericStringConverter;
case enums_1.AsnPropTypes.ObjectIdentifier:
return exports.AsnObjectIdentifierConverter;
case enums_1.AsnPropTypes.OctetString:
return exports.AsnOctetStringConverter;
case enums_1.AsnPropTypes.PrintableString:
return exports.AsnPrintableStringConverter;
case enums_1.AsnPropTypes.TeletexString:
return exports.AsnTeletexStringConverter;
case enums_1.AsnPropTypes.UTCTime:
return exports.AsnUTCTimeConverter;
case enums_1.AsnPropTypes.UniversalString:
return exports.AsnUniversalStringConverter;
case enums_1.AsnPropTypes.Utf8String:
return exports.AsnUtf8StringConverter;
case enums_1.AsnPropTypes.VideotexString:
return exports.AsnVideotexStringConverter;
case enums_1.AsnPropTypes.VisibleString:
return exports.AsnVisibleStringConverter;
default:
return null;
}
}

View file

@ -0,0 +1,50 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsnProp = exports.AsnSequenceType = exports.AsnSetType = exports.AsnChoiceType = exports.AsnType = void 0;
const tslib_1 = require("tslib");
const converters = tslib_1.__importStar(require("./converters"));
const enums_1 = require("./enums");
const storage_1 = require("./storage");
const AsnType = (options) => (target) => {
let schema;
if (!storage_1.schemaStorage.has(target)) {
schema = storage_1.schemaStorage.createDefault(target);
storage_1.schemaStorage.set(target, schema);
}
else {
schema = storage_1.schemaStorage.get(target);
}
Object.assign(schema, options);
};
exports.AsnType = AsnType;
const AsnChoiceType = () => (0, exports.AsnType)({ type: enums_1.AsnTypeTypes.Choice });
exports.AsnChoiceType = AsnChoiceType;
const AsnSetType = (options) => (0, exports.AsnType)({
type: enums_1.AsnTypeTypes.Set, ...options,
});
exports.AsnSetType = AsnSetType;
const AsnSequenceType = (options) => (0, exports.AsnType)({
type: enums_1.AsnTypeTypes.Sequence, ...options,
});
exports.AsnSequenceType = AsnSequenceType;
const AsnProp = (options) => (target, propertyKey) => {
let schema;
if (!storage_1.schemaStorage.has(target.constructor)) {
schema = storage_1.schemaStorage.createDefault(target.constructor);
storage_1.schemaStorage.set(target.constructor, schema);
}
else {
schema = storage_1.schemaStorage.get(target.constructor);
}
const copyOptions = Object.assign({}, options);
if (typeof copyOptions.type === "number" && !copyOptions.converter) {
const defaultConverter = converters.defaultConverter(options.type);
if (!defaultConverter) {
throw new Error(`Cannot get default converter for property '${propertyKey}' of ${target.constructor.name}`);
}
copyOptions.converter = defaultConverter;
}
copyOptions.raw = options.raw;
schema.items[propertyKey] = copyOptions;
};
exports.AsnProp = AsnProp;

View file

@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsnPropTypes = exports.AsnTypeTypes = void 0;
var AsnTypeTypes;
(function (AsnTypeTypes) {
AsnTypeTypes[AsnTypeTypes["Sequence"] = 0] = "Sequence";
AsnTypeTypes[AsnTypeTypes["Set"] = 1] = "Set";
AsnTypeTypes[AsnTypeTypes["Choice"] = 2] = "Choice";
})(AsnTypeTypes || (exports.AsnTypeTypes = AsnTypeTypes = {}));
var AsnPropTypes;
(function (AsnPropTypes) {
AsnPropTypes[AsnPropTypes["Any"] = 1] = "Any";
AsnPropTypes[AsnPropTypes["Boolean"] = 2] = "Boolean";
AsnPropTypes[AsnPropTypes["OctetString"] = 3] = "OctetString";
AsnPropTypes[AsnPropTypes["BitString"] = 4] = "BitString";
AsnPropTypes[AsnPropTypes["Integer"] = 5] = "Integer";
AsnPropTypes[AsnPropTypes["Enumerated"] = 6] = "Enumerated";
AsnPropTypes[AsnPropTypes["ObjectIdentifier"] = 7] = "ObjectIdentifier";
AsnPropTypes[AsnPropTypes["Utf8String"] = 8] = "Utf8String";
AsnPropTypes[AsnPropTypes["BmpString"] = 9] = "BmpString";
AsnPropTypes[AsnPropTypes["UniversalString"] = 10] = "UniversalString";
AsnPropTypes[AsnPropTypes["NumericString"] = 11] = "NumericString";
AsnPropTypes[AsnPropTypes["PrintableString"] = 12] = "PrintableString";
AsnPropTypes[AsnPropTypes["TeletexString"] = 13] = "TeletexString";
AsnPropTypes[AsnPropTypes["VideotexString"] = 14] = "VideotexString";
AsnPropTypes[AsnPropTypes["IA5String"] = 15] = "IA5String";
AsnPropTypes[AsnPropTypes["GraphicString"] = 16] = "GraphicString";
AsnPropTypes[AsnPropTypes["VisibleString"] = 17] = "VisibleString";
AsnPropTypes[AsnPropTypes["GeneralString"] = 18] = "GeneralString";
AsnPropTypes[AsnPropTypes["CharacterString"] = 19] = "CharacterString";
AsnPropTypes[AsnPropTypes["UTCTime"] = 20] = "UTCTime";
AsnPropTypes[AsnPropTypes["GeneralizedTime"] = 21] = "GeneralizedTime";
AsnPropTypes[AsnPropTypes["DATE"] = 22] = "DATE";
AsnPropTypes[AsnPropTypes["TimeOfDay"] = 23] = "TimeOfDay";
AsnPropTypes[AsnPropTypes["DateTime"] = 24] = "DateTime";
AsnPropTypes[AsnPropTypes["Duration"] = 25] = "Duration";
AsnPropTypes[AsnPropTypes["TIME"] = 26] = "TIME";
AsnPropTypes[AsnPropTypes["Null"] = 27] = "Null";
})(AsnPropTypes || (exports.AsnPropTypes = AsnPropTypes = {}));

View file

@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./schema_validation"), exports);

View file

@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsnSchemaValidationError = void 0;
class AsnSchemaValidationError extends Error {
schemas = [];
}
exports.AsnSchemaValidationError = AsnSchemaValidationError;

View file

@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isConvertible = isConvertible;
exports.isTypeOfArray = isTypeOfArray;
exports.isArrayEqual = isArrayEqual;
function isConvertible(target) {
if (typeof target === "function" && target.prototype) {
if (target.prototype.toASN && target.prototype.fromASN) {
return true;
}
else {
return isConvertible(target.prototype);
}
}
else {
return !!(target && typeof target === "object" && "toASN" in target && "fromASN" in target);
}
}
function isTypeOfArray(target) {
if (target) {
const proto = Object.getPrototypeOf(target);
if (proto?.prototype?.constructor === Array) {
return true;
}
return isTypeOfArray(proto);
}
return false;
}
function isArrayEqual(bytes1, bytes2) {
if (!(bytes1 && bytes2)) {
return false;
}
if (bytes1.byteLength !== bytes2.byteLength) {
return false;
}
const b1 = new Uint8Array(bytes1);
const b2 = new Uint8Array(bytes2);
for (let i = 0; i < bytes1.byteLength; i++) {
if (b1[i] !== b2[i]) {
return false;
}
}
return true;
}

View file

@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsnSerializer = exports.AsnParser = exports.AsnPropTypes = exports.AsnTypeTypes = exports.AsnSetType = exports.AsnSequenceType = exports.AsnChoiceType = exports.AsnType = exports.AsnProp = void 0;
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./converters"), exports);
tslib_1.__exportStar(require("./types/index"), exports);
var decorators_1 = require("./decorators");
Object.defineProperty(exports, "AsnProp", { enumerable: true, get: function () { return decorators_1.AsnProp; } });
Object.defineProperty(exports, "AsnType", { enumerable: true, get: function () { return decorators_1.AsnType; } });
Object.defineProperty(exports, "AsnChoiceType", { enumerable: true, get: function () { return decorators_1.AsnChoiceType; } });
Object.defineProperty(exports, "AsnSequenceType", { enumerable: true, get: function () { return decorators_1.AsnSequenceType; } });
Object.defineProperty(exports, "AsnSetType", { enumerable: true, get: function () { return decorators_1.AsnSetType; } });
var enums_1 = require("./enums");
Object.defineProperty(exports, "AsnTypeTypes", { enumerable: true, get: function () { return enums_1.AsnTypeTypes; } });
Object.defineProperty(exports, "AsnPropTypes", { enumerable: true, get: function () { return enums_1.AsnPropTypes; } });
var parser_1 = require("./parser");
Object.defineProperty(exports, "AsnParser", { enumerable: true, get: function () { return parser_1.AsnParser; } });
var serializer_1 = require("./serializer");
Object.defineProperty(exports, "AsnSerializer", { enumerable: true, get: function () { return serializer_1.AsnSerializer; } });
tslib_1.__exportStar(require("./errors"), exports);
tslib_1.__exportStar(require("./objects"), exports);
tslib_1.__exportStar(require("./convert"), exports);

View file

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsnArray = void 0;
class AsnArray extends Array {
constructor(items = []) {
if (typeof items === "number") {
super(items);
}
else {
super();
for (const item of items) {
this.push(item);
}
}
}
}
exports.AsnArray = AsnArray;

View file

@ -0,0 +1,331 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsnParser = void 0;
const tslib_1 = require("tslib");
const asn1js = tslib_1.__importStar(require("asn1js"));
const bytes_1 = require("@peculiar/utils/bytes");
const enums_1 = require("./enums");
const converters = tslib_1.__importStar(require("./converters"));
const errors_1 = require("./errors");
const helper_1 = require("./helper");
const storage_1 = require("./storage");
class AsnParser {
static parse(data, target, options) {
const asn1Parsed = asn1js.fromBER((0, bytes_1.toArrayBuffer)(data), options?.berOptions);
if (asn1Parsed.result.error) {
throw new Error(asn1Parsed.result.error);
}
const res = this.fromASN(asn1Parsed.result, target, options);
return res;
}
static fromASN(asn1Schema, target, options) {
try {
if ((0, helper_1.isConvertible)(target)) {
const value = new target();
return value.fromASN(asn1Schema);
}
const schema = storage_1.schemaStorage.get(target);
storage_1.schemaStorage.cache(target);
let targetSchema = schema.schema;
const choiceResult = this.handleChoiceTypes(asn1Schema, schema, target, targetSchema, options);
if (choiceResult?.result) {
return choiceResult.result;
}
if (choiceResult?.targetSchema) {
targetSchema = choiceResult.targetSchema;
}
const sequenceResult = this.handleSequenceTypes(asn1Schema, schema, target, targetSchema);
const res = new target();
if ((0, helper_1.isTypeOfArray)(target)) {
return this.handleArrayTypes(asn1Schema, schema, target, options);
}
this.processSchemaItems(schema, sequenceResult, res, options);
return res;
}
catch (error) {
if (error instanceof errors_1.AsnSchemaValidationError) {
error.schemas.push(target.name);
}
throw error;
}
}
static handleChoiceTypes(asn1Schema, schema, target, targetSchema, options) {
if (asn1Schema.constructor === asn1js.Constructed
&& schema.type === enums_1.AsnTypeTypes.Choice
&& asn1Schema.idBlock.tagClass === 3) {
for (const key in schema.items) {
const schemaItem = schema.items[key];
if (schemaItem.context === asn1Schema.idBlock.tagNumber && schemaItem.implicit) {
if (typeof schemaItem.type === "function"
&& storage_1.schemaStorage.has(schemaItem.type)) {
const fieldSchema = storage_1.schemaStorage.get(schemaItem.type);
if (fieldSchema && fieldSchema.type === enums_1.AsnTypeTypes.Sequence) {
const newSeq = new asn1js.Sequence();
if ("value" in asn1Schema.valueBlock
&& Array.isArray(asn1Schema.valueBlock.value)
&& "value" in newSeq.valueBlock) {
newSeq.valueBlock.value = asn1Schema.valueBlock.value;
const fieldValue = this.fromASN(newSeq, schemaItem.type, options);
const res = new target();
res[key] = fieldValue;
return { result: res };
}
}
}
}
}
}
else if (asn1Schema.constructor === asn1js.Constructed
&& schema.type !== enums_1.AsnTypeTypes.Choice) {
const newTargetSchema = new asn1js.Constructed({
idBlock: {
tagClass: 3,
tagNumber: asn1Schema.idBlock.tagNumber,
},
value: schema.schema.valueBlock.value,
});
for (const key in schema.items) {
delete asn1Schema[key];
}
return { targetSchema: newTargetSchema };
}
return null;
}
static handleSequenceTypes(asn1Schema, schema, target, targetSchema) {
if (schema.type === enums_1.AsnTypeTypes.Sequence) {
const asn1ComparedSchema = asn1js.compareSchema({}, asn1Schema, targetSchema);
if (!asn1ComparedSchema.verified) {
throw new errors_1.AsnSchemaValidationError(`Data does not match to ${target.name} ASN1 schema.${asn1ComparedSchema.result.error ? ` ${asn1ComparedSchema.result.error}` : ""}`);
}
return asn1ComparedSchema;
}
else {
const asn1ComparedSchema = asn1js.compareSchema({}, asn1Schema, targetSchema);
if (!asn1ComparedSchema.verified) {
throw new errors_1.AsnSchemaValidationError(`Data does not match to ${target.name} ASN1 schema.${asn1ComparedSchema.result.error ? ` ${asn1ComparedSchema.result.error}` : ""}`);
}
return asn1ComparedSchema;
}
}
static processRepeatedField(asn1Elements, asn1Index, schemaItem) {
let elementsToProcess = asn1Elements.slice(asn1Index);
if (elementsToProcess.length === 1 && elementsToProcess[0].constructor.name === "Sequence") {
const seq = elementsToProcess[0];
if (seq.valueBlock && seq.valueBlock.value && Array.isArray(seq.valueBlock.value)) {
elementsToProcess = seq.valueBlock.value;
}
}
if (typeof schemaItem.type === "number") {
const converter = converters.defaultConverter(schemaItem.type);
if (!converter)
throw new Error(`No converter for ASN.1 type ${schemaItem.type}`);
return elementsToProcess
.filter((el) => el && el.valueBlock)
.map((el) => {
try {
return converter.fromASN(el);
}
catch {
return undefined;
}
})
.filter((v) => v !== undefined);
}
else {
return elementsToProcess
.filter((el) => el && el.valueBlock)
.map((el) => {
try {
return this.fromASN(el, schemaItem.type);
}
catch {
return undefined;
}
})
.filter((v) => v !== undefined);
}
}
static processPrimitiveField(asn1Element, schemaItem) {
const converter = converters.defaultConverter(schemaItem.type);
if (!converter)
throw new Error(`No converter for ASN.1 type ${schemaItem.type}`);
return converter.fromASN(asn1Element);
}
static isOptionalChoiceField(schemaItem) {
return (schemaItem.optional
&& typeof schemaItem.type === "function"
&& storage_1.schemaStorage.has(schemaItem.type)
&& storage_1.schemaStorage.get(schemaItem.type).type === enums_1.AsnTypeTypes.Choice);
}
static processOptionalChoiceField(asn1Element, schemaItem) {
try {
const value = this.fromASN(asn1Element, schemaItem.type);
return {
processed: true, value,
};
}
catch (err) {
if (err instanceof errors_1.AsnSchemaValidationError
&& /Wrong values for Choice type/.test(err.message)) {
return { processed: false };
}
throw err;
}
}
static handleArrayTypes(asn1Schema, schema, target, options) {
if (!("value" in asn1Schema.valueBlock && Array.isArray(asn1Schema.valueBlock.value))) {
throw new Error("Cannot get items from the ASN.1 parsed value. ASN.1 object is not constructed.");
}
const itemType = schema.itemType;
if (typeof itemType === "number") {
const converter = converters.defaultConverter(itemType);
if (!converter) {
throw new Error(`Cannot get default converter for array item of ${target.name} ASN1 schema`);
}
return target.from(asn1Schema.valueBlock.value, (element) => converter.fromASN(element));
}
else {
return target.from(asn1Schema.valueBlock.value, (element) => this.fromASN(element, itemType, options));
}
}
static processSchemaItems(schema, asn1ComparedSchema, res, options) {
for (const key in schema.items) {
const asn1SchemaValue = asn1ComparedSchema.result[key];
if (!asn1SchemaValue) {
continue;
}
const schemaItem = schema.items[key];
const schemaItemType = schemaItem.type;
let parsedValue;
if (typeof schemaItemType === "number" || (0, helper_1.isConvertible)(schemaItemType)) {
parsedValue = this.processPrimitiveSchemaItem(asn1SchemaValue, schemaItem, schemaItemType, options);
}
else {
parsedValue = this.processComplexSchemaItem(asn1SchemaValue, schemaItem, schemaItemType, options);
}
if (parsedValue
&& typeof parsedValue === "object"
&& "value" in parsedValue
&& "raw" in parsedValue) {
res[key] = parsedValue.value;
res[`${key}Raw`] = parsedValue.raw;
}
else {
res[key] = parsedValue;
}
}
}
static processPrimitiveSchemaItem(asn1SchemaValue, schemaItem, schemaItemType, options) {
const converter = schemaItem.converter
?? ((0, helper_1.isConvertible)(schemaItemType)
? new schemaItemType()
: null);
if (!converter) {
throw new Error("Converter is empty");
}
if (schemaItem.repeated) {
return this.processRepeatedPrimitiveItem(asn1SchemaValue, schemaItem, converter, options);
}
else {
return this.processSinglePrimitiveItem(asn1SchemaValue, schemaItem, schemaItemType, converter, options);
}
}
static processRepeatedPrimitiveItem(asn1SchemaValue, schemaItem, converter, options) {
if (schemaItem.implicit) {
const Container = schemaItem.repeated === "sequence" ? asn1js.Sequence : asn1js.Set;
const newItem = new Container();
newItem.valueBlock = asn1SchemaValue.valueBlock;
const newItemAsn = asn1js.fromBER(newItem.toBER(false), options?.berOptions);
if (newItemAsn.offset === -1) {
throw new Error(`Cannot parse the child item. ${newItemAsn.result.error}`);
}
if (!("value" in newItemAsn.result.valueBlock
&& Array.isArray(newItemAsn.result.valueBlock.value))) {
throw new Error("Cannot get items from the ASN.1 parsed value. ASN.1 object is not constructed.");
}
const value = newItemAsn.result.valueBlock.value;
return Array.from(value, (element) => converter.fromASN(element));
}
else {
return Array.from(asn1SchemaValue, (element) => converter.fromASN(element));
}
}
static processSinglePrimitiveItem(asn1SchemaValue, schemaItem, schemaItemType, converter, options) {
let value = asn1SchemaValue;
if (schemaItem.implicit) {
let newItem;
if ((0, helper_1.isConvertible)(schemaItemType)) {
newItem = new schemaItemType().toSchema("");
}
else {
const Asn1TypeName = enums_1.AsnPropTypes[schemaItemType];
const Asn1Type = asn1js[Asn1TypeName];
if (!Asn1Type) {
throw new Error(`Cannot get '${Asn1TypeName}' class from asn1js module`);
}
newItem = new Asn1Type();
}
newItem.valueBlock = value.valueBlock;
value = asn1js.fromBER(newItem.toBER(false), options?.berOptions).result;
}
return converter.fromASN(value);
}
static processComplexSchemaItem(asn1SchemaValue, schemaItem, schemaItemType, options) {
if (schemaItem.repeated) {
if (!Array.isArray(asn1SchemaValue)) {
throw new Error("Cannot get list of items from the ASN.1 parsed value. ASN.1 value should be iterable.");
}
return Array.from(asn1SchemaValue, (element) => this.fromASN(element, schemaItemType, options));
}
else {
const valueToProcess = this.handleImplicitTagging(asn1SchemaValue, schemaItem, schemaItemType);
if (this.isOptionalChoiceField(schemaItem)) {
try {
return this.fromASN(valueToProcess, schemaItemType, options);
}
catch (err) {
if (err instanceof errors_1.AsnSchemaValidationError
&& /Wrong values for Choice type/.test(err.message)) {
return undefined;
}
throw err;
}
}
else {
const parsedValue = this.fromASN(valueToProcess, schemaItemType, options);
if (schemaItem.raw) {
return {
value: parsedValue,
raw: asn1SchemaValue.valueBeforeDecodeView,
};
}
return parsedValue;
}
}
}
static handleImplicitTagging(asn1SchemaValue, schemaItem, schemaItemType) {
if (schemaItem.implicit && typeof schemaItem.context === "number") {
const schema = storage_1.schemaStorage.get(schemaItemType);
if (schema.type === enums_1.AsnTypeTypes.Sequence) {
const newSeq = new asn1js.Sequence();
if ("value" in asn1SchemaValue.valueBlock
&& Array.isArray(asn1SchemaValue.valueBlock.value)
&& "value" in newSeq.valueBlock) {
newSeq.valueBlock.value = asn1SchemaValue.valueBlock.value;
return newSeq;
}
}
else if (schema.type === enums_1.AsnTypeTypes.Set) {
const newSet = new asn1js.Set();
if ("value" in asn1SchemaValue.valueBlock
&& Array.isArray(asn1SchemaValue.valueBlock.value)
&& "value" in newSet.valueBlock) {
newSet.valueBlock.value = asn1SchemaValue.valueBlock.value;
return newSet;
}
}
}
return asn1SchemaValue;
}
}
exports.AsnParser = AsnParser;

View file

@ -0,0 +1,156 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsnSchemaStorage = void 0;
const tslib_1 = require("tslib");
const asn1js = tslib_1.__importStar(require("asn1js"));
const enums_1 = require("./enums");
const helper_1 = require("./helper");
class AsnSchemaStorage {
items = new WeakMap();
has(target) {
return this.items.has(target);
}
get(target, checkSchema = false) {
const schema = this.items.get(target);
if (!schema) {
throw new Error(`Cannot get schema for '${target.prototype.constructor.name}' target`);
}
if (checkSchema && !schema.schema) {
throw new Error(`Schema '${target.prototype.constructor.name}' doesn't contain ASN.1 schema. Call 'AsnSchemaStorage.cache'.`);
}
return schema;
}
cache(target) {
const schema = this.get(target);
if (!schema.schema) {
schema.schema = this.create(target, true);
}
}
createDefault(target) {
const schema = {
type: enums_1.AsnTypeTypes.Sequence, items: {},
};
const parentSchema = this.findParentSchema(target);
if (parentSchema) {
Object.assign(schema, parentSchema);
schema.items = Object.assign({}, schema.items, parentSchema.items);
}
return schema;
}
create(target, useNames) {
const schema = this.items.get(target) || this.createDefault(target);
const asn1Value = [];
for (const key in schema.items) {
const item = schema.items[key];
const name = useNames ? key : "";
let asn1Item;
if (typeof item.type === "number") {
const Asn1TypeName = enums_1.AsnPropTypes[item.type];
const Asn1Type = asn1js[Asn1TypeName];
if (!Asn1Type) {
throw new Error(`Cannot get ASN1 class by name '${Asn1TypeName}'`);
}
asn1Item = new Asn1Type({ name });
}
else if ((0, helper_1.isConvertible)(item.type)) {
const instance = new item.type();
asn1Item = instance.toSchema(name);
}
else if (item.optional) {
const itemSchema = this.get(item.type);
if (itemSchema.type === enums_1.AsnTypeTypes.Choice) {
asn1Item = new asn1js.Any({ name });
}
else {
asn1Item = this.create(item.type, false);
asn1Item.name = name;
}
}
else {
asn1Item = new asn1js.Any({ name });
}
const optional = !!item.optional || item.defaultValue !== undefined;
if (item.repeated) {
asn1Item.name = "";
const Container = item.repeated === "set" ? asn1js.Set : asn1js.Sequence;
asn1Item = new Container({
name: "",
value: [new asn1js.Repeated({
name, value: asn1Item,
})],
});
}
if (item.context !== null && item.context !== undefined) {
if (item.implicit) {
if (typeof item.type === "number" || (0, helper_1.isConvertible)(item.type)) {
const Container = item.repeated ? asn1js.Constructed : asn1js.Primitive;
asn1Value.push(new Container({
name, optional, idBlock: {
tagClass: 3, tagNumber: item.context,
},
}));
}
else {
this.cache(item.type);
const isRepeated = !!item.repeated;
let value = !isRepeated ? this.get(item.type, true).schema : asn1Item;
value
= "valueBlock" in value
? value.valueBlock.value
: value.value;
asn1Value.push(new asn1js.Constructed({
name: !isRepeated ? name : "",
optional,
idBlock: {
tagClass: 3, tagNumber: item.context,
},
value: value,
}));
}
}
else {
asn1Value.push(new asn1js.Constructed({
optional,
idBlock: {
tagClass: 3, tagNumber: item.context,
},
value: [asn1Item],
}));
}
}
else {
asn1Item.optional = optional;
asn1Value.push(asn1Item);
}
}
switch (schema.type) {
case enums_1.AsnTypeTypes.Sequence:
return new asn1js.Sequence({
value: asn1Value, name: "",
});
case enums_1.AsnTypeTypes.Set:
return new asn1js.Set({
value: asn1Value, name: "",
});
case enums_1.AsnTypeTypes.Choice:
return new asn1js.Choice({
value: asn1Value, name: "",
});
default:
throw new Error("Unsupported ASN1 type in use");
}
}
set(target, schema) {
this.items.set(target, schema);
return this;
}
findParentSchema(target) {
const parent = Object.getPrototypeOf(target);
if (parent) {
const schema = this.items.get(parent);
return schema || this.findParentSchema(parent);
}
return null;
}
}
exports.AsnSchemaStorage = AsnSchemaStorage;

View file

@ -0,0 +1,156 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsnSerializer = void 0;
const tslib_1 = require("tslib");
const asn1js = tslib_1.__importStar(require("asn1js"));
const bytes_1 = require("@peculiar/utils/bytes");
const converters = tslib_1.__importStar(require("./converters"));
const enums_1 = require("./enums");
const helper_1 = require("./helper");
const storage_1 = require("./storage");
class AsnSerializer {
static serialize(obj) {
if (obj instanceof asn1js.BaseBlock) {
return obj.toBER(false);
}
return this.toASN(obj).toBER(false);
}
static toASN(obj) {
if (obj && typeof obj === "object" && (0, helper_1.isConvertible)(obj)) {
return obj.toASN();
}
if (!(obj && typeof obj === "object")) {
throw new TypeError("Parameter 1 should be type of Object.");
}
const target = obj.constructor;
const schema = storage_1.schemaStorage.get(target);
storage_1.schemaStorage.cache(target);
let asn1Value = [];
if (schema.itemType) {
if (!Array.isArray(obj)) {
throw new TypeError("Parameter 1 should be type of Array.");
}
if (typeof schema.itemType === "number") {
const converter = converters.defaultConverter(schema.itemType);
if (!converter) {
throw new Error(`Cannot get default converter for array item of ${target.name} ASN1 schema`);
}
asn1Value = obj.map((o) => converter.toASN(o));
}
else {
asn1Value = obj.map((o) => this.toAsnItem({ type: schema.itemType }, "[]", target, o));
}
}
else {
for (const key in schema.items) {
const schemaItem = schema.items[key];
const objProp = obj[key];
if (objProp === undefined
|| schemaItem.defaultValue === objProp
|| (typeof schemaItem.defaultValue === "object"
&& typeof objProp === "object"
&& (0, helper_1.isArrayEqual)(this.serialize(schemaItem.defaultValue), this.serialize(objProp)))) {
continue;
}
const asn1Item = AsnSerializer.toAsnItem(schemaItem, key, target, objProp);
if (typeof schemaItem.context === "number") {
if (schemaItem.implicit) {
if (!schemaItem.repeated
&& (typeof schemaItem.type === "number" || (0, helper_1.isConvertible)(schemaItem.type))) {
const value = {};
value.valueHex
= asn1Item instanceof asn1js.Null
? (0, bytes_1.toArrayBuffer)(asn1Item.valueBeforeDecodeView)
: asn1Item.valueBlock.toBER();
asn1Value.push(new asn1js.Primitive({
optional: schemaItem.optional,
idBlock: {
tagClass: 3,
tagNumber: schemaItem.context,
},
...value,
}));
}
else {
asn1Value.push(new asn1js.Constructed({
optional: schemaItem.optional,
idBlock: {
tagClass: 3,
tagNumber: schemaItem.context,
},
value: asn1Item.valueBlock.value,
}));
}
}
else {
asn1Value.push(new asn1js.Constructed({
optional: schemaItem.optional,
idBlock: {
tagClass: 3,
tagNumber: schemaItem.context,
},
value: [asn1Item],
}));
}
}
else if (schemaItem.repeated) {
asn1Value = asn1Value.concat(asn1Item);
}
else {
asn1Value.push(asn1Item);
}
}
}
let asnSchema;
switch (schema.type) {
case enums_1.AsnTypeTypes.Sequence:
asnSchema = new asn1js.Sequence({ value: asn1Value });
break;
case enums_1.AsnTypeTypes.Set:
asnSchema = new asn1js.Set({ value: asn1Value });
break;
case enums_1.AsnTypeTypes.Choice:
if (!asn1Value[0]) {
throw new Error(`Schema '${target.name}' has wrong data. Choice cannot be empty.`);
}
asnSchema = asn1Value[0];
break;
}
return asnSchema;
}
static toAsnItem(schemaItem, key, target, objProp) {
let asn1Item;
if (typeof schemaItem.type === "number") {
const converter = schemaItem.converter;
if (!converter) {
throw new Error(`Property '${key}' doesn't have converter for type ${enums_1.AsnPropTypes[schemaItem.type]} in schema '${target.name}'`);
}
if (schemaItem.repeated) {
if (!Array.isArray(objProp)) {
throw new TypeError("Parameter 'objProp' should be type of Array.");
}
const items = Array.from(objProp, (element) => converter.toASN(element));
const Container = schemaItem.repeated === "sequence" ? asn1js.Sequence : asn1js.Set;
asn1Item = new Container({ value: items });
}
else {
asn1Item = converter.toASN(objProp);
}
}
else {
if (schemaItem.repeated) {
if (!Array.isArray(objProp)) {
throw new TypeError("Parameter 'objProp' should be type of Array.");
}
const items = Array.from(objProp, (element) => this.toASN(element));
const Container = schemaItem.repeated === "sequence" ? asn1js.Sequence : asn1js.Set;
asn1Item = new Container({ value: items });
}
else {
asn1Item = this.toASN(objProp);
}
}
return asn1Item;
}
}
exports.AsnSerializer = AsnSerializer;

View file

@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.schemaStorage = void 0;
const schema_1 = require("./schema");
exports.schemaStorage = new schema_1.AsnSchemaStorage();

View file

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

View file

@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BitString = void 0;
const tslib_1 = require("tslib");
const asn1js = tslib_1.__importStar(require("asn1js"));
const bytes_1 = require("@peculiar/utils/bytes");
class BitString {
unusedBits = 0;
value = new ArrayBuffer(0);
constructor(params, unusedBits = 0) {
if (params) {
if (typeof params === "number") {
this.fromNumber(params);
}
else if ((0, bytes_1.isBufferSource)(params)) {
this.unusedBits = unusedBits;
this.value = (0, bytes_1.toArrayBuffer)(params);
}
else {
throw TypeError("Unsupported type of 'params' argument for BitString");
}
}
}
fromASN(asn) {
if (!(asn instanceof asn1js.BitString)) {
throw new TypeError("Argument 'asn' is not instance of ASN.1 BitString");
}
this.unusedBits = asn.valueBlock.unusedBits;
this.value = (0, bytes_1.toArrayBuffer)(asn.valueBlock.valueHex);
return this;
}
toASN() {
return new asn1js.BitString({
unusedBits: this.unusedBits, valueHex: this.value,
});
}
toSchema(name) {
return new asn1js.BitString({ name });
}
toNumber() {
let res = "";
const uintArray = new Uint8Array(this.value);
for (const octet of uintArray) {
res += octet.toString(2).padStart(8, "0");
}
res = res.split("").reverse().join("");
if (this.unusedBits) {
res = res.slice(this.unusedBits).padStart(this.unusedBits, "0");
}
return parseInt(res, 2);
}
fromNumber(value) {
let bits = value.toString(2);
const octetSize = (bits.length + 7) >> 3;
this.unusedBits = (octetSize << 3) - bits.length;
const octets = new Uint8Array(octetSize);
bits = bits
.padStart(octetSize << 3, "0")
.split("")
.reverse()
.join("");
let index = 0;
while (index < octetSize) {
octets[index] = parseInt(bits.slice(index << 3, (index << 3) + 8), 2);
index++;
}
this.value = octets.buffer;
}
}
exports.BitString = BitString;

View file

@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./bit_string"), exports);
tslib_1.__exportStar(require("./octet_string"), exports);

View file

@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OctetString = void 0;
const tslib_1 = require("tslib");
const asn1js = tslib_1.__importStar(require("asn1js"));
const bytes_1 = require("@peculiar/utils/bytes");
class OctetString {
buffer;
get byteLength() {
return this.buffer.byteLength;
}
get byteOffset() {
return 0;
}
constructor(param) {
if (typeof param === "number") {
this.buffer = new ArrayBuffer(param);
}
else {
if ((0, bytes_1.isBufferSource)(param)) {
this.buffer = (0, bytes_1.toArrayBuffer)(param);
}
else if (Array.isArray(param)) {
this.buffer = new Uint8Array(param).buffer;
}
else {
this.buffer = new ArrayBuffer(0);
}
}
}
fromASN(asn) {
if (!(asn instanceof asn1js.OctetString)) {
throw new TypeError("Argument 'asn' is not instance of ASN.1 OctetString");
}
this.buffer = (0, bytes_1.toArrayBuffer)(asn.valueBlock.valueHex);
return this;
}
toASN() {
return new asn1js.OctetString({ valueHex: this.buffer });
}
toSchema(name) {
return new asn1js.OctetString({ name });
}
}
exports.OctetString = OctetString;

View file

@ -0,0 +1,22 @@
import * as asn1js from "asn1js";
import { isBufferSource, toArrayBuffer, } from "@peculiar/utils/bytes";
import { AsnParser } from "./parser.js";
import { AsnSerializer } from "./serializer.js";
export class AsnConvert {
static serialize(obj) {
return AsnSerializer.serialize(obj);
}
static parse(data, target, options) {
return AsnParser.parse(data, target, options);
}
static toString(data, options) {
const buf = isBufferSource(data)
? toArrayBuffer(data)
: AsnConvert.serialize(data);
const asn = asn1js.fromBER(buf, options?.berOptions);
if (asn.offset === -1) {
throw new Error(`Cannot decode ASN.1 data. ${asn.result.error}`);
}
return asn.result.toString();
}
}

View file

@ -0,0 +1,139 @@
import * as asn1js from "asn1js";
import { toArrayBuffer } from "@peculiar/utils/bytes";
import { AsnPropTypes } from "./enums.js";
import { OctetString } from "./types/index.js";
export const AsnAnyConverter = {
fromASN: (value) => value instanceof asn1js.Null
? null
: toArrayBuffer(value.valueBeforeDecodeView),
toASN: (value) => {
if (value === null) {
return new asn1js.Null();
}
const schema = asn1js.fromBER(value);
if (schema.result.error) {
throw new Error(schema.result.error);
}
return schema.result;
},
};
export const AsnIntegerConverter = {
fromASN: (value) => value.valueBlock.valueHexView.byteLength >= 4
? value.valueBlock.toString()
: value.valueBlock.valueDec,
toASN: (value) => new asn1js.Integer({ value: +value }),
};
export const AsnEnumeratedConverter = {
fromASN: (value) => value.valueBlock.valueDec,
toASN: (value) => new asn1js.Enumerated({ value }),
};
export const AsnIntegerArrayBufferConverter = {
fromASN: (value) => toArrayBuffer(value.valueBlock.valueHexView),
toASN: (value) => new asn1js.Integer({ valueHex: value }),
};
export const AsnIntegerBigIntConverter = {
fromASN: (value) => value.toBigInt(),
toASN: (value) => asn1js.Integer.fromBigInt(value),
};
export const AsnBitStringConverter = {
fromASN: (value) => toArrayBuffer(value.valueBlock.valueHexView),
toASN: (value) => new asn1js.BitString({ valueHex: value }),
};
export const AsnObjectIdentifierConverter = {
fromASN: (value) => value.valueBlock.toString(),
toASN: (value) => new asn1js.ObjectIdentifier({ value }),
};
export const AsnBooleanConverter = {
fromASN: (value) => value.valueBlock.value,
toASN: (value) => new asn1js.Boolean({ value }),
};
export const AsnOctetStringConverter = {
fromASN: (value) => toArrayBuffer(value.valueBlock.valueHexView),
toASN: (value) => new asn1js.OctetString({ valueHex: value }),
};
export const AsnConstructedOctetStringConverter = {
fromASN: (value) => new OctetString(value.getValue()),
toASN: (value) => value.toASN(),
};
function createStringConverter(Asn1Type) {
return {
fromASN: (value) => value.valueBlock.value,
toASN: (value) => new Asn1Type({ value }),
};
}
export const AsnUtf8StringConverter = createStringConverter(asn1js.Utf8String);
export const AsnBmpStringConverter = createStringConverter(asn1js.BmpString);
export const AsnUniversalStringConverter = createStringConverter(asn1js.UniversalString);
export const AsnNumericStringConverter = createStringConverter(asn1js.NumericString);
export const AsnPrintableStringConverter = createStringConverter(asn1js.PrintableString);
export const AsnTeletexStringConverter = createStringConverter(asn1js.TeletexString);
export const AsnVideotexStringConverter = createStringConverter(asn1js.VideotexString);
export const AsnIA5StringConverter = createStringConverter(asn1js.IA5String);
export const AsnGraphicStringConverter = createStringConverter(asn1js.GraphicString);
export const AsnVisibleStringConverter = createStringConverter(asn1js.VisibleString);
export const AsnGeneralStringConverter = createStringConverter(asn1js.GeneralString);
export const AsnCharacterStringConverter = createStringConverter(asn1js.CharacterString);
export const AsnUTCTimeConverter = {
fromASN: (value) => value.toDate(),
toASN: (value) => new asn1js.UTCTime({ valueDate: value }),
};
export const AsnGeneralizedTimeConverter = {
fromASN: (value) => value.toDate(),
toASN: (value) => new asn1js.GeneralizedTime({ valueDate: value }),
};
export const AsnNullConverter = {
fromASN: () => null,
toASN: () => {
return new asn1js.Null();
},
};
export function defaultConverter(type) {
switch (type) {
case AsnPropTypes.Any:
return AsnAnyConverter;
case AsnPropTypes.BitString:
return AsnBitStringConverter;
case AsnPropTypes.BmpString:
return AsnBmpStringConverter;
case AsnPropTypes.Boolean:
return AsnBooleanConverter;
case AsnPropTypes.CharacterString:
return AsnCharacterStringConverter;
case AsnPropTypes.Enumerated:
return AsnEnumeratedConverter;
case AsnPropTypes.GeneralString:
return AsnGeneralStringConverter;
case AsnPropTypes.GeneralizedTime:
return AsnGeneralizedTimeConverter;
case AsnPropTypes.GraphicString:
return AsnGraphicStringConverter;
case AsnPropTypes.IA5String:
return AsnIA5StringConverter;
case AsnPropTypes.Integer:
return AsnIntegerConverter;
case AsnPropTypes.Null:
return AsnNullConverter;
case AsnPropTypes.NumericString:
return AsnNumericStringConverter;
case AsnPropTypes.ObjectIdentifier:
return AsnObjectIdentifierConverter;
case AsnPropTypes.OctetString:
return AsnOctetStringConverter;
case AsnPropTypes.PrintableString:
return AsnPrintableStringConverter;
case AsnPropTypes.TeletexString:
return AsnTeletexStringConverter;
case AsnPropTypes.UTCTime:
return AsnUTCTimeConverter;
case AsnPropTypes.UniversalString:
return AsnUniversalStringConverter;
case AsnPropTypes.Utf8String:
return AsnUtf8StringConverter;
case AsnPropTypes.VideotexString:
return AsnVideotexStringConverter;
case AsnPropTypes.VisibleString:
return AsnVisibleStringConverter;
default:
return null;
}
}

View file

@ -0,0 +1,41 @@
import * as converters from "./converters.js";
import { AsnTypeTypes } from "./enums.js";
import { schemaStorage } from "./storage.js";
export const AsnType = (options) => (target) => {
let schema;
if (!schemaStorage.has(target)) {
schema = schemaStorage.createDefault(target);
schemaStorage.set(target, schema);
}
else {
schema = schemaStorage.get(target);
}
Object.assign(schema, options);
};
export const AsnChoiceType = () => AsnType({ type: AsnTypeTypes.Choice });
export const AsnSetType = (options) => AsnType({
type: AsnTypeTypes.Set, ...options,
});
export const AsnSequenceType = (options) => AsnType({
type: AsnTypeTypes.Sequence, ...options,
});
export const AsnProp = (options) => (target, propertyKey) => {
let schema;
if (!schemaStorage.has(target.constructor)) {
schema = schemaStorage.createDefault(target.constructor);
schemaStorage.set(target.constructor, schema);
}
else {
schema = schemaStorage.get(target.constructor);
}
const copyOptions = Object.assign({}, options);
if (typeof copyOptions.type === "number" && !copyOptions.converter) {
const defaultConverter = converters.defaultConverter(options.type);
if (!defaultConverter) {
throw new Error(`Cannot get default converter for property '${propertyKey}' of ${target.constructor.name}`);
}
copyOptions.converter = defaultConverter;
}
copyOptions.raw = options.raw;
schema.items[propertyKey] = copyOptions;
};

View file

@ -0,0 +1,36 @@
export var AsnTypeTypes;
(function (AsnTypeTypes) {
AsnTypeTypes[AsnTypeTypes["Sequence"] = 0] = "Sequence";
AsnTypeTypes[AsnTypeTypes["Set"] = 1] = "Set";
AsnTypeTypes[AsnTypeTypes["Choice"] = 2] = "Choice";
})(AsnTypeTypes || (AsnTypeTypes = {}));
export var AsnPropTypes;
(function (AsnPropTypes) {
AsnPropTypes[AsnPropTypes["Any"] = 1] = "Any";
AsnPropTypes[AsnPropTypes["Boolean"] = 2] = "Boolean";
AsnPropTypes[AsnPropTypes["OctetString"] = 3] = "OctetString";
AsnPropTypes[AsnPropTypes["BitString"] = 4] = "BitString";
AsnPropTypes[AsnPropTypes["Integer"] = 5] = "Integer";
AsnPropTypes[AsnPropTypes["Enumerated"] = 6] = "Enumerated";
AsnPropTypes[AsnPropTypes["ObjectIdentifier"] = 7] = "ObjectIdentifier";
AsnPropTypes[AsnPropTypes["Utf8String"] = 8] = "Utf8String";
AsnPropTypes[AsnPropTypes["BmpString"] = 9] = "BmpString";
AsnPropTypes[AsnPropTypes["UniversalString"] = 10] = "UniversalString";
AsnPropTypes[AsnPropTypes["NumericString"] = 11] = "NumericString";
AsnPropTypes[AsnPropTypes["PrintableString"] = 12] = "PrintableString";
AsnPropTypes[AsnPropTypes["TeletexString"] = 13] = "TeletexString";
AsnPropTypes[AsnPropTypes["VideotexString"] = 14] = "VideotexString";
AsnPropTypes[AsnPropTypes["IA5String"] = 15] = "IA5String";
AsnPropTypes[AsnPropTypes["GraphicString"] = 16] = "GraphicString";
AsnPropTypes[AsnPropTypes["VisibleString"] = 17] = "VisibleString";
AsnPropTypes[AsnPropTypes["GeneralString"] = 18] = "GeneralString";
AsnPropTypes[AsnPropTypes["CharacterString"] = 19] = "CharacterString";
AsnPropTypes[AsnPropTypes["UTCTime"] = 20] = "UTCTime";
AsnPropTypes[AsnPropTypes["GeneralizedTime"] = 21] = "GeneralizedTime";
AsnPropTypes[AsnPropTypes["DATE"] = 22] = "DATE";
AsnPropTypes[AsnPropTypes["TimeOfDay"] = 23] = "TimeOfDay";
AsnPropTypes[AsnPropTypes["DateTime"] = 24] = "DateTime";
AsnPropTypes[AsnPropTypes["Duration"] = 25] = "Duration";
AsnPropTypes[AsnPropTypes["TIME"] = 26] = "TIME";
AsnPropTypes[AsnPropTypes["Null"] = 27] = "Null";
})(AsnPropTypes || (AsnPropTypes = {}));

View file

@ -0,0 +1 @@
export * from "./schema_validation.js";

View file

@ -0,0 +1,3 @@
export class AsnSchemaValidationError extends Error {
schemas = [];
}

View file

@ -0,0 +1,39 @@
export function isConvertible(target) {
if (typeof target === "function" && target.prototype) {
if (target.prototype.toASN && target.prototype.fromASN) {
return true;
}
else {
return isConvertible(target.prototype);
}
}
else {
return !!(target && typeof target === "object" && "toASN" in target && "fromASN" in target);
}
}
export function isTypeOfArray(target) {
if (target) {
const proto = Object.getPrototypeOf(target);
if (proto?.prototype?.constructor === Array) {
return true;
}
return isTypeOfArray(proto);
}
return false;
}
export function isArrayEqual(bytes1, bytes2) {
if (!(bytes1 && bytes2)) {
return false;
}
if (bytes1.byteLength !== bytes2.byteLength) {
return false;
}
const b1 = new Uint8Array(bytes1);
const b2 = new Uint8Array(bytes2);
for (let i = 0; i < bytes1.byteLength; i++) {
if (b1[i] !== b2[i]) {
return false;
}
}
return true;
}

View file

@ -0,0 +1,9 @@
export * from "./converters.js";
export * from "./types/index.js";
export { AsnProp, AsnType, AsnChoiceType, AsnSequenceType, AsnSetType, } from "./decorators.js";
export { AsnTypeTypes, AsnPropTypes } from "./enums.js";
export { AsnParser } from "./parser.js";
export { AsnSerializer } from "./serializer.js";
export * from "./errors/index.js";
export * from "./objects.js";
export * from "./convert.js";

View file

@ -0,0 +1,13 @@
export class AsnArray extends Array {
constructor(items = []) {
if (typeof items === "number") {
super(items);
}
else {
super();
for (const item of items) {
this.push(item);
}
}
}
}

View file

@ -0,0 +1,3 @@
{
"type": "module"
}

View file

@ -0,0 +1,326 @@
import * as asn1js from "asn1js";
import { toArrayBuffer } from "@peculiar/utils/bytes";
import { AsnPropTypes, AsnTypeTypes } from "./enums.js";
import * as converters from "./converters.js";
import { AsnSchemaValidationError } from "./errors/index.js";
import { isConvertible, isTypeOfArray } from "./helper.js";
import { schemaStorage } from "./storage.js";
export class AsnParser {
static parse(data, target, options) {
const asn1Parsed = asn1js.fromBER(toArrayBuffer(data), options?.berOptions);
if (asn1Parsed.result.error) {
throw new Error(asn1Parsed.result.error);
}
const res = this.fromASN(asn1Parsed.result, target, options);
return res;
}
static fromASN(asn1Schema, target, options) {
try {
if (isConvertible(target)) {
const value = new target();
return value.fromASN(asn1Schema);
}
const schema = schemaStorage.get(target);
schemaStorage.cache(target);
let targetSchema = schema.schema;
const choiceResult = this.handleChoiceTypes(asn1Schema, schema, target, targetSchema, options);
if (choiceResult?.result) {
return choiceResult.result;
}
if (choiceResult?.targetSchema) {
targetSchema = choiceResult.targetSchema;
}
const sequenceResult = this.handleSequenceTypes(asn1Schema, schema, target, targetSchema);
const res = new target();
if (isTypeOfArray(target)) {
return this.handleArrayTypes(asn1Schema, schema, target, options);
}
this.processSchemaItems(schema, sequenceResult, res, options);
return res;
}
catch (error) {
if (error instanceof AsnSchemaValidationError) {
error.schemas.push(target.name);
}
throw error;
}
}
static handleChoiceTypes(asn1Schema, schema, target, targetSchema, options) {
if (asn1Schema.constructor === asn1js.Constructed
&& schema.type === AsnTypeTypes.Choice
&& asn1Schema.idBlock.tagClass === 3) {
for (const key in schema.items) {
const schemaItem = schema.items[key];
if (schemaItem.context === asn1Schema.idBlock.tagNumber && schemaItem.implicit) {
if (typeof schemaItem.type === "function"
&& schemaStorage.has(schemaItem.type)) {
const fieldSchema = schemaStorage.get(schemaItem.type);
if (fieldSchema && fieldSchema.type === AsnTypeTypes.Sequence) {
const newSeq = new asn1js.Sequence();
if ("value" in asn1Schema.valueBlock
&& Array.isArray(asn1Schema.valueBlock.value)
&& "value" in newSeq.valueBlock) {
newSeq.valueBlock.value = asn1Schema.valueBlock.value;
const fieldValue = this.fromASN(newSeq, schemaItem.type, options);
const res = new target();
res[key] = fieldValue;
return { result: res };
}
}
}
}
}
}
else if (asn1Schema.constructor === asn1js.Constructed
&& schema.type !== AsnTypeTypes.Choice) {
const newTargetSchema = new asn1js.Constructed({
idBlock: {
tagClass: 3,
tagNumber: asn1Schema.idBlock.tagNumber,
},
value: schema.schema.valueBlock.value,
});
for (const key in schema.items) {
delete asn1Schema[key];
}
return { targetSchema: newTargetSchema };
}
return null;
}
static handleSequenceTypes(asn1Schema, schema, target, targetSchema) {
if (schema.type === AsnTypeTypes.Sequence) {
const asn1ComparedSchema = asn1js.compareSchema({}, asn1Schema, targetSchema);
if (!asn1ComparedSchema.verified) {
throw new AsnSchemaValidationError(`Data does not match to ${target.name} ASN1 schema.${asn1ComparedSchema.result.error ? ` ${asn1ComparedSchema.result.error}` : ""}`);
}
return asn1ComparedSchema;
}
else {
const asn1ComparedSchema = asn1js.compareSchema({}, asn1Schema, targetSchema);
if (!asn1ComparedSchema.verified) {
throw new AsnSchemaValidationError(`Data does not match to ${target.name} ASN1 schema.${asn1ComparedSchema.result.error ? ` ${asn1ComparedSchema.result.error}` : ""}`);
}
return asn1ComparedSchema;
}
}
static processRepeatedField(asn1Elements, asn1Index, schemaItem) {
let elementsToProcess = asn1Elements.slice(asn1Index);
if (elementsToProcess.length === 1 && elementsToProcess[0].constructor.name === "Sequence") {
const seq = elementsToProcess[0];
if (seq.valueBlock && seq.valueBlock.value && Array.isArray(seq.valueBlock.value)) {
elementsToProcess = seq.valueBlock.value;
}
}
if (typeof schemaItem.type === "number") {
const converter = converters.defaultConverter(schemaItem.type);
if (!converter)
throw new Error(`No converter for ASN.1 type ${schemaItem.type}`);
return elementsToProcess
.filter((el) => el && el.valueBlock)
.map((el) => {
try {
return converter.fromASN(el);
}
catch {
return undefined;
}
})
.filter((v) => v !== undefined);
}
else {
return elementsToProcess
.filter((el) => el && el.valueBlock)
.map((el) => {
try {
return this.fromASN(el, schemaItem.type);
}
catch {
return undefined;
}
})
.filter((v) => v !== undefined);
}
}
static processPrimitiveField(asn1Element, schemaItem) {
const converter = converters.defaultConverter(schemaItem.type);
if (!converter)
throw new Error(`No converter for ASN.1 type ${schemaItem.type}`);
return converter.fromASN(asn1Element);
}
static isOptionalChoiceField(schemaItem) {
return (schemaItem.optional
&& typeof schemaItem.type === "function"
&& schemaStorage.has(schemaItem.type)
&& schemaStorage.get(schemaItem.type).type === AsnTypeTypes.Choice);
}
static processOptionalChoiceField(asn1Element, schemaItem) {
try {
const value = this.fromASN(asn1Element, schemaItem.type);
return {
processed: true, value,
};
}
catch (err) {
if (err instanceof AsnSchemaValidationError
&& /Wrong values for Choice type/.test(err.message)) {
return { processed: false };
}
throw err;
}
}
static handleArrayTypes(asn1Schema, schema, target, options) {
if (!("value" in asn1Schema.valueBlock && Array.isArray(asn1Schema.valueBlock.value))) {
throw new Error("Cannot get items from the ASN.1 parsed value. ASN.1 object is not constructed.");
}
const itemType = schema.itemType;
if (typeof itemType === "number") {
const converter = converters.defaultConverter(itemType);
if (!converter) {
throw new Error(`Cannot get default converter for array item of ${target.name} ASN1 schema`);
}
return target.from(asn1Schema.valueBlock.value, (element) => converter.fromASN(element));
}
else {
return target.from(asn1Schema.valueBlock.value, (element) => this.fromASN(element, itemType, options));
}
}
static processSchemaItems(schema, asn1ComparedSchema, res, options) {
for (const key in schema.items) {
const asn1SchemaValue = asn1ComparedSchema.result[key];
if (!asn1SchemaValue) {
continue;
}
const schemaItem = schema.items[key];
const schemaItemType = schemaItem.type;
let parsedValue;
if (typeof schemaItemType === "number" || isConvertible(schemaItemType)) {
parsedValue = this.processPrimitiveSchemaItem(asn1SchemaValue, schemaItem, schemaItemType, options);
}
else {
parsedValue = this.processComplexSchemaItem(asn1SchemaValue, schemaItem, schemaItemType, options);
}
if (parsedValue
&& typeof parsedValue === "object"
&& "value" in parsedValue
&& "raw" in parsedValue) {
res[key] = parsedValue.value;
res[`${key}Raw`] = parsedValue.raw;
}
else {
res[key] = parsedValue;
}
}
}
static processPrimitiveSchemaItem(asn1SchemaValue, schemaItem, schemaItemType, options) {
const converter = schemaItem.converter
?? (isConvertible(schemaItemType)
? new schemaItemType()
: null);
if (!converter) {
throw new Error("Converter is empty");
}
if (schemaItem.repeated) {
return this.processRepeatedPrimitiveItem(asn1SchemaValue, schemaItem, converter, options);
}
else {
return this.processSinglePrimitiveItem(asn1SchemaValue, schemaItem, schemaItemType, converter, options);
}
}
static processRepeatedPrimitiveItem(asn1SchemaValue, schemaItem, converter, options) {
if (schemaItem.implicit) {
const Container = schemaItem.repeated === "sequence" ? asn1js.Sequence : asn1js.Set;
const newItem = new Container();
newItem.valueBlock = asn1SchemaValue.valueBlock;
const newItemAsn = asn1js.fromBER(newItem.toBER(false), options?.berOptions);
if (newItemAsn.offset === -1) {
throw new Error(`Cannot parse the child item. ${newItemAsn.result.error}`);
}
if (!("value" in newItemAsn.result.valueBlock
&& Array.isArray(newItemAsn.result.valueBlock.value))) {
throw new Error("Cannot get items from the ASN.1 parsed value. ASN.1 object is not constructed.");
}
const value = newItemAsn.result.valueBlock.value;
return Array.from(value, (element) => converter.fromASN(element));
}
else {
return Array.from(asn1SchemaValue, (element) => converter.fromASN(element));
}
}
static processSinglePrimitiveItem(asn1SchemaValue, schemaItem, schemaItemType, converter, options) {
let value = asn1SchemaValue;
if (schemaItem.implicit) {
let newItem;
if (isConvertible(schemaItemType)) {
newItem = new schemaItemType().toSchema("");
}
else {
const Asn1TypeName = AsnPropTypes[schemaItemType];
const Asn1Type = asn1js[Asn1TypeName];
if (!Asn1Type) {
throw new Error(`Cannot get '${Asn1TypeName}' class from asn1js module`);
}
newItem = new Asn1Type();
}
newItem.valueBlock = value.valueBlock;
value = asn1js.fromBER(newItem.toBER(false), options?.berOptions).result;
}
return converter.fromASN(value);
}
static processComplexSchemaItem(asn1SchemaValue, schemaItem, schemaItemType, options) {
if (schemaItem.repeated) {
if (!Array.isArray(asn1SchemaValue)) {
throw new Error("Cannot get list of items from the ASN.1 parsed value. ASN.1 value should be iterable.");
}
return Array.from(asn1SchemaValue, (element) => this.fromASN(element, schemaItemType, options));
}
else {
const valueToProcess = this.handleImplicitTagging(asn1SchemaValue, schemaItem, schemaItemType);
if (this.isOptionalChoiceField(schemaItem)) {
try {
return this.fromASN(valueToProcess, schemaItemType, options);
}
catch (err) {
if (err instanceof AsnSchemaValidationError
&& /Wrong values for Choice type/.test(err.message)) {
return undefined;
}
throw err;
}
}
else {
const parsedValue = this.fromASN(valueToProcess, schemaItemType, options);
if (schemaItem.raw) {
return {
value: parsedValue,
raw: asn1SchemaValue.valueBeforeDecodeView,
};
}
return parsedValue;
}
}
}
static handleImplicitTagging(asn1SchemaValue, schemaItem, schemaItemType) {
if (schemaItem.implicit && typeof schemaItem.context === "number") {
const schema = schemaStorage.get(schemaItemType);
if (schema.type === AsnTypeTypes.Sequence) {
const newSeq = new asn1js.Sequence();
if ("value" in asn1SchemaValue.valueBlock
&& Array.isArray(asn1SchemaValue.valueBlock.value)
&& "value" in newSeq.valueBlock) {
newSeq.valueBlock.value = asn1SchemaValue.valueBlock.value;
return newSeq;
}
}
else if (schema.type === AsnTypeTypes.Set) {
const newSet = new asn1js.Set();
if ("value" in asn1SchemaValue.valueBlock
&& Array.isArray(asn1SchemaValue.valueBlock.value)
&& "value" in newSet.valueBlock) {
newSet.valueBlock.value = asn1SchemaValue.valueBlock.value;
return newSet;
}
}
}
return asn1SchemaValue;
}
}

View file

@ -0,0 +1,151 @@
import * as asn1js from "asn1js";
import { AsnPropTypes, AsnTypeTypes } from "./enums.js";
import { isConvertible } from "./helper.js";
export class AsnSchemaStorage {
items = new WeakMap();
has(target) {
return this.items.has(target);
}
get(target, checkSchema = false) {
const schema = this.items.get(target);
if (!schema) {
throw new Error(`Cannot get schema for '${target.prototype.constructor.name}' target`);
}
if (checkSchema && !schema.schema) {
throw new Error(`Schema '${target.prototype.constructor.name}' doesn't contain ASN.1 schema. Call 'AsnSchemaStorage.cache'.`);
}
return schema;
}
cache(target) {
const schema = this.get(target);
if (!schema.schema) {
schema.schema = this.create(target, true);
}
}
createDefault(target) {
const schema = {
type: AsnTypeTypes.Sequence, items: {},
};
const parentSchema = this.findParentSchema(target);
if (parentSchema) {
Object.assign(schema, parentSchema);
schema.items = Object.assign({}, schema.items, parentSchema.items);
}
return schema;
}
create(target, useNames) {
const schema = this.items.get(target) || this.createDefault(target);
const asn1Value = [];
for (const key in schema.items) {
const item = schema.items[key];
const name = useNames ? key : "";
let asn1Item;
if (typeof item.type === "number") {
const Asn1TypeName = AsnPropTypes[item.type];
const Asn1Type = asn1js[Asn1TypeName];
if (!Asn1Type) {
throw new Error(`Cannot get ASN1 class by name '${Asn1TypeName}'`);
}
asn1Item = new Asn1Type({ name });
}
else if (isConvertible(item.type)) {
const instance = new item.type();
asn1Item = instance.toSchema(name);
}
else if (item.optional) {
const itemSchema = this.get(item.type);
if (itemSchema.type === AsnTypeTypes.Choice) {
asn1Item = new asn1js.Any({ name });
}
else {
asn1Item = this.create(item.type, false);
asn1Item.name = name;
}
}
else {
asn1Item = new asn1js.Any({ name });
}
const optional = !!item.optional || item.defaultValue !== undefined;
if (item.repeated) {
asn1Item.name = "";
const Container = item.repeated === "set" ? asn1js.Set : asn1js.Sequence;
asn1Item = new Container({
name: "",
value: [new asn1js.Repeated({
name, value: asn1Item,
})],
});
}
if (item.context !== null && item.context !== undefined) {
if (item.implicit) {
if (typeof item.type === "number" || isConvertible(item.type)) {
const Container = item.repeated ? asn1js.Constructed : asn1js.Primitive;
asn1Value.push(new Container({
name, optional, idBlock: {
tagClass: 3, tagNumber: item.context,
},
}));
}
else {
this.cache(item.type);
const isRepeated = !!item.repeated;
let value = !isRepeated ? this.get(item.type, true).schema : asn1Item;
value
= "valueBlock" in value
? value.valueBlock.value
: value.value;
asn1Value.push(new asn1js.Constructed({
name: !isRepeated ? name : "",
optional,
idBlock: {
tagClass: 3, tagNumber: item.context,
},
value: value,
}));
}
}
else {
asn1Value.push(new asn1js.Constructed({
optional,
idBlock: {
tagClass: 3, tagNumber: item.context,
},
value: [asn1Item],
}));
}
}
else {
asn1Item.optional = optional;
asn1Value.push(asn1Item);
}
}
switch (schema.type) {
case AsnTypeTypes.Sequence:
return new asn1js.Sequence({
value: asn1Value, name: "",
});
case AsnTypeTypes.Set:
return new asn1js.Set({
value: asn1Value, name: "",
});
case AsnTypeTypes.Choice:
return new asn1js.Choice({
value: asn1Value, name: "",
});
default:
throw new Error("Unsupported ASN1 type in use");
}
}
set(target, schema) {
this.items.set(target, schema);
return this;
}
findParentSchema(target) {
const parent = Object.getPrototypeOf(target);
if (parent) {
const schema = this.items.get(parent);
return schema || this.findParentSchema(parent);
}
return null;
}
}

View file

@ -0,0 +1,151 @@
import * as asn1js from "asn1js";
import { toArrayBuffer } from "@peculiar/utils/bytes";
import * as converters from "./converters.js";
import { AsnPropTypes, AsnTypeTypes } from "./enums.js";
import { isConvertible, isArrayEqual } from "./helper.js";
import { schemaStorage } from "./storage.js";
export class AsnSerializer {
static serialize(obj) {
if (obj instanceof asn1js.BaseBlock) {
return obj.toBER(false);
}
return this.toASN(obj).toBER(false);
}
static toASN(obj) {
if (obj && typeof obj === "object" && isConvertible(obj)) {
return obj.toASN();
}
if (!(obj && typeof obj === "object")) {
throw new TypeError("Parameter 1 should be type of Object.");
}
const target = obj.constructor;
const schema = schemaStorage.get(target);
schemaStorage.cache(target);
let asn1Value = [];
if (schema.itemType) {
if (!Array.isArray(obj)) {
throw new TypeError("Parameter 1 should be type of Array.");
}
if (typeof schema.itemType === "number") {
const converter = converters.defaultConverter(schema.itemType);
if (!converter) {
throw new Error(`Cannot get default converter for array item of ${target.name} ASN1 schema`);
}
asn1Value = obj.map((o) => converter.toASN(o));
}
else {
asn1Value = obj.map((o) => this.toAsnItem({ type: schema.itemType }, "[]", target, o));
}
}
else {
for (const key in schema.items) {
const schemaItem = schema.items[key];
const objProp = obj[key];
if (objProp === undefined
|| schemaItem.defaultValue === objProp
|| (typeof schemaItem.defaultValue === "object"
&& typeof objProp === "object"
&& isArrayEqual(this.serialize(schemaItem.defaultValue), this.serialize(objProp)))) {
continue;
}
const asn1Item = AsnSerializer.toAsnItem(schemaItem, key, target, objProp);
if (typeof schemaItem.context === "number") {
if (schemaItem.implicit) {
if (!schemaItem.repeated
&& (typeof schemaItem.type === "number" || isConvertible(schemaItem.type))) {
const value = {};
value.valueHex
= asn1Item instanceof asn1js.Null
? toArrayBuffer(asn1Item.valueBeforeDecodeView)
: asn1Item.valueBlock.toBER();
asn1Value.push(new asn1js.Primitive({
optional: schemaItem.optional,
idBlock: {
tagClass: 3,
tagNumber: schemaItem.context,
},
...value,
}));
}
else {
asn1Value.push(new asn1js.Constructed({
optional: schemaItem.optional,
idBlock: {
tagClass: 3,
tagNumber: schemaItem.context,
},
value: asn1Item.valueBlock.value,
}));
}
}
else {
asn1Value.push(new asn1js.Constructed({
optional: schemaItem.optional,
idBlock: {
tagClass: 3,
tagNumber: schemaItem.context,
},
value: [asn1Item],
}));
}
}
else if (schemaItem.repeated) {
asn1Value = asn1Value.concat(asn1Item);
}
else {
asn1Value.push(asn1Item);
}
}
}
let asnSchema;
switch (schema.type) {
case AsnTypeTypes.Sequence:
asnSchema = new asn1js.Sequence({ value: asn1Value });
break;
case AsnTypeTypes.Set:
asnSchema = new asn1js.Set({ value: asn1Value });
break;
case AsnTypeTypes.Choice:
if (!asn1Value[0]) {
throw new Error(`Schema '${target.name}' has wrong data. Choice cannot be empty.`);
}
asnSchema = asn1Value[0];
break;
}
return asnSchema;
}
static toAsnItem(schemaItem, key, target, objProp) {
let asn1Item;
if (typeof schemaItem.type === "number") {
const converter = schemaItem.converter;
if (!converter) {
throw new Error(`Property '${key}' doesn't have converter for type ${AsnPropTypes[schemaItem.type]} in schema '${target.name}'`);
}
if (schemaItem.repeated) {
if (!Array.isArray(objProp)) {
throw new TypeError("Parameter 'objProp' should be type of Array.");
}
const items = Array.from(objProp, (element) => converter.toASN(element));
const Container = schemaItem.repeated === "sequence" ? asn1js.Sequence : asn1js.Set;
asn1Item = new Container({ value: items });
}
else {
asn1Item = converter.toASN(objProp);
}
}
else {
if (schemaItem.repeated) {
if (!Array.isArray(objProp)) {
throw new TypeError("Parameter 'objProp' should be type of Array.");
}
const items = Array.from(objProp, (element) => this.toASN(element));
const Container = schemaItem.repeated === "sequence" ? asn1js.Sequence : asn1js.Set;
asn1Item = new Container({ value: items });
}
else {
asn1Item = this.toASN(objProp);
}
}
return asn1Item;
}
}

View file

@ -0,0 +1,2 @@
import { AsnSchemaStorage } from "./schema.js";
export const schemaStorage = new AsnSchemaStorage();

View file

@ -0,0 +1 @@
export {};

View file

@ -0,0 +1,65 @@
import * as asn1js from "asn1js";
import { isBufferSource, toArrayBuffer, } from "@peculiar/utils/bytes";
export class BitString {
unusedBits = 0;
value = new ArrayBuffer(0);
constructor(params, unusedBits = 0) {
if (params) {
if (typeof params === "number") {
this.fromNumber(params);
}
else if (isBufferSource(params)) {
this.unusedBits = unusedBits;
this.value = toArrayBuffer(params);
}
else {
throw TypeError("Unsupported type of 'params' argument for BitString");
}
}
}
fromASN(asn) {
if (!(asn instanceof asn1js.BitString)) {
throw new TypeError("Argument 'asn' is not instance of ASN.1 BitString");
}
this.unusedBits = asn.valueBlock.unusedBits;
this.value = toArrayBuffer(asn.valueBlock.valueHex);
return this;
}
toASN() {
return new asn1js.BitString({
unusedBits: this.unusedBits, valueHex: this.value,
});
}
toSchema(name) {
return new asn1js.BitString({ name });
}
toNumber() {
let res = "";
const uintArray = new Uint8Array(this.value);
for (const octet of uintArray) {
res += octet.toString(2).padStart(8, "0");
}
res = res.split("").reverse().join("");
if (this.unusedBits) {
res = res.slice(this.unusedBits).padStart(this.unusedBits, "0");
}
return parseInt(res, 2);
}
fromNumber(value) {
let bits = value.toString(2);
const octetSize = (bits.length + 7) >> 3;
this.unusedBits = (octetSize << 3) - bits.length;
const octets = new Uint8Array(octetSize);
bits = bits
.padStart(octetSize << 3, "0")
.split("")
.reverse()
.join("");
let index = 0;
while (index < octetSize) {
octets[index] = parseInt(bits.slice(index << 3, (index << 3) + 8), 2);
index++;
}
this.value = octets.buffer;
}
}

View file

@ -0,0 +1,2 @@
export * from "./bit_string.js";
export * from "./octet_string.js";

View file

@ -0,0 +1,40 @@
import * as asn1js from "asn1js";
import { isBufferSource, toArrayBuffer, } from "@peculiar/utils/bytes";
export class OctetString {
buffer;
get byteLength() {
return this.buffer.byteLength;
}
get byteOffset() {
return 0;
}
constructor(param) {
if (typeof param === "number") {
this.buffer = new ArrayBuffer(param);
}
else {
if (isBufferSource(param)) {
this.buffer = toArrayBuffer(param);
}
else if (Array.isArray(param)) {
this.buffer = new Uint8Array(param).buffer;
}
else {
this.buffer = new ArrayBuffer(0);
}
}
}
fromASN(asn) {
if (!(asn instanceof asn1js.OctetString)) {
throw new TypeError("Argument 'asn' is not instance of ASN.1 OctetString");
}
this.buffer = toArrayBuffer(asn.valueBlock.valueHex);
return this;
}
toASN() {
return new asn1js.OctetString({ valueHex: this.buffer });
}
toSchema(name) {
return new asn1js.OctetString({ name });
}
}

View file

@ -0,0 +1,20 @@
import { type BufferSourceLike } from "@peculiar/utils/bytes";
import { IEmptyConstructor, IAsnParseOptions } from "./types";
export declare class AsnConvert {
static serialize(obj: unknown): ArrayBuffer;
static parse<T>(data: BufferSourceLike, target: IEmptyConstructor<T>, options?: IAsnParseOptions): T;
/**
* Returns a string representation of an ASN.1 encoded data
* @param data ASN.1 encoded buffer source
* @param options Optional parsing options forwarded to `asn1js.fromBER`
* @returns String representation of ASN.1 structure
*/
static toString(data: BufferSourceLike, options?: IAsnParseOptions): string;
/**
* Returns a string representation of an ASN.1 schema
* @param obj Object which can be serialized to ASN.1 schema
* @param options Optional parsing options forwarded to `asn1js.fromBER`
* @returns String representation of ASN.1 structure
*/
static toString(obj: unknown, options?: IAsnParseOptions): string;
}

View file

@ -0,0 +1,113 @@
import * as asn1js from "asn1js";
import { AnyConverterType, IAsnConverter, IntegerConverterType } from "./types";
import { AsnPropTypes } from "./enums";
import { OctetString } from "./types/index";
/**
* NOTE: Converter MUST have name Asn<Asn1PropType.name>Converter.
* Asn1Prop decorator link custom converters by name of the Asn1PropType
*/
/**
* ASN.1 ANY converter
*/
export declare const AsnAnyConverter: IAsnConverter<AnyConverterType>;
/**
* ASN.1 INTEGER to Number/String converter
*/
export declare const AsnIntegerConverter: IAsnConverter<IntegerConverterType, asn1js.Integer>;
/**
* ASN.1 ENUMERATED converter
*/
export declare const AsnEnumeratedConverter: IAsnConverter<number, asn1js.Enumerated>;
/**
* ASN.1 INTEGER to ArrayBuffer converter
*/
export declare const AsnIntegerArrayBufferConverter: IAsnConverter<ArrayBuffer, asn1js.Integer>;
/**
* ASN.1 INTEGER to BigInt converter
*/
export declare const AsnIntegerBigIntConverter: IAsnConverter<bigint, asn1js.Integer>;
/**
* ASN.1 BIT STRING converter
*/
export declare const AsnBitStringConverter: IAsnConverter<ArrayBuffer, asn1js.BitString>;
/**
* ASN.1 OBJECT IDENTIFIER converter
*/
export declare const AsnObjectIdentifierConverter: IAsnConverter<string, asn1js.ObjectIdentifier>;
/**
* ASN.1 BOOLEAN converter
*/
export declare const AsnBooleanConverter: IAsnConverter<boolean, asn1js.Boolean>;
/**
* ASN.1 OCTET_STRING converter
*/
export declare const AsnOctetStringConverter: IAsnConverter<ArrayBuffer, asn1js.OctetString>;
/**
* ASN.1 OCTET_STRING converter to OctetString class
*/
export declare const AsnConstructedOctetStringConverter: IAsnConverter<OctetString, asn1js.OctetString>;
/**
* ASN.1 UTF8_STRING converter
*/
export declare const AsnUtf8StringConverter: IAsnConverter<string, asn1js.AsnType>;
/**
* ASN.1 BPM STRING converter
*/
export declare const AsnBmpStringConverter: IAsnConverter<string, asn1js.AsnType>;
/**
* ASN.1 UNIVERSAL STRING converter
*/
export declare const AsnUniversalStringConverter: IAsnConverter<string, asn1js.AsnType>;
/**
* ASN.1 NUMERIC STRING converter
*/
export declare const AsnNumericStringConverter: IAsnConverter<string, asn1js.AsnType>;
/**
* ASN.1 PRINTABLE STRING converter
*/
export declare const AsnPrintableStringConverter: IAsnConverter<string, asn1js.AsnType>;
/**
* ASN.1 TELETEX STRING converter
*/
export declare const AsnTeletexStringConverter: IAsnConverter<string, asn1js.AsnType>;
/**
* ASN.1 VIDEOTEX STRING converter
*/
export declare const AsnVideotexStringConverter: IAsnConverter<string, asn1js.AsnType>;
/**
* ASN.1 IA5 STRING converter
*/
export declare const AsnIA5StringConverter: IAsnConverter<string, asn1js.AsnType>;
/**
* ASN.1 GRAPHIC STRING converter
*/
export declare const AsnGraphicStringConverter: IAsnConverter<string, asn1js.AsnType>;
/**
* ASN.1 VISIBLE STRING converter
*/
export declare const AsnVisibleStringConverter: IAsnConverter<string, asn1js.AsnType>;
/**
* ASN.1 GENERAL STRING converter
*/
export declare const AsnGeneralStringConverter: IAsnConverter<string, asn1js.AsnType>;
/**
* ASN.1 CHARACTER STRING converter
*/
export declare const AsnCharacterStringConverter: IAsnConverter<string, asn1js.AsnType>;
/**
* ASN.1 UTCTime converter
*/
export declare const AsnUTCTimeConverter: IAsnConverter<Date, asn1js.UTCTime>;
/**
* ASN.1 GeneralizedTime converter
*/
export declare const AsnGeneralizedTimeConverter: IAsnConverter<Date, asn1js.GeneralizedTime>;
/**
* ASN.1 ANY converter
*/
export declare const AsnNullConverter: IAsnConverter<null, asn1js.Null>;
/**
* Returns default converter for specified type
* @param type
*/
export declare function defaultConverter(type: AsnPropTypes): IAsnConverter | null;

View file

@ -0,0 +1,36 @@
import { AsnPropTypes, AsnTypeTypes } from "./enums";
import { IAsnConverter, IEmptyConstructor } from "./types";
export type AsnItemType<T = unknown> = AsnPropTypes | IEmptyConstructor<T>;
export interface IAsn1TypeOptions {
type: AsnTypeTypes;
itemType?: AsnItemType;
}
export type AsnRepeatTypeString = "sequence" | "set";
export type AsnRepeatType = AsnRepeatTypeString;
export interface IAsn1PropOptions {
type: AsnItemType;
optional?: boolean;
defaultValue?: unknown;
context?: number;
implicit?: boolean;
converter?: IAsnConverter;
repeated?: AsnRepeatType;
/**
* If true, the raw ASN.1 encoded bytes of the property will be stored in a separate property
* with 'Raw' suffix.
*/
raw?: boolean;
}
export type AsnTypeDecorator = (target: IEmptyConstructor) => void;
export declare const AsnType: (options: IAsn1TypeOptions) => AsnTypeDecorator;
export declare const AsnChoiceType: () => AsnTypeDecorator;
export interface IAsn1SetOptions {
itemType: AsnItemType;
}
export declare const AsnSetType: (options: IAsn1SetOptions) => AsnTypeDecorator;
export interface IAsn1SequenceOptions {
itemType?: AsnItemType;
}
export declare const AsnSequenceType: (options: IAsn1SequenceOptions) => AsnTypeDecorator;
export type AsnPropDecorator = (target: object, propertyKey: string) => void;
export declare const AsnProp: (options: IAsn1PropOptions) => AsnPropDecorator;

View file

@ -0,0 +1,40 @@
/**
* ASN.1 types for classes
*/
export declare enum AsnTypeTypes {
Sequence = 0,
Set = 1,
Choice = 2
}
/**
* ASN.1 types for properties
*/
export declare enum AsnPropTypes {
Any = 1,
Boolean = 2,
OctetString = 3,
BitString = 4,
Integer = 5,
Enumerated = 6,
ObjectIdentifier = 7,
Utf8String = 8,
BmpString = 9,
UniversalString = 10,
NumericString = 11,
PrintableString = 12,
TeletexString = 13,
VideotexString = 14,
IA5String = 15,
GraphicString = 16,
VisibleString = 17,
GeneralString = 18,
CharacterString = 19,
UTCTime = 20,
GeneralizedTime = 21,
DATE = 22,
TimeOfDay = 23,
DateTime = 24,
Duration = 25,
TIME = 26,
Null = 27
}

View file

@ -0,0 +1 @@
export * from "./schema_validation";

View file

@ -0,0 +1,3 @@
export declare class AsnSchemaValidationError extends Error {
schemas: string[];
}

View file

@ -0,0 +1,5 @@
import { IAsnConvertible, IEmptyConstructor } from "./types";
export declare function isConvertible(target: IEmptyConstructor): target is new () => IAsnConvertible;
export declare function isConvertible(target: unknown): target is IAsnConvertible;
export declare function isTypeOfArray(target: unknown): target is typeof Array;
export declare function isArrayEqual(bytes1: ArrayBuffer, bytes2: ArrayBuffer): boolean;

View file

@ -0,0 +1,10 @@
export * from "./converters";
export * from "./types/index";
export { AsnProp, AsnType, AsnChoiceType, AsnSequenceType, AsnSetType, } from "./decorators";
export { AsnTypeTypes, AsnPropTypes } from "./enums";
export { AsnParser } from "./parser";
export { AsnSerializer } from "./serializer";
export { IAsnConverter, IAsnConvertible, IAsnParseOptions, } from "./types";
export * from "./errors";
export * from "./objects";
export * from "./convert";

View file

@ -0,0 +1,3 @@
export declare abstract class AsnArray<T> extends Array<T> {
constructor(items?: T[]);
}

View file

@ -0,0 +1,72 @@
import * as asn1js from "asn1js";
import { type BufferSourceLike } from "@peculiar/utils/bytes";
import { IEmptyConstructor, IAsnParseOptions } from "./types";
/**
* Deserializes objects from ASN.1 encoded data
*/
export declare class AsnParser {
/**
* Deserializes an object from the ASN.1 encoded buffer
* @param data ASN.1 encoded buffer
* @param target Target schema for object deserialization
*/
static parse<T>(data: BufferSourceLike, target: IEmptyConstructor<T>, options?: IAsnParseOptions): T;
/**
* Deserializes an object from the asn1js object
* @param asn1Schema asn1js object
* @param target Target schema for object deserialization
*/
static fromASN<T>(asn1Schema: asn1js.AsnType, target: IEmptyConstructor<T>, options?: IAsnParseOptions): T;
/**
* Handles Choice types with context tags (IMPLICIT) and IMPLICIT tagging
*/
private static handleChoiceTypes;
/**
* Handles SEQUENCE types with optional CHOICE fields and schema comparison
*/
private static handleSequenceTypes;
/**
* Processes repeated fields in manual mapping
*/
private static processRepeatedField;
/**
* Processes primitive fields in manual mapping
*/
private static processPrimitiveField;
/**
* Checks if a schema item is an optional CHOICE field
*/
private static isOptionalChoiceField;
/**
* Processes optional CHOICE fields in manual mapping
*/
private static processOptionalChoiceField;
/**
* Handles array types
*/
private static handleArrayTypes;
/**
* Processes all schema items
*/
private static processSchemaItems;
/**
* Processes primitive schema items
*/
private static processPrimitiveSchemaItem;
/**
* Processes repeated primitive items
*/
private static processRepeatedPrimitiveItem;
/**
* Processes single primitive items
*/
private static processSinglePrimitiveItem;
/**
* Processes complex schema items (SEQUENCE, SET, CHOICE)
*/
private static processComplexSchemaItem;
/**
* Handles IMPLICIT tagging for complex types
*/
private static handleImplicitTagging;
}

View file

@ -0,0 +1,32 @@
import * as asn1js from "asn1js";
import { AsnRepeatType } from "./decorators";
import { AsnPropTypes, AsnTypeTypes } from "./enums";
import { IAsnConverter, IEmptyConstructor } from "./types";
export interface IAsnSchemaItem {
type: AsnPropTypes | IEmptyConstructor;
optional?: boolean;
defaultValue?: unknown;
context?: number;
implicit?: boolean;
converter?: IAsnConverter;
repeated?: AsnRepeatType;
raw?: boolean;
}
export interface IAsnSchema {
type: AsnTypeTypes;
itemType: AsnPropTypes | IEmptyConstructor;
items: Record<string, IAsnSchemaItem>;
schema?: AsnSchemaType;
}
export type AsnSchemaType = asn1js.Sequence | asn1js.Set | asn1js.Choice;
export declare class AsnSchemaStorage {
protected items: WeakMap<object, IAsnSchema>;
has(target: object): boolean;
get(target: IEmptyConstructor, checkSchema: true): IAsnSchema & Required<Pick<IAsnSchema, "schema">>;
get(target: IEmptyConstructor, checkSchema?: false): IAsnSchema;
cache(target: IEmptyConstructor): void;
createDefault(target: object): IAsnSchema;
create(target: object, useNames: boolean): AsnSchemaType;
set(target: object, schema: IAsnSchema): this;
protected findParentSchema(target: object): IAsnSchema | null;
}

View file

@ -0,0 +1,17 @@
import * as asn1js from "asn1js";
/**
* Serializes objects into ASN.1 encoded data
*/
export declare class AsnSerializer {
/**
* Serializes an object to the ASN.1 encoded buffer
* @param obj The object to serialize
*/
static serialize(obj: unknown): ArrayBuffer;
/**
* Serialize an object to the asn1js object
* @param obj The object to serialize
*/
static toASN(obj: unknown): asn1js.AsnType;
private static toAsnItem;
}

View file

@ -0,0 +1,2 @@
import { AsnSchemaStorage } from "./schema";
export declare const schemaStorage: AsnSchemaStorage;

View file

@ -0,0 +1,42 @@
/**
* ASN1 type
*/
import * as asn1js from "asn1js";
export type IEmptyConstructor<T = unknown> = new () => T;
/**
* Options for parsing ASN.1 encoded data
*/
export interface IAsnParseOptions {
/**
* Resource limits forwarded to `asn1js.fromBER` for untrusted input
* (`maxDepth`, `maxNodes`, `maxContentLength`). When omitted, the asn1js
* defaults apply (maxDepth: 100, maxNodes: 10000, maxContentLength: 16MB).
*/
berOptions?: asn1js.FromBerOptions;
}
/**
* Allows to convert ASN.1 object to JS value and back
*/
export interface IAsnConverter<T = unknown, AsnType = asn1js.AsnType> {
/**
* Returns JS value from ASN.1 object
* @param value ASN.1 object from asn1js module
*/
fromASN(value: AsnType): T;
/**
* Returns ASN.1 object from JS value
* @param value JS value
*/
toASN(value: T): AsnType;
}
export type IntegerConverterType = string | number;
export type AnyConverterType = ArrayBuffer | null;
/**
* Allows an object to control its own ASN.1 serialization and deserialization
*/
export interface IAsnConvertible<T = asn1js.AsnType> {
fromASN(asn: T): this;
toASN(): T;
toSchema(name: string): asn1js.BaseBlock;
}
export type IAsnConvertibleConstructor = new () => IAsnConvertible;

View file

@ -0,0 +1,15 @@
import * as asn1js from "asn1js";
import { type BufferSourceLike } from "@peculiar/utils/bytes";
import { IAsnConvertible } from "../types";
export declare class BitString<T extends number = number> implements IAsnConvertible {
unusedBits: number;
value: ArrayBuffer;
constructor();
constructor(value: T);
constructor(value: BufferSourceLike, unusedBits?: number);
fromASN(asn: asn1js.BitString): this;
toASN(): asn1js.BitString;
toSchema(name: string): asn1js.BitString;
toNumber(): T;
fromNumber(value: T): void;
}

View file

@ -0,0 +1,2 @@
export * from "./bit_string";
export * from "./octet_string";

View file

@ -0,0 +1,15 @@
import * as asn1js from "asn1js";
import { BufferSourceLike } from "@peculiar/utils/bytes";
import { IAsnConvertible } from "../types";
export declare class OctetString implements IAsnConvertible, ArrayBufferView {
buffer: ArrayBuffer;
get byteLength(): number;
get byteOffset(): number;
constructor();
constructor(byteLength: number);
constructor(bytes: number[]);
constructor(bytes: BufferSourceLike);
fromASN(asn: asn1js.OctetString): this;
toASN(): asn1js.OctetString;
toSchema(name: string): asn1js.OctetString;
}

View file

@ -0,0 +1,71 @@
{
"name": "@peculiar/asn1-schema",
"version": "2.8.0",
"description": "Decorators and helper APIs for declaring ASN.1 schemas in TypeScript.",
"keywords": [
"asn",
"asn1",
"schema",
"serialize",
"parse",
"decorator",
"der"
],
"author": "PeculiarVentures, LLC",
"license": "MIT",
"files": [
"build/**/*.{js,d.ts}",
"build/es2015/package.json",
"LICENSE",
"README.md"
],
"main": "build/cjs/index.js",
"module": "build/es2015/index.js",
"types": "build/types/index.d.ts",
"exports": {
".": {
"types": "./build/types/index.d.ts",
"import": "./build/es2015/index.js",
"require": "./build/cjs/index.js"
},
"./package.json": "./package.json"
},
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/PeculiarVentures/asn1-schema",
"directory": "packages/schema"
},
"bugs": {
"url": "https://github.com/PeculiarVentures/asn1-schema/issues"
},
"homepage": "https://github.com/PeculiarVentures/asn1-schema/tree/master/packages/schema#readme",
"scripts": {
"clear": "rimraf build",
"build": "npm run build:module && npm run build:types",
"build:module": "npm run build:cjs && npm run build:es2015",
"build:cjs": "tsc -p tsconfig.compile.json --removeComments --module commonjs --outDir build/cjs",
"build:es2015": "tsc -p tsconfig.compile.json --removeComments --module ES2015 --outDir build/es2015",
"postbuild:es2015": "node ../../scripts/prepare_esm_package.mjs build/es2015",
"prebuild:types": "rimraf build/types",
"build:types": "tsc -p tsconfig.compile.json --outDir build/types --declaration --emitDeclarationOnly",
"rebuild": "npm run clear && npm run build"
},
"dependencies": {
"@peculiar/utils": "^2.0.2",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
},
"contributors": [
{
"email": "rmh@unmitigatedrisk.com",
"name": "Ryan Hurst"
},
{
"email": "microshine@mail.ru",
"name": "Miroshin Stepan"
}
]
}

21
electron/node_modules/@peculiar/json-schema/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

158
electron/node_modules/@peculiar/json-schema/README.md generated vendored Normal file
View file

@ -0,0 +1,158 @@
# JSON-SCHEMA
[![License](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://raw.githubusercontent.com/PeculiarVentures/json-schema/master/LICENSE.md)
[![CircleCI](https://circleci.com/gh/PeculiarVentures/json-schema.svg?style=svg)](https://circleci.com/gh/PeculiarVentures/json-schema)
[![Coverage Status](https://coveralls.io/repos/github/PeculiarVentures/json-schema/badge.svg?branch=master&t=ddJivl)](https://coveralls.io/github/PeculiarVentures/json-schema?branch=master)
[![npm version](https://badge.fury.io/js/%40peculiar%2Fjson-schema.svg)](https://badge.fury.io/js/%40peculiar%2Fjson-schema)
[![NPM](https://nodei.co/npm/@peculiar/json-schema.png)](https://nodei.co/npm/@peculiar/json-schema/)
This package uses ES2015 [decorators](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841) to simplify JSON [schema creation and use](https://json-schema.org/understanding-json-schema/index.html).
## Introduction
JSON (JavaScript Object Notation) is a lightweight data-interchange format that was designed to be easy for humans to read and write but in practice, it is [minefield](http://seriot.ch/parsing_json.html) when it machines need to parse it.
While the use of schemas can help with this problem their use can be complicated. When using `json-schema` this is addressed by using decorators to make both serialization and parsing of XML possible via a simple class that handles the schemas for you.
This is important because validating input data before its use is important to do because all input data is evil. Using a schema helps you handle this data [safely](https://www.whitehatsec.com/blog/handling-untrusted-json-safely/).
## Installation
Installation is handled via `npm`:
```
$ npm install @peculiar/json-schema
```
## Examples
### Node.js
Creating a schema:
```js
import { JsonParser, JsonSerializer, JsonProp, JsonPropTypes, IJsonConverter } from "@peculiar/json-schema";
// custom data converter
const JsonBase64UrlConverter: IJsonConverter<Uint8Array, string> = {
fromJSON: (value: string) => base64UrlToBuffer(value),
toJSON: (value: Uint8Array) => bufferToBase64Url(value),
};
class EcPublicKey {
@JsonProp({ name: "kty" })
keyType = "EC";
@JsonProp({ name: "crv" })
namedCurve = "";
@JsonProp({ converter: JsonBase64UrlConverter })
x = new Uint8Array(0);
@JsonProp({ converter: JsonBase64UrlConverter })
y = new Uint8Array(0);
@JsonProp({ name: "ext", type: JsonPropTypes.Boolean, optional: true })
extractable = false;
@JsonProp({ name: "key_ops", type: JsonPropTypes.String, repeated: true, optional: true })
usages: string[] = [];
}
const json = `{
"kty": "EC",
"crv": "P-256",
"x": "zCQ5BPHPCLZYgdpo1n-x_90P2Ij52d53YVwTh3ZdiMo",
"y": "pDfQTUx0-OiZc5ZuKMcA7v2Q7ZPKsQwzB58bft0JTko",
"ext": true
}`;
const ecPubKey = JsonParser.parse(json, { targetSchema: EcPublicKey });
console.log(ecPubKey);
ecPubKey.usages.push("verify");
const jsonText = JsonSerializer.serialize(ecPubKey, undefined, undefined, 2);
console.log(jsonText);
// Output
//
// EcPublicKey {keyType: "EC", namedCurve: "P-256", x: Uint8Array(32), y: Uint8Array(32), extractable: true, …}
//
// {
// "kty": "EC",
// "crv": "P-256",
// "x": "zCQ5BPHPCLZYgdpo1n+x/90P2Ij52d53YVwTh3ZdiMo=",
// "y": "pDfQTUx0+OiZc5ZuKMcA7v2Q7ZPKsQwzB58bft0JTko=",
// "ext": true,
// "key_ops": [
// "verify"
// ]
// }
```
Extending a Schema:
```js
class BaseObject {
@JsonProp({ name: "i" })
public id = 0;
}
class Word extends BaseObject {
@JsonProp({ name: "t" })
public text = "";
}
class Person extends BaseObject {
@JsonProp({ name: "n" })
public name = 0;
@JsonProp({ name: "w", repeated: true, type: Word })
public words = [];
}
const json = `{
"i":1,
"n":"Bob",
"w":[
{"i":2,"t":"hello"},
{"i":3,"t":"world"}
]
}`;
const person = JsonParser.parse(json, { targetSchema: Person });
console.log(person);
const word = new Word();
word.id = 4;
word.text = "!!!";
const jsonText = JsonSerializer.serialize(person, undefined, undefined, 2);
console.log(jsonText);
// Output
//
// Person {id: 1, name: "Bob", words: [Word {id: 2, text: "hello"}, Word {id: 3, text: "world"}]}
// {
// "i": 1,
// "n": "Bob",
// "w": [
// {
// "i": 2,
// "t": "hello"
// },
// {
// "i": 3,
// "t": "world"
// },
// {
// "i": 4,
// "t": "!!!"
// }
// ]
// }
```
## API
Use [index.d.ts](index.d.ts) file

View file

@ -0,0 +1,484 @@
/**
* Copyright (c) 2020, Peculiar Ventures, All rights reserved.
*/
class JsonError extends Error {
constructor(message, innerError) {
super(innerError
? `${message}. See the inner exception for more details.`
: message);
this.message = message;
this.innerError = innerError;
}
}
class TransformError extends JsonError {
constructor(schema, message, innerError) {
super(message, innerError);
this.schema = schema;
}
}
class ParserError extends TransformError {
constructor(schema, message, innerError) {
super(schema, `JSON doesn't match to '${schema.target.name}' schema. ${message}`, innerError);
}
}
class ValidationError extends JsonError {
}
class SerializerError extends JsonError {
constructor(schemaName, message, innerError) {
super(`Cannot serialize by '${schemaName}' schema. ${message}`, innerError);
this.schemaName = schemaName;
}
}
class KeyError extends ParserError {
constructor(schema, keys, errors = {}) {
super(schema, "Some keys doesn't match to schema");
this.keys = keys;
this.errors = errors;
}
}
var JsonPropTypes;
(function (JsonPropTypes) {
JsonPropTypes[JsonPropTypes["Any"] = 0] = "Any";
JsonPropTypes[JsonPropTypes["Boolean"] = 1] = "Boolean";
JsonPropTypes[JsonPropTypes["Number"] = 2] = "Number";
JsonPropTypes[JsonPropTypes["String"] = 3] = "String";
})(JsonPropTypes || (JsonPropTypes = {}));
function checkType(value, type) {
switch (type) {
case JsonPropTypes.Boolean:
return typeof value === "boolean";
case JsonPropTypes.Number:
return typeof value === "number";
case JsonPropTypes.String:
return typeof value === "string";
}
return true;
}
function throwIfTypeIsWrong(value, type) {
if (!checkType(value, type)) {
throw new TypeError(`Value must be ${JsonPropTypes[type]}`);
}
}
function isConvertible(target) {
if (target && target.prototype) {
if (target.prototype.toJSON && target.prototype.fromJSON) {
return true;
}
else {
return isConvertible(target.prototype);
}
}
else {
return !!(target && target.toJSON && target.fromJSON);
}
}
class JsonSchemaStorage {
constructor() {
this.items = new Map();
}
has(target) {
return this.items.has(target) || !!this.findParentSchema(target);
}
get(target) {
const schema = this.items.get(target) || this.findParentSchema(target);
if (!schema) {
throw new Error("Cannot get schema for current target");
}
return schema;
}
create(target) {
const schema = { names: {} };
const parentSchema = this.findParentSchema(target);
if (parentSchema) {
Object.assign(schema, parentSchema);
schema.names = {};
for (const name in parentSchema.names) {
schema.names[name] = Object.assign({}, parentSchema.names[name]);
}
}
schema.target = target;
return schema;
}
set(target, schema) {
this.items.set(target, schema);
return this;
}
findParentSchema(target) {
const parent = target.__proto__;
if (parent) {
const schema = this.items.get(parent);
return schema || this.findParentSchema(parent);
}
return null;
}
}
const DEFAULT_SCHEMA = "default";
const schemaStorage = new JsonSchemaStorage();
class PatternValidation {
constructor(pattern) {
this.pattern = new RegExp(pattern);
}
validate(value) {
const pattern = new RegExp(this.pattern.source, this.pattern.flags);
if (typeof value !== "string") {
throw new ValidationError("Incoming value must be string");
}
if (!pattern.exec(value)) {
throw new ValidationError(`Value doesn't match to pattern '${pattern.toString()}'`);
}
}
}
class InclusiveValidation {
constructor(min = Number.MIN_VALUE, max = Number.MAX_VALUE) {
this.min = min;
this.max = max;
}
validate(value) {
throwIfTypeIsWrong(value, JsonPropTypes.Number);
if (!(this.min <= value && value <= this.max)) {
const min = this.min === Number.MIN_VALUE ? "MIN" : this.min;
const max = this.max === Number.MAX_VALUE ? "MAX" : this.max;
throw new ValidationError(`Value doesn't match to diapason [${min},${max}]`);
}
}
}
class ExclusiveValidation {
constructor(min = Number.MIN_VALUE, max = Number.MAX_VALUE) {
this.min = min;
this.max = max;
}
validate(value) {
throwIfTypeIsWrong(value, JsonPropTypes.Number);
if (!(this.min < value && value < this.max)) {
const min = this.min === Number.MIN_VALUE ? "MIN" : this.min;
const max = this.max === Number.MAX_VALUE ? "MAX" : this.max;
throw new ValidationError(`Value doesn't match to diapason (${min},${max})`);
}
}
}
class LengthValidation {
constructor(length, minLength, maxLength) {
this.length = length;
this.minLength = minLength;
this.maxLength = maxLength;
}
validate(value) {
if (this.length !== undefined) {
if (value.length !== this.length) {
throw new ValidationError(`Value length must be exactly ${this.length}.`);
}
return;
}
if (this.minLength !== undefined) {
if (value.length < this.minLength) {
throw new ValidationError(`Value length must be more than ${this.minLength}.`);
}
}
if (this.maxLength !== undefined) {
if (value.length > this.maxLength) {
throw new ValidationError(`Value length must be less than ${this.maxLength}.`);
}
}
}
}
class EnumerationValidation {
constructor(enumeration) {
this.enumeration = enumeration;
}
validate(value) {
throwIfTypeIsWrong(value, JsonPropTypes.String);
if (!this.enumeration.includes(value)) {
throw new ValidationError(`Value must be one of ${this.enumeration.map((v) => `'${v}'`).join(", ")}`);
}
}
}
class JsonTransform {
static checkValues(data, schemaItem) {
const values = Array.isArray(data) ? data : [data];
for (const value of values) {
for (const validation of schemaItem.validations) {
if (validation instanceof LengthValidation && schemaItem.repeated) {
validation.validate(data);
}
else {
validation.validate(value);
}
}
}
}
static checkTypes(value, schemaItem) {
if (schemaItem.repeated && !Array.isArray(value)) {
throw new TypeError("Value must be Array");
}
if (typeof schemaItem.type === "number") {
const values = Array.isArray(value) ? value : [value];
for (const v of values) {
throwIfTypeIsWrong(v, schemaItem.type);
}
}
}
static getSchemaByName(schema, name = DEFAULT_SCHEMA) {
return { ...schema.names[DEFAULT_SCHEMA], ...schema.names[name] };
}
}
class JsonSerializer extends JsonTransform {
static serialize(obj, options, replacer, space) {
const json = this.toJSON(obj, options);
return JSON.stringify(json, replacer, space);
}
static toJSON(obj, options = {}) {
let res;
let targetSchema = options.targetSchema;
const schemaName = options.schemaName || DEFAULT_SCHEMA;
if (isConvertible(obj)) {
return obj.toJSON();
}
if (Array.isArray(obj)) {
res = [];
for (const item of obj) {
res.push(this.toJSON(item, options));
}
}
else if (typeof obj === "object") {
if (targetSchema && !schemaStorage.has(targetSchema)) {
throw new JsonError("Cannot get schema for `targetSchema` param");
}
targetSchema = (targetSchema || obj.constructor);
if (schemaStorage.has(targetSchema)) {
const schema = schemaStorage.get(targetSchema);
res = {};
const namedSchema = this.getSchemaByName(schema, schemaName);
for (const key in namedSchema) {
try {
const item = namedSchema[key];
const objItem = obj[key];
let value;
if ((item.optional && objItem === undefined)
|| (item.defaultValue !== undefined && objItem === item.defaultValue)) {
continue;
}
if (!item.optional && objItem === undefined) {
throw new SerializerError(targetSchema.name, `Property '${key}' is required.`);
}
if (typeof item.type === "number") {
if (item.converter) {
if (item.repeated) {
value = objItem.map((el) => item.converter.toJSON(el, obj));
}
else {
value = item.converter.toJSON(objItem, obj);
}
}
else {
value = objItem;
}
}
else {
if (item.repeated) {
value = objItem.map((el) => this.toJSON(el, { schemaName }));
}
else {
value = this.toJSON(objItem, { schemaName });
}
}
this.checkTypes(value, item);
this.checkValues(value, item);
res[item.name || key] = value;
}
catch (e) {
if (e instanceof SerializerError) {
throw e;
}
else {
throw new SerializerError(schema.target.name, `Property '${key}' is wrong. ${e.message}`, e);
}
}
}
}
else {
res = {};
for (const key in obj) {
res[key] = this.toJSON(obj[key], { schemaName });
}
}
}
else {
res = obj;
}
return res;
}
}
class JsonParser extends JsonTransform {
static parse(data, options) {
const obj = JSON.parse(data);
return this.fromJSON(obj, options);
}
static fromJSON(target, options) {
const targetSchema = options.targetSchema;
const schemaName = options.schemaName || DEFAULT_SCHEMA;
const obj = new targetSchema();
if (isConvertible(obj)) {
return obj.fromJSON(target);
}
const schema = schemaStorage.get(targetSchema);
const namedSchema = this.getSchemaByName(schema, schemaName);
const keyErrors = {};
if (options.strictProperty && !Array.isArray(target)) {
JsonParser.checkStrictProperty(target, namedSchema, schema);
}
for (const key in namedSchema) {
try {
const item = namedSchema[key];
const name = item.name || key;
const value = target[name];
if (value === undefined && (item.optional || item.defaultValue !== undefined)) {
continue;
}
if (!item.optional && value === undefined) {
throw new ParserError(schema, `Property '${name}' is required.`);
}
this.checkTypes(value, item);
this.checkValues(value, item);
if (typeof (item.type) === "number") {
if (item.converter) {
if (item.repeated) {
obj[key] = value.map((el) => item.converter.fromJSON(el, obj));
}
else {
obj[key] = item.converter.fromJSON(value, obj);
}
}
else {
obj[key] = value;
}
}
else {
const newOptions = {
...options,
targetSchema: item.type,
schemaName,
};
if (item.repeated) {
obj[key] = value.map((el) => this.fromJSON(el, newOptions));
}
else {
obj[key] = this.fromJSON(value, newOptions);
}
}
}
catch (e) {
if (!(e instanceof ParserError)) {
e = new ParserError(schema, `Property '${key}' is wrong. ${e.message}`, e);
}
if (options.strictAllKeys) {
keyErrors[key] = e;
}
else {
throw e;
}
}
}
const keys = Object.keys(keyErrors);
if (keys.length) {
throw new KeyError(schema, keys, keyErrors);
}
return obj;
}
static checkStrictProperty(target, namedSchema, schema) {
const jsonProps = Object.keys(target);
const schemaProps = Object.keys(namedSchema);
const keys = [];
for (const key of jsonProps) {
if (schemaProps.indexOf(key) === -1) {
keys.push(key);
}
}
if (keys.length) {
throw new KeyError(schema, keys);
}
}
}
function getValidations(item) {
const validations = [];
if (item.pattern) {
validations.push(new PatternValidation(item.pattern));
}
if (item.type === JsonPropTypes.Number || item.type === JsonPropTypes.Any) {
if (item.minInclusive !== undefined || item.maxInclusive !== undefined) {
validations.push(new InclusiveValidation(item.minInclusive, item.maxInclusive));
}
if (item.minExclusive !== undefined || item.maxExclusive !== undefined) {
validations.push(new ExclusiveValidation(item.minExclusive, item.maxExclusive));
}
if (item.enumeration !== undefined) {
validations.push(new EnumerationValidation(item.enumeration));
}
}
if (item.type === JsonPropTypes.String || item.repeated || item.type === JsonPropTypes.Any) {
if (item.length !== undefined || item.minLength !== undefined || item.maxLength !== undefined) {
validations.push(new LengthValidation(item.length, item.minLength, item.maxLength));
}
}
return validations;
}
const JsonProp = (options = {}) => (target, propertyKey) => {
const errorMessage = `Cannot set type for ${propertyKey} property of ${target.constructor.name} schema`;
let schema;
if (!schemaStorage.has(target.constructor)) {
schema = schemaStorage.create(target.constructor);
schemaStorage.set(target.constructor, schema);
}
else {
schema = schemaStorage.get(target.constructor);
if (schema.target !== target.constructor) {
schema = schemaStorage.create(target.constructor);
schemaStorage.set(target.constructor, schema);
}
}
const defaultSchema = {
type: JsonPropTypes.Any,
validations: [],
};
const copyOptions = Object.assign(defaultSchema, options);
copyOptions.validations = getValidations(copyOptions);
if (typeof copyOptions.type !== "number") {
if (!schemaStorage.has(copyOptions.type) && !isConvertible(copyOptions.type)) {
throw new Error(`${errorMessage}. Assigning type doesn't have schema.`);
}
}
let schemaNames;
if (Array.isArray(options.schema)) {
schemaNames = options.schema;
}
else {
schemaNames = [options.schema || DEFAULT_SCHEMA];
}
for (const schemaName of schemaNames) {
if (!schema.names[schemaName]) {
schema.names[schemaName] = {};
}
const namedSchema = schema.names[schemaName];
namedSchema[propertyKey] = copyOptions;
}
};
export { JsonError, JsonParser, JsonProp, JsonPropTypes, JsonSerializer, KeyError, ParserError, SerializerError, TransformError, ValidationError };

View file

@ -0,0 +1,495 @@
/**
* Copyright (c) 2020, Peculiar Ventures, All rights reserved.
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
class JsonError extends Error {
constructor(message, innerError) {
super(innerError
? `${message}. See the inner exception for more details.`
: message);
this.message = message;
this.innerError = innerError;
}
}
class TransformError extends JsonError {
constructor(schema, message, innerError) {
super(message, innerError);
this.schema = schema;
}
}
class ParserError extends TransformError {
constructor(schema, message, innerError) {
super(schema, `JSON doesn't match to '${schema.target.name}' schema. ${message}`, innerError);
}
}
class ValidationError extends JsonError {
}
class SerializerError extends JsonError {
constructor(schemaName, message, innerError) {
super(`Cannot serialize by '${schemaName}' schema. ${message}`, innerError);
this.schemaName = schemaName;
}
}
class KeyError extends ParserError {
constructor(schema, keys, errors = {}) {
super(schema, "Some keys doesn't match to schema");
this.keys = keys;
this.errors = errors;
}
}
(function (JsonPropTypes) {
JsonPropTypes[JsonPropTypes["Any"] = 0] = "Any";
JsonPropTypes[JsonPropTypes["Boolean"] = 1] = "Boolean";
JsonPropTypes[JsonPropTypes["Number"] = 2] = "Number";
JsonPropTypes[JsonPropTypes["String"] = 3] = "String";
})(exports.JsonPropTypes || (exports.JsonPropTypes = {}));
function checkType(value, type) {
switch (type) {
case exports.JsonPropTypes.Boolean:
return typeof value === "boolean";
case exports.JsonPropTypes.Number:
return typeof value === "number";
case exports.JsonPropTypes.String:
return typeof value === "string";
}
return true;
}
function throwIfTypeIsWrong(value, type) {
if (!checkType(value, type)) {
throw new TypeError(`Value must be ${exports.JsonPropTypes[type]}`);
}
}
function isConvertible(target) {
if (target && target.prototype) {
if (target.prototype.toJSON && target.prototype.fromJSON) {
return true;
}
else {
return isConvertible(target.prototype);
}
}
else {
return !!(target && target.toJSON && target.fromJSON);
}
}
class JsonSchemaStorage {
constructor() {
this.items = new Map();
}
has(target) {
return this.items.has(target) || !!this.findParentSchema(target);
}
get(target) {
const schema = this.items.get(target) || this.findParentSchema(target);
if (!schema) {
throw new Error("Cannot get schema for current target");
}
return schema;
}
create(target) {
const schema = { names: {} };
const parentSchema = this.findParentSchema(target);
if (parentSchema) {
Object.assign(schema, parentSchema);
schema.names = {};
for (const name in parentSchema.names) {
schema.names[name] = Object.assign({}, parentSchema.names[name]);
}
}
schema.target = target;
return schema;
}
set(target, schema) {
this.items.set(target, schema);
return this;
}
findParentSchema(target) {
const parent = target.__proto__;
if (parent) {
const schema = this.items.get(parent);
return schema || this.findParentSchema(parent);
}
return null;
}
}
const DEFAULT_SCHEMA = "default";
const schemaStorage = new JsonSchemaStorage();
class PatternValidation {
constructor(pattern) {
this.pattern = new RegExp(pattern);
}
validate(value) {
const pattern = new RegExp(this.pattern.source, this.pattern.flags);
if (typeof value !== "string") {
throw new ValidationError("Incoming value must be string");
}
if (!pattern.exec(value)) {
throw new ValidationError(`Value doesn't match to pattern '${pattern.toString()}'`);
}
}
}
class InclusiveValidation {
constructor(min = Number.MIN_VALUE, max = Number.MAX_VALUE) {
this.min = min;
this.max = max;
}
validate(value) {
throwIfTypeIsWrong(value, exports.JsonPropTypes.Number);
if (!(this.min <= value && value <= this.max)) {
const min = this.min === Number.MIN_VALUE ? "MIN" : this.min;
const max = this.max === Number.MAX_VALUE ? "MAX" : this.max;
throw new ValidationError(`Value doesn't match to diapason [${min},${max}]`);
}
}
}
class ExclusiveValidation {
constructor(min = Number.MIN_VALUE, max = Number.MAX_VALUE) {
this.min = min;
this.max = max;
}
validate(value) {
throwIfTypeIsWrong(value, exports.JsonPropTypes.Number);
if (!(this.min < value && value < this.max)) {
const min = this.min === Number.MIN_VALUE ? "MIN" : this.min;
const max = this.max === Number.MAX_VALUE ? "MAX" : this.max;
throw new ValidationError(`Value doesn't match to diapason (${min},${max})`);
}
}
}
class LengthValidation {
constructor(length, minLength, maxLength) {
this.length = length;
this.minLength = minLength;
this.maxLength = maxLength;
}
validate(value) {
if (this.length !== undefined) {
if (value.length !== this.length) {
throw new ValidationError(`Value length must be exactly ${this.length}.`);
}
return;
}
if (this.minLength !== undefined) {
if (value.length < this.minLength) {
throw new ValidationError(`Value length must be more than ${this.minLength}.`);
}
}
if (this.maxLength !== undefined) {
if (value.length > this.maxLength) {
throw new ValidationError(`Value length must be less than ${this.maxLength}.`);
}
}
}
}
class EnumerationValidation {
constructor(enumeration) {
this.enumeration = enumeration;
}
validate(value) {
throwIfTypeIsWrong(value, exports.JsonPropTypes.String);
if (!this.enumeration.includes(value)) {
throw new ValidationError(`Value must be one of ${this.enumeration.map((v) => `'${v}'`).join(", ")}`);
}
}
}
class JsonTransform {
static checkValues(data, schemaItem) {
const values = Array.isArray(data) ? data : [data];
for (const value of values) {
for (const validation of schemaItem.validations) {
if (validation instanceof LengthValidation && schemaItem.repeated) {
validation.validate(data);
}
else {
validation.validate(value);
}
}
}
}
static checkTypes(value, schemaItem) {
if (schemaItem.repeated && !Array.isArray(value)) {
throw new TypeError("Value must be Array");
}
if (typeof schemaItem.type === "number") {
const values = Array.isArray(value) ? value : [value];
for (const v of values) {
throwIfTypeIsWrong(v, schemaItem.type);
}
}
}
static getSchemaByName(schema, name = DEFAULT_SCHEMA) {
return { ...schema.names[DEFAULT_SCHEMA], ...schema.names[name] };
}
}
class JsonSerializer extends JsonTransform {
static serialize(obj, options, replacer, space) {
const json = this.toJSON(obj, options);
return JSON.stringify(json, replacer, space);
}
static toJSON(obj, options = {}) {
let res;
let targetSchema = options.targetSchema;
const schemaName = options.schemaName || DEFAULT_SCHEMA;
if (isConvertible(obj)) {
return obj.toJSON();
}
if (Array.isArray(obj)) {
res = [];
for (const item of obj) {
res.push(this.toJSON(item, options));
}
}
else if (typeof obj === "object") {
if (targetSchema && !schemaStorage.has(targetSchema)) {
throw new JsonError("Cannot get schema for `targetSchema` param");
}
targetSchema = (targetSchema || obj.constructor);
if (schemaStorage.has(targetSchema)) {
const schema = schemaStorage.get(targetSchema);
res = {};
const namedSchema = this.getSchemaByName(schema, schemaName);
for (const key in namedSchema) {
try {
const item = namedSchema[key];
const objItem = obj[key];
let value;
if ((item.optional && objItem === undefined)
|| (item.defaultValue !== undefined && objItem === item.defaultValue)) {
continue;
}
if (!item.optional && objItem === undefined) {
throw new SerializerError(targetSchema.name, `Property '${key}' is required.`);
}
if (typeof item.type === "number") {
if (item.converter) {
if (item.repeated) {
value = objItem.map((el) => item.converter.toJSON(el, obj));
}
else {
value = item.converter.toJSON(objItem, obj);
}
}
else {
value = objItem;
}
}
else {
if (item.repeated) {
value = objItem.map((el) => this.toJSON(el, { schemaName }));
}
else {
value = this.toJSON(objItem, { schemaName });
}
}
this.checkTypes(value, item);
this.checkValues(value, item);
res[item.name || key] = value;
}
catch (e) {
if (e instanceof SerializerError) {
throw e;
}
else {
throw new SerializerError(schema.target.name, `Property '${key}' is wrong. ${e.message}`, e);
}
}
}
}
else {
res = {};
for (const key in obj) {
res[key] = this.toJSON(obj[key], { schemaName });
}
}
}
else {
res = obj;
}
return res;
}
}
class JsonParser extends JsonTransform {
static parse(data, options) {
const obj = JSON.parse(data);
return this.fromJSON(obj, options);
}
static fromJSON(target, options) {
const targetSchema = options.targetSchema;
const schemaName = options.schemaName || DEFAULT_SCHEMA;
const obj = new targetSchema();
if (isConvertible(obj)) {
return obj.fromJSON(target);
}
const schema = schemaStorage.get(targetSchema);
const namedSchema = this.getSchemaByName(schema, schemaName);
const keyErrors = {};
if (options.strictProperty && !Array.isArray(target)) {
JsonParser.checkStrictProperty(target, namedSchema, schema);
}
for (const key in namedSchema) {
try {
const item = namedSchema[key];
const name = item.name || key;
const value = target[name];
if (value === undefined && (item.optional || item.defaultValue !== undefined)) {
continue;
}
if (!item.optional && value === undefined) {
throw new ParserError(schema, `Property '${name}' is required.`);
}
this.checkTypes(value, item);
this.checkValues(value, item);
if (typeof (item.type) === "number") {
if (item.converter) {
if (item.repeated) {
obj[key] = value.map((el) => item.converter.fromJSON(el, obj));
}
else {
obj[key] = item.converter.fromJSON(value, obj);
}
}
else {
obj[key] = value;
}
}
else {
const newOptions = {
...options,
targetSchema: item.type,
schemaName,
};
if (item.repeated) {
obj[key] = value.map((el) => this.fromJSON(el, newOptions));
}
else {
obj[key] = this.fromJSON(value, newOptions);
}
}
}
catch (e) {
if (!(e instanceof ParserError)) {
e = new ParserError(schema, `Property '${key}' is wrong. ${e.message}`, e);
}
if (options.strictAllKeys) {
keyErrors[key] = e;
}
else {
throw e;
}
}
}
const keys = Object.keys(keyErrors);
if (keys.length) {
throw new KeyError(schema, keys, keyErrors);
}
return obj;
}
static checkStrictProperty(target, namedSchema, schema) {
const jsonProps = Object.keys(target);
const schemaProps = Object.keys(namedSchema);
const keys = [];
for (const key of jsonProps) {
if (schemaProps.indexOf(key) === -1) {
keys.push(key);
}
}
if (keys.length) {
throw new KeyError(schema, keys);
}
}
}
function getValidations(item) {
const validations = [];
if (item.pattern) {
validations.push(new PatternValidation(item.pattern));
}
if (item.type === exports.JsonPropTypes.Number || item.type === exports.JsonPropTypes.Any) {
if (item.minInclusive !== undefined || item.maxInclusive !== undefined) {
validations.push(new InclusiveValidation(item.minInclusive, item.maxInclusive));
}
if (item.minExclusive !== undefined || item.maxExclusive !== undefined) {
validations.push(new ExclusiveValidation(item.minExclusive, item.maxExclusive));
}
if (item.enumeration !== undefined) {
validations.push(new EnumerationValidation(item.enumeration));
}
}
if (item.type === exports.JsonPropTypes.String || item.repeated || item.type === exports.JsonPropTypes.Any) {
if (item.length !== undefined || item.minLength !== undefined || item.maxLength !== undefined) {
validations.push(new LengthValidation(item.length, item.minLength, item.maxLength));
}
}
return validations;
}
const JsonProp = (options = {}) => (target, propertyKey) => {
const errorMessage = `Cannot set type for ${propertyKey} property of ${target.constructor.name} schema`;
let schema;
if (!schemaStorage.has(target.constructor)) {
schema = schemaStorage.create(target.constructor);
schemaStorage.set(target.constructor, schema);
}
else {
schema = schemaStorage.get(target.constructor);
if (schema.target !== target.constructor) {
schema = schemaStorage.create(target.constructor);
schemaStorage.set(target.constructor, schema);
}
}
const defaultSchema = {
type: exports.JsonPropTypes.Any,
validations: [],
};
const copyOptions = Object.assign(defaultSchema, options);
copyOptions.validations = getValidations(copyOptions);
if (typeof copyOptions.type !== "number") {
if (!schemaStorage.has(copyOptions.type) && !isConvertible(copyOptions.type)) {
throw new Error(`${errorMessage}. Assigning type doesn't have schema.`);
}
}
let schemaNames;
if (Array.isArray(options.schema)) {
schemaNames = options.schema;
}
else {
schemaNames = [options.schema || DEFAULT_SCHEMA];
}
for (const schemaName of schemaNames) {
if (!schema.names[schemaName]) {
schema.names[schemaName] = {};
}
const namedSchema = schema.names[schemaName];
namedSchema[propertyKey] = copyOptions;
}
};
exports.JsonError = JsonError;
exports.JsonParser = JsonParser;
exports.JsonProp = JsonProp;
exports.JsonSerializer = JsonSerializer;
exports.KeyError = KeyError;
exports.ParserError = ParserError;
exports.SerializerError = SerializerError;
exports.TransformError = TransformError;
exports.ValidationError = ValidationError;

View file

@ -0,0 +1,51 @@
import { JsonPropTypes } from "./prop_types";
import { IEmptyConstructor, IJsonConverter } from "./types";
export interface IJsonPropOptions {
type?: JsonPropTypes | IEmptyConstructor<any>;
optional?: boolean;
defaultValue?: any;
converter?: IJsonConverter<any, any>;
repeated?: boolean;
name?: string;
/**
* Defines name of schema
*/
schema?: string | string[];
/**
* Defines regular expression for text
*/
pattern?: string | RegExp;
/**
* Defines a list of acceptable values
*/
enumeration?: string[];
/**
* Specifies the exact number of characters or list items allowed. Must be equal to or greater than zero
*/
length?: number;
/**
* Specifies the minimum number of characters or list items allowed. Must be equal to or greater than zero
*/
minLength?: number;
/**
* Specifies the maximum number of characters or list items allowed. Must be equal to or greater than zero
*/
maxLength?: number;
/**
* Specifies the lower bounds for numeric values (the value must be greater than or equal to this value)
*/
minInclusive?: number;
/**
* Specifies the upper bounds for numeric values (the value must be less than or equal to this value)
*/
maxInclusive?: number;
/**
* Specifies the lower bounds for numeric values (the value must be greater than this value)
*/
minExclusive?: number;
/**
* Specifies the upper bounds for numeric values (the value must be less than this value)
*/
maxExclusive?: number;
}
export declare const JsonProp: (options?: IJsonPropOptions) => (target: object, propertyKey: string) => void;

View file

@ -0,0 +1,6 @@
export * from "./json_error";
export * from "./parser_error";
export * from "./validation_error";
export * from "./serializer_error";
export * from "./transform_error";
export * from "./key_error";

View file

@ -0,0 +1,5 @@
export declare class JsonError extends Error {
message: string;
innerError?: Error | undefined;
constructor(message: string, innerError?: Error | undefined);
}

View file

@ -0,0 +1,10 @@
import { IJsonSchema } from "../schema";
import { ParserError } from "./parser_error";
export interface IKeyErrors {
[key: string]: Error;
}
export declare class KeyError extends ParserError {
keys: string[];
errors: IKeyErrors;
constructor(schema: IJsonSchema, keys: string[], errors?: IKeyErrors);
}

View file

@ -0,0 +1,5 @@
import { IJsonSchema } from "../schema";
import { TransformError } from "./transform_error";
export declare class ParserError extends TransformError {
constructor(schema: IJsonSchema, message: string, innerError?: Error);
}

View file

@ -0,0 +1,5 @@
import { JsonError } from "./json_error";
export declare class SerializerError extends JsonError {
schemaName: string;
constructor(schemaName: string, message: string, innerError?: Error);
}

View file

@ -0,0 +1,6 @@
import { IJsonSchema } from "../schema";
import { JsonError } from "./json_error";
export declare class TransformError extends JsonError {
schema: IJsonSchema;
constructor(schema: IJsonSchema, message: string, innerError?: Error);
}

View file

@ -0,0 +1,3 @@
import { JsonError } from "./json_error";
export declare class ValidationError extends JsonError {
}

View file

@ -0,0 +1,5 @@
import { JsonPropTypes } from "./prop_types";
import { IJsonConvertible } from "./types";
export declare function checkType(value: any, type: JsonPropTypes): boolean;
export declare function throwIfTypeIsWrong(value: any, type: JsonPropTypes): void;
export declare function isConvertible(target: any): target is IJsonConvertible;

View file

@ -0,0 +1,6 @@
export * from "./serializer";
export * from "./parser";
export * from "./decorators";
export { JsonPropTypes } from "./prop_types";
export * from "./types";
export * from "./errors";

View file

@ -0,0 +1,26 @@
import { JsonTransform } from "./transform";
import { IEmptyConstructor } from "./types";
export interface IJsonParserOptions<T> {
targetSchema: IEmptyConstructor<T>;
schemaName?: string;
/**
* Enable strict checking of properties. Throw exception if incoming JSON has odd fields
*/
strictProperty?: boolean;
/**
* Checks all properties for object and throws KeyError with list of wrong keys
*/
strictAllKeys?: boolean;
}
export declare class JsonParser extends JsonTransform {
static parse<T>(data: string, options: IJsonParserOptions<T>): T;
static fromJSON<T>(target: any, options: IJsonParserOptions<T>): T;
/**
* Checks for odd properties in target object.
* @param target Target object
* @param namedSchema Named schema with a list of properties
* @param schema
* @throws Throws ParserError exception whenever target object has odd property
*/
private static checkStrictProperty;
}

View file

@ -0,0 +1,6 @@
export declare enum JsonPropTypes {
Any = 0,
Boolean = 1,
Number = 2,
String = 3
}

View file

@ -0,0 +1,35 @@
import { JsonPropTypes } from "./prop_types";
import { IEmptyConstructor, IJsonConverter, IValidation } from "./types";
export interface IValidationEvent {
propName: string;
value: any;
}
export interface IJsonSchemaItem {
type: JsonPropTypes | IEmptyConstructor<any>;
optional?: boolean;
defaultValue?: any;
converter?: IJsonConverter<any, any>;
repeated?: boolean;
name?: string;
validations: IValidation[];
}
export interface IJsonSchema {
target: IEmptyConstructor<any>;
names: {
[key: string]: {
[key: string]: IJsonSchemaItem;
};
};
}
export declare class JsonSchemaStorage {
protected items: Map<object, IJsonSchema>;
has(target: object): boolean;
get(target: object): IJsonSchema;
/**
* Creates new schema
* @param target Target object
*/
create(target: object): IJsonSchema;
set(target: object, schema: IJsonSchema): this;
protected findParentSchema(target: object): IJsonSchema | null;
}

View file

@ -0,0 +1,10 @@
import { JsonTransform } from "./transform";
import { IEmptyConstructor } from "./types";
export interface IJsonSerializerOptions {
targetSchema?: IEmptyConstructor<any>;
schemaName?: string;
}
export declare class JsonSerializer extends JsonTransform {
static serialize(obj: any, options?: IJsonSerializerOptions, replacer?: (key: string, value: any) => any, space?: string | number): string;
static toJSON(obj: any, options?: IJsonSerializerOptions): any;
}

View file

@ -0,0 +1,6 @@
import { JsonSchemaStorage } from "./schema";
/**
* Name of default schema
*/
export declare const DEFAULT_SCHEMA = "default";
export declare const schemaStorage: JsonSchemaStorage;

View file

@ -0,0 +1,9 @@
import { IJsonSchema, IJsonSchemaItem } from "./schema";
export interface IJsonNamedSchema {
[key: string]: IJsonSchemaItem;
}
export declare class JsonTransform {
protected static checkValues(data: any, schemaItem: IJsonSchemaItem): void;
protected static checkTypes(value: any, schemaItem: IJsonSchemaItem): void;
protected static getSchemaByName(schema: IJsonSchema, name?: string): IJsonNamedSchema;
}

View file

@ -0,0 +1,12 @@
export declare type IEmptyConstructor<T> = new () => T;
export interface IJsonConverter<T, S> {
fromJSON(value: S, target: any): T;
toJSON(value: T, target: any): S;
}
export interface IJsonConvertible<T = any> {
fromJSON(json: T): this;
toJSON(): T;
}
export interface IValidation {
validate(value: any): void;
}

View file

@ -0,0 +1,6 @@
import { IValidation } from "../types";
export declare class EnumerationValidation implements IValidation {
private enumeration;
constructor(enumeration: string[]);
validate(value: any): void;
}

View file

@ -0,0 +1,7 @@
import { IValidation } from "../types";
export declare class ExclusiveValidation implements IValidation {
private min;
private max;
constructor(min?: number, max?: number);
validate(value: any): void;
}

View file

@ -0,0 +1,7 @@
import { IValidation } from "../types";
export declare class InclusiveValidation implements IValidation {
private min;
private max;
constructor(min?: number, max?: number);
validate(value: any): void;
}

View file

@ -0,0 +1,5 @@
export * from "./pattern";
export * from "./inclusive";
export * from "./exclusive";
export * from "./length";
export * from "./enumeration";

View file

@ -0,0 +1,8 @@
import { IValidation } from "../types";
export declare class LengthValidation implements IValidation {
private length?;
private minLength?;
private maxLength?;
constructor(length?: number | undefined, minLength?: number | undefined, maxLength?: number | undefined);
validate(value: any): void;
}

View file

@ -0,0 +1,6 @@
import { IValidation } from "../types";
export declare class PatternValidation implements IValidation {
private pattern;
constructor(pattern: string | RegExp);
validate(value: any): void;
}

View file

@ -0,0 +1,95 @@
{
"name": "@peculiar/json-schema",
"version": "1.1.12",
"description": "This package uses ES2015 decorators to simplify JSON schema creation and use",
"main": "build/index.js",
"module": "build/index.es.js",
"types": "build/types/index.d.ts",
"scripts": {
"test": "mocha",
"prepare": "npm run build",
"lint": "tslint -p .",
"lint:fix": "tslint --fix -p .",
"build": "npm run build:module && npm run build:types",
"build:module": "rollup -c",
"build:types": "tsc -p tsconfig.types.json",
"clear": "rimraf build/*",
"rebuild": "npm run clear && npm run build",
"prepub": "npm run lint && npm run build",
"pub": "npm version patch && npm publish",
"postpub": "git push && git push --tags origin master",
"prepub:next": "npm run lint && npm run build",
"pub:next": "npm version prerelease --preid=next && npm publish --tag next",
"postpub:next": "git push",
"coverage": "nyc npm test",
"coveralls": "nyc report --reporter=text-lcov | coveralls"
},
"repository": {
"type": "git",
"url": "git+https://github.com/PeculiarVentures/json-schema.git"
},
"keywords": [
"json",
"stringify",
"serialize",
"parse",
"convert",
"decorator"
],
"author": "PeculiarVentures, Inc",
"contributors": [
{
"email": "rmh@unmitigatedrisk.com",
"name": "Ryan Hurst"
},
{
"email": "microshine@mail.ru",
"name": "Miroshin Stepan"
}
],
"license": "MIT",
"bugs": {
"url": "https://github.com/PeculiarVentures/json-schema/issues"
},
"homepage": "https://github.com/PeculiarVentures/json-schema#readme",
"engines": {
"node": ">=8.0.0"
},
"devDependencies": {
"@types/mocha": "^8.0.0",
"@types/node": "^12.12.51",
"mocha": "^8.0.1",
"rimraf": "^3.0.2",
"rollup": "^2.22.2",
"rollup-plugin-typescript2": "^0.27.1",
"ts-node": "^8.10.2",
"tslint": "^6.1.2",
"typescript": "^3.9.7"
},
"dependencies": {
"tslib": "^2.0.0"
},
"nyc": {
"extension": [
".ts",
".tsx"
],
"include": [
"src/**/*.ts"
],
"exclude": [
"**/*.d.ts"
],
"reporter": [
"text-summary",
"html"
]
},
"mocha": {
"require": "ts-node/register",
"extension": [
"ts"
],
"watch-files": "test/**/*.ts"
}
}

21
electron/node_modules/@peculiar/utils/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017-2026 Peculiar Ventures, LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

299
electron/node_modules/@peculiar/utils/README.md generated vendored Normal file
View file

@ -0,0 +1,299 @@
# @peculiar/utils
[![npm version](https://img.shields.io/npm/v/%40peculiar%2Futils.svg)](https://www.npmjs.com/package/@peculiar/utils)
[![Test](https://github.com/PeculiarVentures/pvtsutils/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/PeculiarVentures/pvtsutils/actions/workflows/test.yml)
[![Coverage Status](https://coveralls.io/repos/github/PeculiarVentures/pvtsutils/badge.svg?branch=master)](https://coveralls.io/github/PeculiarVentures/pvtsutils?branch=master)
[![License: MIT](https://img.shields.io/github/license/PeculiarVentures/pvtsutils.svg)](https://github.com/PeculiarVentures/pvtsutils/blob/master/LICENSE)
Modern byte, text, converter registry, and PEM utilities for TypeScript projects.
The package is designed around a modular v2 API:
- multi-entry exports for tree-shake-friendly imports;
- `encode` and `decode` terminology;
- an extensible runtime converter registry;
- generic PEM helpers without PKI-specific parsing;
- a legacy compatibility layer for historical `pvtsutils` consumers.
## Install
```bash
npm install @peculiar/utils
```
## Entry Points
```ts
import { bytes } from "@peculiar/utils";
import { hex, base64, base64url } from "@peculiar/utils/encoding";
import { pem } from "@peculiar/utils/pem";
import { convert, createConverterRegistry, defaultConverters } from "@peculiar/utils/converters";
import { Convert } from "@peculiar/utils/legacy";
```
## Bytes Helpers
`@peculiar/utils/bytes` stays focused on stateless byte sequence utilities. It does not include stateful readers, writers, ASN.1 parsing, PDF parsing, or other structured binary readers. For structured binary parsing, use a dedicated binary reader package.
```ts
import { bytes } from "@peculiar/utils";
const offset = bytes.indexOf(new Uint8Array([0x25, 0x25, 0x45, 0x4f, 0x46]), "%%EOF", {
encoding: "ascii",
});
const suffix = bytes.endsWith(new Uint8Array([0x25, 0x25, 0x45, 0x4f, 0x46]), "%%EOF", {
encoding: "ascii",
});
```
### Find `startxref` In A PDF Tail
```ts
import { lastIndexOf } from "@peculiar/utils/bytes";
const tailStart = Math.max(0, pdf.byteLength - 4096);
const offset = lastIndexOf(pdf, "startxref", {
encoding: "ascii",
start: pdf.byteLength,
end: tailStart,
});
if (offset === -1) {
throw new Error("PDF startxref marker not found");
}
```
### Find `startxref` Via `tail`
```ts
import { lastIndexOf, tail } from "@peculiar/utils/bytes";
const pdfTail = tail(pdf, 4096);
const localOffset = lastIndexOf(pdfTail, "startxref", {
encoding: "ascii",
});
const offset =
localOffset === -1
? -1
: pdf.byteLength - pdfTail.byteLength + localOffset;
```
### Check Prefixes And Suffixes
```ts
import { bytes } from "@peculiar/utils";
bytes.startsWith(data, "-----BEGIN", { encoding: "ascii" });
bytes.endsWith(data, "%%EOF", { encoding: "ascii" });
```
### Compare Byte Sequences
```ts
import { bytes } from "@peculiar/utils";
const result = bytes.compare(a, b);
if (result === 0) {
console.log("equal");
}
```
## Convert API
The default `convert` facade is a convenience singleton backed by the built-in registry.
```ts
import { convert } from "@peculiar/utils/converters";
const bytes = convert.decode("base64", "AQID");
const text = convert.encode("hex", bytes, { case: "upper" });
```
Deprecated `convert.to(...)` and `convert.from(...)` aliases are still available for temporary migration, but the primary v2 API is `encode` and `decode`.
## Transcode
Direct text-to-text transcoding goes through the registry without a manual intermediate step.
```ts
import { convert } from "@peculiar/utils/converters";
import { hex } from "@peculiar/utils/encoding";
const pemText = convert.transcode("AQID", {
from: "base64",
to: "pem",
toOptions: {
label: "CERTIFICATE",
},
});
const hexText = convert.transcode(pemText, {
from: "pem",
fromOptions: { label: "CERTIFICATE" },
to: "hex",
toOptions: hex.formats.colonUpper,
});
```
There is intentionally no chain API.
## Hex Formatting
The `hex` codec accepts common input styles and can format output explicitly.
```ts
import { hex } from "@peculiar/utils/encoding";
hex.decode("0102030405060708090a0b0c");
hex.decode("01020304 05060708 090a0b0c");
hex.decode("01:02:03:04:05:06:07:08:09:0A:0B:0C");
hex.decode("0x0102030405060708090a0b0c");
hex.encode(new Uint8Array([1, 2, 3, 4]), hex.formats.colonUpper);
hex.encode(new Uint8Array([1, 2, 3, 4]), {
prefix: "0x",
group: {
size: 2,
separator: " ",
},
});
```
Available presets:
- `hex.formats.compact`
- `hex.formats.upper`
- `hex.formats.colon`
- `hex.formats.colonUpper`
- `hex.formats.groupsOf4`
- `hex.formats.prefixed`
## Preserve Formatting
Use `parse` and `format` when you want to keep the original visual style of a hex string.
```ts
import { hex } from "@peculiar/utils/encoding";
const parsed = hex.parse("01:02:03:04:05:06");
parsed.bytes;
parsed.format;
parsed.normalized;
const updated = hex.format(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]), parsed.format);
```
The same capabilities are available through the registry facade:
```ts
import { convert } from "@peculiar/utils/converters";
const parsed = convert.parse("hex", "01:02:03:04");
const formatted = convert.format("hex", new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd]), parsed.format);
```
## PEM Helpers
PEM support stays generic. The package does not parse ASN.1, validate PKI semantics, or handle encrypted PEM containers.
```ts
import { pem } from "@peculiar/utils/pem";
const text = pem.encode("CERTIFICATE", new Uint8Array([1, 2, 3]));
const blocks = pem.decode(text);
const block = pem.find(text, "CERTIFICATE");
const matches = pem.findAll(text, "CERTIFICATE");
const bundle = pem.encodeMany([
{ label: "CERTIFICATE", data: new Uint8Array([1, 2, 3]) },
{ label: "PRIVATE KEY", data: new Uint8Array([4, 5, 6]) },
]);
```
## Safe Decode And Detection
```ts
import { convert } from "@peculiar/utils/converters";
const result = convert.tryDecode("hex", "01:02:03");
if (result.ok) {
console.log(result.bytes);
} else {
console.error(result.error);
}
const candidates = convert.detect("-----BEGIN DATA-----\nAQID\n-----END DATA-----\n", {
formats: ["pem", "base64", "hex"],
});
```
## Custom Registries
Applications can create isolated registries instead of mutating global state.
```ts
import { createConverterRegistry, defaultConverters } from "@peculiar/utils/converters";
const registry = createConverterRegistry(defaultConverters);
registry.register({
name: "base58btc",
aliases: ["b58"],
encode(data) {
return base58btcEncode(data);
},
decode(text) {
return base58btcDecode(text);
},
});
```
Name and alias conflicts throw by default. Use `{ override: true }` only when replacement is intentional.
## Typed Converter Options
Built-in converters expose typed options through the registry facade.
```ts
import { convert } from "@peculiar/utils/converters";
convert.encode("hex", new Uint8Array([1, 2, 3]), {
case: "upper",
});
```
Wrong options are rejected by TypeScript:
```ts
convert.encode("hex", new Uint8Array([1, 2, 3]), {
label: "CERTIFICATE",
});
```
Custom converters can extend the options map via module augmentation:
```ts
declare module "@peculiar/utils/converters" {
interface ConverterOptionsMap {
base58btc: {
encode: Base58EncodeOptions;
decode: Base58DecodeOptions;
};
}
}
```
## Legacy Compatibility
The old `pvtsutils`-style surface is preserved under the legacy entry point.
```ts
import { BufferSourceConverter, Convert, assign, combine, isEqual } from "@peculiar/utils/legacy";
```

View file

@ -0,0 +1,115 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isArrayBuffer = isArrayBuffer;
exports.isSharedArrayBuffer = isSharedArrayBuffer;
exports.isArrayBufferLike = isArrayBufferLike;
exports.isArrayBufferView = isArrayBufferView;
exports.isBufferSource = isBufferSource;
exports.assertBufferSource = assertBufferSource;
exports.toUint8Array = toUint8Array;
exports.toUint8ArrayCopy = toUint8ArrayCopy;
exports.toArrayBuffer = toArrayBuffer;
exports.toArrayBufferLike = toArrayBufferLike;
exports.toView = toView;
exports.toViewCopy = toViewCopy;
const ARRAY_BUFFER_TAG = "[object ArrayBuffer]";
const SHARED_ARRAY_BUFFER_TAG = "[object SharedArrayBuffer]";
function tagOf(value) {
return Object.prototype.toString.call(value);
}
function isDataViewConstructor(type) {
return type === DataView || type.prototype instanceof DataView;
}
function bytesPerElement(type) {
if (isDataViewConstructor(type)) {
return 1;
}
const value = type.BYTES_PER_ELEMENT;
return value ?? 1;
}
function isArrayBufferViewLike(value) {
if (ArrayBuffer.isView(value)) {
return true;
}
if (!value || typeof value !== "object") {
return false;
}
const view = value;
return typeof view.byteOffset === "number"
&& typeof view.byteLength === "number"
&& isArrayBufferLike(view.buffer);
}
function copyBytes(data) {
const view = toUint8Array(data);
const copy = new Uint8Array(view.byteLength);
copy.set(view);
return copy;
}
function isArrayBuffer(value) {
return tagOf(value) === ARRAY_BUFFER_TAG;
}
function isSharedArrayBuffer(value) {
return typeof SharedArrayBuffer !== "undefined" && tagOf(value) === SHARED_ARRAY_BUFFER_TAG;
}
function isArrayBufferLike(value) {
return isArrayBuffer(value) || isSharedArrayBuffer(value);
}
function isArrayBufferView(value) {
return isArrayBufferViewLike(value);
}
function isBufferSource(value) {
return isArrayBufferLike(value) || isArrayBufferView(value);
}
function assertBufferSource(value) {
if (!isBufferSource(value)) {
throw new TypeError("Expected ArrayBuffer, SharedArrayBuffer, or ArrayBufferView");
}
}
function toUint8Array(data) {
assertBufferSource(data);
if (isArrayBufferLike(data)) {
return new Uint8Array(data);
}
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
}
function toUint8ArrayCopy(data) {
return copyBytes(data);
}
function toArrayBuffer(data) {
assertBufferSource(data);
if (isArrayBuffer(data)) {
return data;
}
const buffer = new ArrayBuffer(data.byteLength);
new Uint8Array(buffer).set(toUint8Array(data));
return buffer;
}
function toArrayBufferLike(data) {
assertBufferSource(data);
if (isArrayBufferLike(data)) {
return data;
}
if (data.byteOffset === 0 && data.byteLength === data.buffer.byteLength) {
return data.buffer;
}
return copyBytes(data).buffer;
}
function toView(data, type) {
assertBufferSource(data);
if (ArrayBuffer.isView(data) && data.constructor === type) {
return data;
}
const view = toUint8Array(data);
const elementSize = bytesPerElement(type);
if (view.byteOffset % elementSize !== 0 || view.byteLength % elementSize !== 0) {
throw new RangeError(`Cannot create ${type.name} over unaligned byte range`);
}
if (isDataViewConstructor(type)) {
return new type(view.buffer, view.byteOffset, view.byteLength);
}
return new type(view.buffer, view.byteOffset, view.byteLength / elementSize);
}
function toViewCopy(data, type) {
const copy = toUint8ArrayCopy(data);
return toView(copy, type);
}

View file

@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.concatToUint8Array = concatToUint8Array;
exports.concat = concat;
const buffer_source_js_1 = require("./buffer-source.js");
function concatToUint8Array(buffers) {
const views = [];
let length = 0;
for (const buffer of buffers) {
const view = (0, buffer_source_js_1.toUint8Array)(buffer);
views.push(view);
length += view.byteLength;
}
const result = new Uint8Array(length);
let offset = 0;
for (const view of views) {
result.set(view, offset);
offset += view.byteLength;
}
return result;
}
function concat(first, second, ...rest) {
let buffers;
let type;
if (typeof second === "function") {
buffers = Array.from(first);
type = second;
}
else if ((0, buffer_source_js_1.isBufferSource)(first)) {
buffers = [first, second, ...rest].filter(buffer_source_js_1.isBufferSource);
}
else {
buffers = Array.from(first);
if (second) {
buffers.push(second);
}
buffers.push(...rest);
}
const bytes = concatToUint8Array(buffers);
return type ? (0, buffer_source_js_1.toView)(bytes, type) : bytes.buffer;
}

View file

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.equal = equal;
const buffer_source_js_1 = require("./buffer-source.js");
function equal(a, b, options = {}) {
const left = (0, buffer_source_js_1.toUint8Array)(a);
const right = (0, buffer_source_js_1.toUint8Array)(b);
if (!options.constantTime && left.byteLength !== right.byteLength) {
return false;
}
const length = Math.max(left.byteLength, right.byteLength);
let diff = left.byteLength ^ right.byteLength;
for (let i = 0; i < length; i++) {
diff |= (left[i] ?? 0) ^ (right[i] ?? 0);
}
return diff === 0;
}

View file

@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.tail = exports.startsWith = exports.slice = exports.lastIndexOf = exports.indexOf = exports.includes = exports.endsWith = exports.copy = exports.compare = exports.equal = exports.concatToUint8Array = exports.concat = exports.toViewCopy = exports.toView = exports.toUint8ArrayCopy = exports.toUint8Array = exports.toArrayBufferLike = exports.toArrayBuffer = exports.isSharedArrayBuffer = exports.isBufferSource = exports.isArrayBufferView = exports.isArrayBufferLike = exports.isArrayBuffer = exports.assertBufferSource = void 0;
var buffer_source_js_1 = require("./buffer-source.js");
Object.defineProperty(exports, "assertBufferSource", { enumerable: true, get: function () { return buffer_source_js_1.assertBufferSource; } });
Object.defineProperty(exports, "isArrayBuffer", { enumerable: true, get: function () { return buffer_source_js_1.isArrayBuffer; } });
Object.defineProperty(exports, "isArrayBufferLike", { enumerable: true, get: function () { return buffer_source_js_1.isArrayBufferLike; } });
Object.defineProperty(exports, "isArrayBufferView", { enumerable: true, get: function () { return buffer_source_js_1.isArrayBufferView; } });
Object.defineProperty(exports, "isBufferSource", { enumerable: true, get: function () { return buffer_source_js_1.isBufferSource; } });
Object.defineProperty(exports, "isSharedArrayBuffer", { enumerable: true, get: function () { return buffer_source_js_1.isSharedArrayBuffer; } });
Object.defineProperty(exports, "toArrayBuffer", { enumerable: true, get: function () { return buffer_source_js_1.toArrayBuffer; } });
Object.defineProperty(exports, "toArrayBufferLike", { enumerable: true, get: function () { return buffer_source_js_1.toArrayBufferLike; } });
Object.defineProperty(exports, "toUint8Array", { enumerable: true, get: function () { return buffer_source_js_1.toUint8Array; } });
Object.defineProperty(exports, "toUint8ArrayCopy", { enumerable: true, get: function () { return buffer_source_js_1.toUint8ArrayCopy; } });
Object.defineProperty(exports, "toView", { enumerable: true, get: function () { return buffer_source_js_1.toView; } });
Object.defineProperty(exports, "toViewCopy", { enumerable: true, get: function () { return buffer_source_js_1.toViewCopy; } });
var concat_js_1 = require("./concat.js");
Object.defineProperty(exports, "concat", { enumerable: true, get: function () { return concat_js_1.concat; } });
Object.defineProperty(exports, "concatToUint8Array", { enumerable: true, get: function () { return concat_js_1.concatToUint8Array; } });
var equal_js_1 = require("./equal.js");
Object.defineProperty(exports, "equal", { enumerable: true, get: function () { return equal_js_1.equal; } });
var sequence_js_1 = require("./sequence.js");
Object.defineProperty(exports, "compare", { enumerable: true, get: function () { return sequence_js_1.compare; } });
Object.defineProperty(exports, "copy", { enumerable: true, get: function () { return sequence_js_1.copy; } });
Object.defineProperty(exports, "endsWith", { enumerable: true, get: function () { return sequence_js_1.endsWith; } });
Object.defineProperty(exports, "includes", { enumerable: true, get: function () { return sequence_js_1.includes; } });
Object.defineProperty(exports, "indexOf", { enumerable: true, get: function () { return sequence_js_1.indexOf; } });
Object.defineProperty(exports, "lastIndexOf", { enumerable: true, get: function () { return sequence_js_1.lastIndexOf; } });
Object.defineProperty(exports, "slice", { enumerable: true, get: function () { return sequence_js_1.slice; } });
Object.defineProperty(exports, "startsWith", { enumerable: true, get: function () { return sequence_js_1.startsWith; } });
Object.defineProperty(exports, "tail", { enumerable: true, get: function () { return sequence_js_1.tail; } });

View file

@ -0,0 +1,161 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.indexOf = indexOf;
exports.lastIndexOf = lastIndexOf;
exports.includes = includes;
exports.startsWith = startsWith;
exports.endsWith = endsWith;
exports.slice = slice;
exports.tail = tail;
exports.copy = copy;
exports.compare = compare;
const buffer_source_js_1 = require("./buffer-source.js");
function clampIndex(value, fallback, length) {
const normalized = Number.isFinite(value) ? Math.trunc(value) : fallback;
if (normalized <= 0) {
return 0;
}
if (normalized >= length) {
return length;
}
return normalized;
}
function normalizeForwardRange(length, options) {
const start = clampIndex(options?.start, 0, length);
const end = clampIndex(options?.end, length, length);
return end >= start ? [start, end] : [start, start];
}
function normalizeReverseRange(length, options) {
const start = clampIndex(options?.start, length, length);
const end = clampIndex(options?.end, 0, length);
return start >= end ? [end, start] : [start, start];
}
function normalizeSliceIndex(value, fallback, length) {
const normalized = Number.isFinite(value) ? Math.trunc(value) : fallback;
if (normalized < 0) {
return Math.max(length + normalized, 0);
}
if (normalized > length) {
return length;
}
return normalized;
}
function encodeAscii(text) {
const bytes = new Uint8Array(text.length);
for (let i = 0; i < text.length; i++) {
bytes[i] = text.charCodeAt(i) & 0xff;
}
return bytes;
}
function encodeUtf8(text) {
return new TextEncoder().encode(text);
}
function toPatternBytes(pattern, options) {
if (typeof pattern === "string") {
return options?.encoding === "utf8" ? encodeUtf8(pattern) : encodeAscii(pattern);
}
return (0, buffer_source_js_1.toUint8Array)(pattern);
}
function bytesEqualAt(data, pattern, offset) {
for (let index = 0; index < pattern.byteLength; index++) {
if (data[offset + index] !== pattern[index]) {
return false;
}
}
return true;
}
function indexOf(data, pattern, options) {
const bytes = (0, buffer_source_js_1.toUint8Array)(data);
const needle = toPatternBytes(pattern, options);
const [start, end] = normalizeForwardRange(bytes.byteLength, options);
if (needle.byteLength === 0) {
return start;
}
const lastOffset = end - needle.byteLength;
if (lastOffset < start) {
return -1;
}
for (let offset = start; offset <= lastOffset; offset++) {
if (bytesEqualAt(bytes, needle, offset)) {
return offset;
}
}
return -1;
}
function lastIndexOf(data, pattern, options) {
const bytes = (0, buffer_source_js_1.toUint8Array)(data);
const needle = toPatternBytes(pattern, options);
const [end, start] = normalizeReverseRange(bytes.byteLength, options);
if (needle.byteLength === 0) {
return start;
}
const firstOffset = start - needle.byteLength;
if (firstOffset < end) {
return -1;
}
for (let offset = firstOffset; offset >= end; offset--) {
if (bytesEqualAt(bytes, needle, offset)) {
return offset;
}
}
return -1;
}
function includes(data, pattern, options) {
return indexOf(data, pattern, options) !== -1;
}
function startsWith(data, pattern, options) {
const bytes = (0, buffer_source_js_1.toUint8Array)(data);
const needle = toPatternBytes(pattern, options);
if (needle.byteLength > bytes.byteLength) {
return false;
}
return bytesEqualAt(bytes, needle, 0);
}
function endsWith(data, pattern, options) {
const bytes = (0, buffer_source_js_1.toUint8Array)(data);
const needle = toPatternBytes(pattern, options);
if (needle.byteLength > bytes.byteLength) {
return false;
}
return bytesEqualAt(bytes, needle, bytes.byteLength - needle.byteLength);
}
function slice(data, start, end) {
const bytes = (0, buffer_source_js_1.toUint8Array)(data);
const normalizedStart = normalizeSliceIndex(start, 0, bytes.byteLength);
const normalizedEnd = normalizeSliceIndex(end, bytes.byteLength, bytes.byteLength);
if (normalizedEnd <= normalizedStart) {
return bytes.subarray(normalizedStart, normalizedStart);
}
return bytes.subarray(normalizedStart, normalizedEnd);
}
function tail(data, length) {
const bytes = (0, buffer_source_js_1.toUint8Array)(data);
const normalizedLength = Number.isFinite(length) ? Math.max(0, Math.trunc(length)) : 0;
if (normalizedLength >= bytes.byteLength) {
return bytes;
}
return bytes.subarray(bytes.byteLength - normalizedLength);
}
function copy(data) {
return (0, buffer_source_js_1.toUint8ArrayCopy)(data);
}
function compare(a, b) {
const left = (0, buffer_source_js_1.toUint8Array)(a);
const right = (0, buffer_source_js_1.toUint8Array)(b);
const limit = Math.min(left.byteLength, right.byteLength);
for (let index = 0; index < limit; index++) {
if (left[index] < right[index]) {
return -1;
}
if (left[index] > right[index]) {
return 1;
}
}
if (left.byteLength < right.byteLength) {
return -1;
}
if (left.byteLength > right.byteLength) {
return 1;
}
return 0;
}

View file

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

View file

@ -0,0 +1,74 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.convert = void 0;
const index_js_1 = require("../bytes/index.js");
const index_js_2 = require("../encoding/index.js");
const defaults_js_1 = require("./defaults.js");
function encode(name, data, ...args) {
return defaults_js_1.defaultConverterRegistry.encode(name, data, ...args);
}
function decode(name, text, ...args) {
return defaults_js_1.defaultConverterRegistry.decode(name, text, ...args);
}
function tryDecode(name, text, ...args) {
return defaults_js_1.defaultConverterRegistry.tryDecode(name, text, ...args);
}
function normalize(name, text, ...args) {
return defaults_js_1.defaultConverterRegistry.normalize(name, text, ...args);
}
function parse(name, text, ...args) {
return defaults_js_1.defaultConverterRegistry.parse(name, text, ...args);
}
function format(name, data, value) {
return defaults_js_1.defaultConverterRegistry.format(name, data, value);
}
function transcode(text, options) {
return defaults_js_1.defaultConverterRegistry.transcode(text, options);
}
function detect(text, options) {
return defaults_js_1.defaultConverterRegistry.detect(text, options);
}
function normalizeEncodingName(encoding) {
return encoding.toLowerCase();
}
exports.convert = {
encode,
decode,
tryDecode,
normalize,
parse,
format,
transcode,
detect,
to(format, data, ...args) {
return encode(format, data, ...args);
},
from(format, text, ...args) {
return decode(format, text, ...args);
},
toString(data, encoding = "utf8") {
return encode(encoding, data);
},
fromString(text, encoding = "utf8") {
if (normalizeEncodingName(encoding) === "hex") {
return (0, index_js_1.toArrayBuffer)(index_js_2.hex.decode(text, { allowOddLength: true }));
}
return (0, index_js_1.toArrayBuffer)(decode(encoding, text));
},
toBase64: index_js_2.base64.encode,
fromBase64: (text) => (0, index_js_1.toArrayBuffer)(index_js_2.base64.decode(text)),
toBase64Url: index_js_2.base64url.encode,
fromBase64Url: (text) => (0, index_js_1.toArrayBuffer)(index_js_2.base64url.decode(text)),
toHex: index_js_2.hex.encode,
fromHex: (text) => (0, index_js_1.toArrayBuffer)(index_js_2.hex.decode(text, { allowOddLength: true })),
toBinary: index_js_2.binary.encode,
fromBinary: (text) => (0, index_js_1.toArrayBuffer)(index_js_2.binary.decode(text)),
toUtf8String: index_js_2.utf8.decode,
fromUtf8String: (text) => (0, index_js_1.toArrayBuffer)(index_js_2.utf8.encode(text)),
toUtf16String: (data, littleEndian = false) => index_js_2.utf16.decode(data, { littleEndian }),
fromUtf16String: (text, littleEndian = false) => (0, index_js_1.toArrayBuffer)(index_js_2.utf16.encode(text, { littleEndian })),
isHex: index_js_2.hex.is,
isBase64: index_js_2.base64.is,
isBase64Url: index_js_2.base64url.is,
formatString: index_js_2.base64.normalize,
};

View file

@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultConverterRegistry = exports.defaultConverters = exports.utf16leConverter = exports.utf16beConverter = exports.utf8Converter = exports.base64urlConverter = exports.base64Converter = exports.hexConverter = exports.binaryConverter = exports.pemConverter = void 0;
const index_js_1 = require("../encoding/index.js");
const index_js_2 = require("../pem/index.js");
var index_js_3 = require("../pem/index.js");
Object.defineProperty(exports, "pemConverter", { enumerable: true, get: function () { return index_js_3.pemConverter; } });
const registry_js_1 = require("./registry.js");
exports.binaryConverter = {
name: "binary",
aliases: ["latin1"],
encode: index_js_1.binary.encode,
decode: index_js_1.binary.decode,
is: index_js_1.binary.is,
};
exports.hexConverter = {
name: "hex",
encode: index_js_1.hex.encode,
decode: index_js_1.hex.decode,
format: index_js_1.hex.format,
is: index_js_1.hex.is,
normalize: index_js_1.hex.normalize,
parse: index_js_1.hex.parse,
};
exports.base64Converter = {
name: "base64",
aliases: ["b64"],
encode: index_js_1.base64.encode,
decode: index_js_1.base64.decode,
is: index_js_1.base64.is,
normalize: index_js_1.base64.normalize,
};
exports.base64urlConverter = {
name: "base64url",
aliases: ["base64-url", "b64url"],
encode: index_js_1.base64url.encode,
decode: index_js_1.base64url.decode,
is: index_js_1.base64url.is,
normalize: index_js_1.base64url.normalize,
};
exports.utf8Converter = {
name: "utf8",
aliases: ["utf-8"],
encode: (data) => index_js_1.utf8.decode(data),
decode: (text) => index_js_1.utf8.encode(text),
is: (text) => typeof text === "string",
};
exports.utf16beConverter = {
name: "utf16be",
aliases: ["utf16", "utf-16", "utf-16be"],
encode: (data) => index_js_1.utf16.decode(data),
decode: (text) => index_js_1.utf16.encode(text),
is: (text) => typeof text === "string",
};
exports.utf16leConverter = {
name: "utf16le",
aliases: ["utf-16le", "ucs2", "usc2"],
encode: (data) => index_js_1.utf16.decode(data, { littleEndian: true }),
decode: (text) => index_js_1.utf16.encode(text, { littleEndian: true }),
is: (text) => typeof text === "string",
};
exports.defaultConverters = [
exports.binaryConverter,
exports.hexConverter,
exports.base64Converter,
exports.base64urlConverter,
exports.utf8Converter,
exports.utf16beConverter,
exports.utf16leConverter,
index_js_2.pemConverter,
];
exports.defaultConverterRegistry = (0, registry_js_1.createConverterRegistry)(exports.defaultConverters);

View file

@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.convert = exports.utf8Converter = exports.utf16leConverter = exports.utf16beConverter = exports.pemConverter = exports.hexConverter = exports.defaultConverters = exports.defaultConverterRegistry = exports.binaryConverter = exports.base64urlConverter = exports.base64Converter = exports.createConverterRegistry = void 0;
var registry_js_1 = require("./registry.js");
Object.defineProperty(exports, "createConverterRegistry", { enumerable: true, get: function () { return registry_js_1.createConverterRegistry; } });
var defaults_js_1 = require("./defaults.js");
Object.defineProperty(exports, "base64Converter", { enumerable: true, get: function () { return defaults_js_1.base64Converter; } });
Object.defineProperty(exports, "base64urlConverter", { enumerable: true, get: function () { return defaults_js_1.base64urlConverter; } });
Object.defineProperty(exports, "binaryConverter", { enumerable: true, get: function () { return defaults_js_1.binaryConverter; } });
Object.defineProperty(exports, "defaultConverterRegistry", { enumerable: true, get: function () { return defaults_js_1.defaultConverterRegistry; } });
Object.defineProperty(exports, "defaultConverters", { enumerable: true, get: function () { return defaults_js_1.defaultConverters; } });
Object.defineProperty(exports, "hexConverter", { enumerable: true, get: function () { return defaults_js_1.hexConverter; } });
Object.defineProperty(exports, "pemConverter", { enumerable: true, get: function () { return defaults_js_1.pemConverter; } });
Object.defineProperty(exports, "utf16beConverter", { enumerable: true, get: function () { return defaults_js_1.utf16beConverter; } });
Object.defineProperty(exports, "utf16leConverter", { enumerable: true, get: function () { return defaults_js_1.utf16leConverter; } });
Object.defineProperty(exports, "utf8Converter", { enumerable: true, get: function () { return defaults_js_1.utf8Converter; } });
var convert_js_1 = require("./convert.js");
Object.defineProperty(exports, "convert", { enumerable: true, get: function () { return convert_js_1.convert; } });

View file

@ -0,0 +1,188 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createConverterRegistry = createConverterRegistry;
function keyOf(name) {
return name.trim().toLowerCase();
}
function toError(error) {
return error instanceof Error ? error : new Error(String(error));
}
function removeConverter(converters, primaryNames, converter) {
for (const alias of [converter.name, ...(converter.aliases ?? [])]) {
converters.delete(keyOf(alias));
}
primaryNames.delete(keyOf(converter.name));
}
function requireCapability(converter, name, capability) {
const method = converter[capability];
if (typeof method !== "function") {
throw new Error(`Converter '${name}' does not support ${capability}()`);
}
return method;
}
function detectConfidence(name, text, converter) {
const normalizedName = keyOf(converter.name || name);
const trimmed = text.trim();
if (!trimmed) {
return 0;
}
let accepted = false;
if (converter.is) {
accepted = converter.is(text);
}
let decodable = false;
try {
converter.decode(text);
decodable = true;
}
catch {
decodable = false;
}
if (!accepted && !decodable) {
return 0;
}
switch (normalizedName) {
case "pem":
return /-----BEGIN [^-]+-----/.test(text) ? 1 : 0;
case "hex": {
const compact = trimmed.replace(/^0x/i, "").replace(/[\s:.-]/g, "");
if (!compact || /[^0-9a-f]/i.test(compact) || compact.length % 2 !== 0) {
return 0;
}
if (/^0x/i.test(trimmed) || /[:\s.-]/.test(trimmed)) {
return 0.95;
}
if (/[a-f]/.test(trimmed) || /[A-F]/.test(trimmed)) {
return 0.8;
}
return 0.45;
}
case "base64url":
if (/[-_]/.test(trimmed)) {
return 0.95;
}
if (/=/.test(trimmed)) {
return 0.1;
}
return 0.6;
case "base64":
if (/[+/=]/.test(trimmed)) {
return 0.9;
}
return 0.55;
case "binary":
case "utf8":
case "utf16be":
case "utf16le":
return 0;
default:
return accepted && decodable ? 0.75 : 0.5;
}
}
function createConverterRegistry(initialConverters = []) {
const converters = new Map();
const primaryNames = new Set();
const api = {
register(converter, options = {}) {
if (!converter.name || !keyOf(converter.name)) {
throw new TypeError("Converter name is required");
}
const names = [...new Set([converter.name, ...(converter.aliases ?? [])].map(keyOf))];
const conflicts = new Set();
for (const name of names) {
const existing = converters.get(name);
if (!existing) {
continue;
}
if (!options.override) {
throw new Error(`Converter '${name}' is already registered`);
}
conflicts.add(existing);
}
for (const conflicting of conflicts) {
removeConverter(converters, primaryNames, conflicting);
}
for (const name of names) {
converters.set(name, converter);
}
primaryNames.add(keyOf(converter.name));
return this;
},
unregister(name) {
const converter = converters.get(keyOf(name));
if (!converter) {
return false;
}
removeConverter(converters, primaryNames, converter);
return true;
},
has(name) {
return converters.has(keyOf(name));
},
get(name) {
const converter = converters.get(keyOf(name));
if (!converter) {
throw new Error(`Converter '${name}' is not registered`);
}
return converter;
},
list() {
return [...primaryNames].map((name) => this.get(name));
},
encode(name, data, options) {
return this.get(name).encode(data, options);
},
decode(name, text, options) {
return this.get(name).decode(text, options);
},
tryDecode(name, text, options) {
try {
return { ok: true, bytes: this.decode(name, text, options) };
}
catch (error) {
return { ok: false, error: toError(error) };
}
},
normalize(name, text, options) {
const converter = this.get(name);
return requireCapability(converter, name, "normalize").call(converter, text, options);
},
parse(name, text, options) {
const converter = this.get(name);
return requireCapability(converter, name, "parse").call(converter, text, options);
},
format(name, data, format) {
const converter = this.get(name);
return requireCapability(converter, name, "format").call(converter, data, format);
},
transcode(text, options) {
const bytes = this.decode(options.from, text, options.fromOptions);
return this.encode(options.to, bytes, options.toOptions);
},
detect(text, options = {}) {
const formatNames = options.formats?.length
? options.formats.map((name) => String(name))
: this.list()
.map((converter) => converter.name)
.filter((name) => !["binary", "utf8", "utf16be", "utf16le"].includes(keyOf(name)));
const detections = new Map();
for (const requestedName of formatNames) {
const converter = this.get(requestedName);
const confidence = detectConfidence(requestedName, text, converter);
if (confidence <= 0) {
continue;
}
const format = converter.name;
const current = detections.get(format);
if (!current || confidence > current.confidence) {
detections.set(format, { format, confidence });
}
}
return [...detections.values()].sort((left, right) => right.confidence - left.confidence);
},
};
for (const converter of initialConverters) {
api.register(converter);
}
return api;
}

View file

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

View file

@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.base64 = void 0;
exports.normalize = normalize;
exports.pad = pad;
exports.is = is;
exports.encode = encode;
exports.decode = decode;
const index_js_1 = require("../bytes/index.js");
const binary_js_1 = require("./binary.js");
const BASE64_REGEX = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
function nodeBuffer() {
return globalThis.Buffer;
}
function normalize(text) {
return text.replace(/[\n\r\t ]/g, "");
}
function pad(text) {
const remainder = text.length % 4;
return remainder ? text + "=".repeat(4 - remainder) : text;
}
function is(text) {
if (typeof text !== "string") {
return false;
}
const normalized = normalize(text);
return normalized === "" || BASE64_REGEX.test(normalized);
}
function encode(data, _options) {
const bytes = (0, index_js_1.toUint8Array)(data);
const buffer = nodeBuffer();
if (buffer) {
return buffer.from(bytes).toString("base64");
}
return btoa((0, binary_js_1.encode)(bytes));
}
function decode(text, _options) {
const normalized = normalize(text);
if (!is(normalized)) {
throw new TypeError("Input is not valid Base64 text");
}
const buffer = nodeBuffer();
if (buffer) {
return new Uint8Array(buffer.from(normalized, "base64"));
}
return (0, binary_js_1.decode)(atob(normalized));
}
exports.base64 = { encode, decode, is, normalize, pad };

View file

@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.base64url = void 0;
exports.normalize = normalize;
exports.is = is;
exports.encode = encode;
exports.decode = decode;
const base64_js_1 = require("./base64.js");
const BASE64URL_REGEX = /^[A-Za-z0-9_-]*$/;
function normalize(text) {
return text.replace(/[\n\r\t ]/g, "");
}
function is(text) {
return typeof text === "string" && BASE64URL_REGEX.test(normalize(text));
}
function encode(data, _options) {
return base64_js_1.base64.encode(data).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
}
function decode(text, _options) {
const normalized = normalize(text);
if (!is(normalized)) {
throw new TypeError("Input is not valid Base64Url text");
}
return base64_js_1.base64.decode(base64_js_1.base64.pad(normalized.replace(/-/g, "+").replace(/_/g, "/")));
}
exports.base64url = { encode, decode, is, normalize };

View file

@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.binary = void 0;
exports.encode = encode;
exports.decode = decode;
exports.is = is;
const index_js_1 = require("../bytes/index.js");
function encode(data) {
const bytes = (0, index_js_1.toUint8Array)(data);
let result = "";
for (const byte of bytes) {
result += String.fromCharCode(byte);
}
return result;
}
function decode(text) {
const result = new Uint8Array(text.length);
for (let i = 0; i < text.length; i++) {
result[i] = text.charCodeAt(i) & 0xff;
}
return result;
}
function is(text) {
return typeof text === "string";
}
exports.binary = { encode, decode, is };

View file

@ -0,0 +1,229 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hex = exports.formats = void 0;
exports.normalize = normalize;
exports.is = is;
exports.encode = encode;
exports.decode = decode;
exports.parse = parse;
exports.format = format;
const index_js_1 = require("../bytes/index.js");
const HEX_CHARACTER_REGEX = /^[0-9a-f]$/i;
const COMMON_SEPARATORS = [" ", "\t", "\n", "\r", ":", "-", "."];
function resolveSeparators(options) {
if (options.separators === "none") {
return [];
}
if (!options.separators || options.separators === "common") {
return COMMON_SEPARATORS;
}
return options.separators;
}
function validateSeparator(separator) {
if (!separator) {
throw new TypeError("Hex separators must be non-empty strings");
}
}
function matchSeparator(text, index, separators) {
for (const separator of separators) {
if (text.startsWith(separator, index)) {
return separator;
}
}
return undefined;
}
function detectCase(text) {
const hasUpper = /[A-F]/.test(text);
const hasLower = /[a-f]/.test(text);
return hasUpper && !hasLower ? "upper" : "lower";
}
function detectLineSeparator(text) {
const match = /\r\n|\n/.exec(text);
if (!match) {
return undefined;
}
return match[0] === "\r\n" ? "\r\n" : "\n";
}
function compactForDetection(text) {
return text.replace(/[^0-9a-f]/gi, "");
}
function detectGroup(text) {
const segments = text.match(/[0-9A-Fa-f]+|[^0-9A-Fa-f]+/g) ?? [];
if (segments.length < 3) {
return undefined;
}
const hexSegments = segments.filter((_, index) => index % 2 === 0);
const separators = segments.filter((_, index) => index % 2 === 1);
const separator = separators[0];
if (!separator || separators.some((item) => item !== separator)) {
return undefined;
}
if (hexSegments.some((segment) => segment.length === 0 || segment.length % 2 !== 0)) {
return undefined;
}
const firstLength = hexSegments[0]?.length ?? 0;
if (!firstLength) {
return undefined;
}
if (hexSegments.slice(0, -1).some((segment) => segment.length !== firstLength)) {
return undefined;
}
if ((hexSegments[hexSegments.length - 1]?.length ?? 0) > firstLength) {
return undefined;
}
return {
size: firstLength / 2,
separator,
};
}
function detectFormat(text) {
const trimmed = text.trim();
const prefix = /^0x/i.test(trimmed) ? "0x" : "";
const body = prefix ? trimmed.slice(2) : trimmed;
const lineSeparator = detectLineSeparator(body);
const lines = body.split(/\r\n|\n/).filter((line) => line.length > 0);
const sampleLine = lines[0]?.trim() ?? "";
const group = detectGroup(sampleLine);
const format = {
case: detectCase(trimmed),
prefix,
};
if (group) {
format.group = group;
}
if (lineSeparator && lines.length > 1) {
const firstLineBytes = compactForDetection(lines[0] ?? "").length / 2;
if (firstLineBytes > 0 && lines.slice(0, -1).every((line) => compactForDetection(line).length / 2 === firstLineBytes)) {
format.line = {
bytesPerLine: firstLineBytes,
separator: lineSeparator,
};
}
}
return format;
}
function normalizeText(text, options) {
const allowPrefix = options.allowPrefix ?? true;
const separators = [...resolveSeparators(options)].sort((left, right) => right.length - left.length);
for (const separator of separators) {
validateSeparator(separator);
}
let working = text.trim();
if (/^0x/i.test(working)) {
if (!allowPrefix) {
throw new TypeError("Hexadecimal text must not include a 0x prefix");
}
working = working.slice(2);
}
let normalized = "";
let lastTokenWasSeparator = false;
for (let index = 0; index < working.length;) {
const character = working[index] ?? "";
if (HEX_CHARACTER_REGEX.test(character)) {
normalized += character;
lastTokenWasSeparator = false;
index += 1;
continue;
}
const separator = matchSeparator(working, index, separators);
if (!separator) {
throw new TypeError("Input is not valid hexadecimal text");
}
if (options.strict && (lastTokenWasSeparator || normalized.length === 0)) {
throw new TypeError("Hexadecimal text contains misplaced separators");
}
lastTokenWasSeparator = true;
index += separator.length;
}
if (options.strict && lastTokenWasSeparator && normalized.length > 0) {
throw new TypeError("Hexadecimal text must not end with a separator");
}
if (normalized.length % 2 !== 0) {
if (!options.allowOddLength) {
throw new TypeError("Hexadecimal text must contain an even number of characters");
}
normalized = `0${normalized}`;
}
return normalized.toLowerCase();
}
function groupPairs(pairs, group) {
if (!group) {
return pairs.join("");
}
if (!Number.isInteger(group.size) || group.size < 1) {
throw new RangeError("Hex group size must be a positive integer");
}
const chunks = [];
for (let index = 0; index < pairs.length; index += group.size) {
chunks.push(pairs.slice(index, index + group.size).join(""));
}
return chunks.join(group.separator);
}
function normalize(text, options = {}) {
return normalizeText(text, options);
}
function is(text, options = {}) {
if (typeof text !== "string") {
return false;
}
try {
normalize(text, options);
return true;
}
catch {
return false;
}
}
function encode(data, options = {}) {
const bytes = (0, index_js_1.toUint8Array)(data);
const casing = options.case ?? "lower";
const pairs = Array.from(bytes, (byte) => {
const text = byte.toString(16).padStart(2, "0");
return casing === "upper" ? text.toUpperCase() : text;
});
let body = "";
if (options.line) {
const bytesPerLine = options.line.bytesPerLine;
if (!Number.isInteger(bytesPerLine) || bytesPerLine < 1) {
throw new RangeError("Hex bytesPerLine must be a positive integer");
}
const separator = options.line.separator ?? "\n";
const lines = [];
for (let index = 0; index < pairs.length; index += bytesPerLine) {
lines.push(groupPairs(pairs.slice(index, index + bytesPerLine), options.group));
}
body = lines.join(separator);
}
else {
body = groupPairs(pairs, options.group);
}
return `${options.prefix ?? ""}${body}`;
}
function decode(text, options = {}) {
const normalized = normalize(text, options);
const result = new Uint8Array(normalized.length / 2);
for (let i = 0; i < normalized.length; i += 2) {
result[i / 2] = Number.parseInt(normalized.slice(i, i + 2), 16);
}
return result;
}
function parse(text, options = {}) {
const normalized = normalize(text, options);
return {
bytes: decode(normalized),
format: detectFormat(text),
normalized,
};
}
function format(data, value) {
return encode(data, value);
}
exports.formats = {
compact: Object.freeze({}),
upper: Object.freeze({ case: "upper" }),
colon: Object.freeze({ group: { size: 1, separator: ":" } }),
colonUpper: Object.freeze({ case: "upper", group: { size: 1, separator: ":" } }),
groupsOf4: Object.freeze({ group: { size: 4, separator: " " } }),
prefixed: Object.freeze({ prefix: "0x" }),
};
exports.hex = { encode, decode, format, formats: exports.formats, is, normalize, parse };

Some files were not shown because too many files have changed in this diff Show more