Skip to content

Commit

Permalink
Merge pull request #12 from ESTOS/feature/BUILDSYS-389
Browse files Browse the repository at this point in the history
BUILDSYS-389 Add Extension Element to the schema to announce extendable structures like with ... in asn1
  • Loading branch information
JanFellner authored Jan 5, 2024
2 parents a913715 + 4bafdf1 commit e7800ec
Show file tree
Hide file tree
Showing 14 changed files with 1,957 additions and 928 deletions.
21 changes: 18 additions & 3 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
},
"plugins": [
"@typescript-eslint",
"deprecation"
"deprecation",
"import",
"unused-imports"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
"plugin:@typescript-eslint/recommended",
"plugin:import/typescript"
],
"ignorePatterns": [
"build/**/*.ts",
Expand Down Expand Up @@ -49,6 +52,18 @@
"@typescript-eslint/semi": 2,
"@typescript-eslint/quotes": 2,
"@typescript-eslint/explicit-module-boundary-types": 0,
"@typescript-eslint/triple-slash-reference": 0
"@typescript-eslint/triple-slash-reference": 0,
"import/no-restricted-paths": [
"error",
{
"zones": [
{
"target": "**/*",
"from": "build"
}
]
}
],
"unused-imports/no-unused-imports": "error"
}
}
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ jobs:
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel: true
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
},
"eslint.alwaysShowStatus": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
}
}
18 changes: 18 additions & 0 deletions asn1ts.code-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"tslint.enable": false,
"eslint.enable": true,
"javascript.preferences.quoteStyle": "double",
"typescript.preferences.quoteStyle": "double",
"editor.tabCompletion": "on",
"eslint.alwaysShowStatus": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
}
11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@estos/asn1ts",
"version": "3.1.12",
"version": "3.2.0",
"license": "BSD-3-Clause",
"author": {
"name": "estos GmbH",
Expand All @@ -22,21 +22,24 @@
}
],
"engines": {
"node": ">=18.0.0"
"node": ">=18"
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/mocha": "^10.0.1",
"@types/node": "^20.8.6",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"asn1-test-suite": "^1.0.2",
"eslint": "^8.31.0",
"eslint-plugin-deprecation": "^2.0.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-unused-imports": "^3.0.0",
"mocha": "^10.2.0",
"npm-run-all": "^4.1.5",
"nyc": "^15.1.0",
"rollup": "^4.1.4",
"rollup-plugin-dts": "^6.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-typescript2": "^0.36.0",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
Expand Down Expand Up @@ -85,6 +88,8 @@
"prepublishOnly": "npm run build",
"lint": "eslint . --ext .ts",
"lint:fix": "eslint --fix . --ext .ts",
"relint": "run-s lintclear lint",
"lintclear": "del /s .eslintcache",
"coverage": "nyc npm test"
}
}
54 changes: 54 additions & 0 deletions src/Extension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { ViewWriter } from "./ViewWriter";
import { ValueBlock, ValueBlockJson } from "./ValueBlock";
import { BaseBlock } from "./BaseBlock";
import { ETagClass, EUniversalTagNumber, typeStore } from "./TypeStore";

/**
* It is possible to add a ... to the asn1 Schema for objects that are extendable (The other side may add attributes)
* In order to handle that properly we define a dummy type inside of a schema and this dummy type tells us whether a structure may be larger than expecteed (contains a ... in the ans1 Definitions)
*
* This will value will never get encoded or decoded as there is no such type in any encoding
*/
export class Extension extends BaseBlock<ValueBlock, ValueBlockJson> {
static {
typeStore.Extension = this;
}

public static override NAME = "NULL";
public static override defaultIDs = {tagClass: ETagClass.UNIVERSAL, tagNumber: EUniversalTagNumber.Extension};

constructor() {
super({idBlock: Extension.defaultIDs}, ValueBlock);

}

public getValue(): null {
return null;
}

public setValue(value: number): void {
}

public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
throw new Error("An extension attribute should never get decoded... It´s just for schema validation");
}

public override toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer {
throw new Error("An extension attribute should never get encoded... It´s just for schema validation");
}

protected override onAsciiEncoding(): string {
return `${(this.constructor as typeof Extension).NAME}`;
}

/**
* A typeguard that allows to validate if a certain asn1.js object is of our type
*
* @param obj The object we want to match against the type of this class
* @returns true if obj is of the same type as our class
*/
public static typeGuard(obj: unknown | undefined): obj is Extension {
return this.matches(obj);
}

}
8 changes: 7 additions & 1 deletion src/TypeStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import type { UTCTime } from "./UTCTime";
import type { Utf8String } from "./Utf8String";
import type { VideotexString } from "./VideotexString";
import type { VisibleString } from "./VisibleString";
import { Extension } from "./Extension";

export type AsnType = BaseBlock | EndOfContent | AsnBoolean | Integer | Real | BitString | OctetString | Null | ObjectIdentifier | Enumerated | Utf8String | RelativeObjectIdentifier | TIME | Sequence | Set | NumericString | PrintableString | TeletexString | VideotexString | IA5String | UTCTime | GeneralizedTime | GraphicString | VisibleString | GeneralString | UniversalString | CharacterString | BmpString | DATE | TimeOfDay | DateTime | Duration | Constructed | Primitive;

Expand Down Expand Up @@ -69,6 +70,7 @@ export interface TypeStore {
Utf8String: typeof Utf8String;
VideotexString: typeof VideotexString;
VisibleString: typeof VisibleString;
Extension: typeof Extension;
}

export enum ETagClass {
Expand Down Expand Up @@ -115,7 +117,9 @@ export enum EUniversalTagNumber {
DATE = 31,
TimeOfDay = 32,
DateTime = 33,
Duration = 34
Duration = 34,
/** The extension element marks that a schema may contain more attributes than specifieid, thus it defines whether parsing complains about further elements in the schema or not */
Extension = 35
}

/* istanbul ignore next */
Expand Down Expand Up @@ -199,6 +203,8 @@ export function getTagNumberAsText(tagNumber: EUniversalTagNumber): string {
return "DateTime";
case EUniversalTagNumber.Duration:
return "Duration";
case EUniversalTagNumber.Extension:
return "Extension";
default:
return `TAGNUMBER(${tagNumber})`;
}
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export * from "./EndOfContent";

/** common */
export * from "./Null";
export * from "./Extension";
export * from "./Boolean";
export * from "./OctetString";
export * from "./BitString";
Expand Down
24 changes: 13 additions & 11 deletions src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { LocalLengthBlock } from "./internals/LocalLengthBlock";
import { BaseBlock } from "./BaseBlock";
import { SequenceOf } from "./SequenceOf";
import { SetOf } from "./SetOf";
import { Extension } from "./Extension";

export type AsnSchemaType = AsnType | Any | Choice | SequenceOf | SetOf;

Expand All @@ -30,14 +31,11 @@ export interface CompareSchemaFail {
* Allows to configure laxer or stricter parsing
*/
export class VerifyOptions {
constructor(continueOnError = true, allowLargerThanSchema = false) {
constructor(continueOnError = true) {
this.continueOnError = continueOnError;
this.allowLargerThanSchema = allowLargerThanSchema;
}
/** Parsing continues on an error, the errorlist contains all errors */
public continueOnError: boolean;
/** If the asn1 object is larger than the schema, this is not an error */
public allowLargerThanSchema: boolean;
}

/**
Expand Down Expand Up @@ -529,14 +527,18 @@ function compareSchemaInternal(root: AsnType, inputSchema: AsnSchemaType, option
let inputObject = inputValue[i - admission];
let schema = inputSchema.valueBlock.value[i];

if (Extension.typeGuard(schema)) {
// As soon as we face the extension attribute we can no further decode the incoming object
// The schema ends here and the incoming playload may be larger but not relevant to the one providing the schema
break;
}

const newContext = context.recurse(schema);

if (!schema) {
/** The input object exists but is not reference in the schema. */
if (!options.allowLargerThanSchema) {
/** This is not allowed, let´s throw an error */
newContext.path += inputObject.idBlock.getDebug("-");
errors.push(new SchemaError(ESchemaError.ASN1_IS_LARGER_THAN_SCHEMA, newContext));
}
/** This is not allowed, let´s throw an error */
newContext.path += inputObject.idBlock.getDebug("-");
errors.push(new SchemaError(ESchemaError.ASN1_IS_LARGER_THAN_SCHEMA, newContext));
return errors;
}

Expand Down Expand Up @@ -580,7 +582,7 @@ function compareSchemaInternal(root: AsnType, inputSchema: AsnSchemaType, option
/** Now we need to calculate the offset of the payload inside the source elements, It´s the source idblock length + the source len block length */
const offset = inputObject.lenBlock.blockLength + inputObject.idBlock.blockLength;
const decoded = contextualElement.fromBER(contextualElement.valueBeforeDecodeView, offset, contextualElement.valueBeforeDecodeView.length);
if (decoded) {
if (decoded >= 0) {
inputObject = contextualElement;
inputValue[i - admission] = contextualElement;
}
Expand Down
6 changes: 0 additions & 6 deletions test/asn1repeated.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import * as assert from "assert";
import * as asn1ts from "../src";
import * as pvtsutils from "pvtsutils";
import { SchemaContext } from "../src";
import { ILocalIdentificationBlockParams } from "../src/internals/LocalIdentificationBlock";
import { localFromBER } from "../src/parser";
import { ETagClass } from "../src/TypeStore";


/**
* Gets a repeated schema
Expand Down
20 changes: 6 additions & 14 deletions test/simple_examples.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import * as assert from "assert";
import * as asn1ts from "../src";
import * as pvtsutils from "pvtsutils";

context("Simple examples from the readme.md", () => {
it ("How to create a simple ASN structures", () => {
Expand All @@ -18,7 +17,8 @@ context("Simple examples from the readme.md", () => {
const encoded = seq.toBER();

// 300e0c06737472696e670201010101ff
console.log(Buffer.from(new Uint8Array(encoded)).toString("hex"));
const HexEncoded = Buffer.from(new Uint8Array(encoded)).toString("hex");
assert.equal(HexEncoded, "300e0c06737472696e670201010101ff");
});

it ("How to validate data against a scheme", () => {
Expand Down Expand Up @@ -46,15 +46,11 @@ context("Simple examples from the readme.md", () => {

// Verify the data against the schema
const result = asn1ts.verifySchema(encoded, scheme);
assert.equal(result.verified, true);
if (result.verified) {
// Schema has been verified, let´s get the property "integer_value"
const asn1tsInteger = result.result.getTypedValueByName(asn1ts.Integer, "integer_value");
if (asn1tsInteger) {
// 1
console.log(asn1tsInteger.getValue());
}
} else {
console.log(result.errors);
assert.equal(asn1tsInteger.getValue(), 1);
}
});

Expand Down Expand Up @@ -84,15 +80,11 @@ context("Simple examples from the readme.md", () => {

// Verify the data against the schema
const result = asn1ts.verifySchema(encoded, scheme);
assert.equal(result.verified, true);
if (result.verified) {
// Schema has been verified, let´s get the property "integer_value"
const asn1tsInteger = result.result.getTypedValueByName(asn1ts.Integer, "integer_value");
if (asn1tsInteger) {
// 2
console.log(asn1tsInteger.getValue());
}
} else {
console.log(result.errors);
assert.equal(asn1tsInteger.getValue(), 2);
}
});

Expand Down
Loading

0 comments on commit e7800ec

Please sign in to comment.