tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SafeBag.ts (6320B)


      1 import * as asn1js from "asn1js";
      2 import * as pvutils from "pvutils";
      3 import { Attribute, AttributeJson } from "./Attribute";
      4 import * as Schema from "./Schema";
      5 import { PkiObject, PkiObjectParameters } from "./PkiObject";
      6 import { AsnError } from "./errors";
      7 
      8 const BAG_ID = "bagId";
      9 const BAG_VALUE = "bagValue";
     10 const BAG_ATTRIBUTES = "bagAttributes";
     11 const CLEAR_PROPS = [
     12  BAG_ID,
     13  BAG_VALUE,
     14  BAG_ATTRIBUTES
     15 ];
     16 
     17 export interface ISafeBag<T extends BagType = BagType> {
     18  bagId: string;
     19  bagValue: T;
     20  bagAttributes?: Attribute[];
     21 }
     22 
     23 export type SafeBagParameters<T extends BagType = BagType> = PkiObjectParameters & Partial<ISafeBag<T>>;
     24 
     25 export interface SafeBagJson {
     26  bagId: string;
     27  bagValue: BagTypeJson;
     28  bagAttributes?: AttributeJson[];
     29 }
     30 
     31 /**
     32 * Represents the SafeBag structure described in [RFC7292](https://datatracker.ietf.org/doc/html/rfc7292)
     33 */
     34 export class SafeBag<T extends BagType = BagType> extends PkiObject implements ISafeBag<T> {
     35 
     36  public static override CLASS_NAME = "SafeBag";
     37 
     38  public bagId!: string;
     39  public bagValue!: T;
     40  public bagAttributes?: Attribute[];
     41 
     42  /**
     43   * Initializes a new instance of the {@link SafeBag} class
     44   * @param parameters Initialization parameters
     45   */
     46  constructor(parameters: SafeBagParameters<T> = {}) {
     47    super();
     48 
     49    this.bagId = pvutils.getParametersValue(parameters, BAG_ID, SafeBag.defaultValues(BAG_ID));
     50    this.bagValue = pvutils.getParametersValue(parameters, BAG_VALUE, SafeBag.defaultValues(BAG_VALUE)) as unknown as T;
     51    if (BAG_ATTRIBUTES in parameters) {
     52      this.bagAttributes = pvutils.getParametersValue(parameters, BAG_ATTRIBUTES, SafeBag.defaultValues(BAG_ATTRIBUTES));
     53    }
     54 
     55    if (parameters.schema) {
     56      this.fromSchema(parameters.schema);
     57    }
     58  }
     59 
     60  /**
     61   * Returns default values for all class members
     62   * @param memberName String name for a class member
     63   * @returns Default value
     64   */
     65  public static override defaultValues(memberName: typeof BAG_ID): string;
     66  public static override defaultValues(memberName: typeof BAG_VALUE): BagType;
     67  public static override defaultValues(memberName: typeof BAG_ATTRIBUTES): Attribute[];
     68  public static override defaultValues(memberName: string): any {
     69    switch (memberName) {
     70      case BAG_ID:
     71        return EMPTY_STRING;
     72      case BAG_VALUE:
     73        return (new asn1js.Any());
     74      case BAG_ATTRIBUTES:
     75        return [];
     76      default:
     77        return super.defaultValues(memberName);
     78    }
     79  }
     80 
     81  /**
     82   * Compare values with default values for all class members
     83   * @param memberName String name for a class member
     84   * @param memberValue Value to compare with default value
     85   */
     86  public static compareWithDefault(memberName: string, memberValue: any): boolean {
     87    switch (memberName) {
     88      case BAG_ID:
     89        return (memberValue === EMPTY_STRING);
     90      case BAG_VALUE:
     91        return (memberValue instanceof asn1js.Any);
     92      case BAG_ATTRIBUTES:
     93        return (memberValue.length === 0);
     94      default:
     95        return super.defaultValues(memberName);
     96    }
     97  }
     98 
     99  /**
    100   * @inheritdoc
    101   * @asn ASN.1 schema
    102   * ```asn
    103   * SafeBag ::= SEQUENCE {
    104   *    bagId         BAG-TYPE.&id ({PKCS12BagSet}),
    105   *    bagValue      [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
    106   *    bagAttributes SET OF PKCS12Attribute OPTIONAL
    107   * }
    108   *```
    109   */
    110  public static override schema(parameters: Schema.SchemaParameters<{
    111    bagId?: string;
    112    bagValue?: string;
    113    bagAttributes?: string;
    114  }> = {}): Schema.SchemaType {
    115    const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});
    116 
    117    return (new asn1js.Sequence({
    118      name: (names.blockName || EMPTY_STRING),
    119      value: [
    120        new asn1js.ObjectIdentifier({ name: (names.bagId || BAG_ID) }),
    121        new asn1js.Constructed({
    122          idBlock: {
    123            tagClass: 3, // CONTEXT-SPECIFIC
    124            tagNumber: 0 // [0]
    125          },
    126          value: [new asn1js.Any({ name: (names.bagValue || BAG_VALUE) })] // EXPLICIT ANY value
    127        }),
    128        new asn1js.Set({
    129          optional: true,
    130          value: [
    131            new asn1js.Repeated({
    132              name: (names.bagAttributes || BAG_ATTRIBUTES),
    133              value: Attribute.schema()
    134            })
    135          ]
    136        })
    137      ]
    138    }));
    139  }
    140 
    141  public fromSchema(schema: Schema.SchemaType): void {
    142    // Clear input data first
    143    pvutils.clearProps(schema, CLEAR_PROPS);
    144 
    145    // Check the schema is valid
    146    const asn1 = asn1js.compareSchema(schema,
    147      schema,
    148      SafeBag.schema({
    149        names: {
    150          bagId: BAG_ID,
    151          bagValue: BAG_VALUE,
    152          bagAttributes: BAG_ATTRIBUTES
    153        }
    154      })
    155    );
    156    AsnError.assertSchema(asn1, this.className);
    157 
    158    //#region Get internal properties from parsed schema
    159    this.bagId = asn1.result.bagId.valueBlock.toString();
    160 
    161    const bagType = SafeBagValueFactory.find(this.bagId);
    162    if (!bagType) {
    163      throw new Error(`Invalid BAG_ID for SafeBag: ${this.bagId}`);
    164    }
    165    this.bagValue = new bagType({ schema: asn1.result.bagValue }) as unknown as T;
    166 
    167    if (BAG_ATTRIBUTES in asn1.result) {
    168      this.bagAttributes = Array.from(asn1.result.bagAttributes, element => new Attribute({ schema: element }));
    169    }
    170    //#endregion
    171  }
    172 
    173  public toSchema(): asn1js.Sequence {
    174    //#region Construct and return new ASN.1 schema for this object
    175    const outputArray = [
    176      new asn1js.ObjectIdentifier({ value: this.bagId }),
    177      new asn1js.Constructed({
    178        idBlock: {
    179          tagClass: 3, // CONTEXT-SPECIFIC
    180          tagNumber: 0 // [0]
    181        },
    182        value: [this.bagValue.toSchema()]
    183      })
    184    ];
    185 
    186    if (this.bagAttributes) {
    187      outputArray.push(new asn1js.Set({
    188        value: Array.from(this.bagAttributes, o => o.toSchema())
    189      }));
    190    }
    191 
    192    return (new asn1js.Sequence({
    193      value: outputArray
    194    }));
    195    //#endregion
    196  }
    197 
    198  public toJSON(): SafeBagJson {
    199    const output: SafeBagJson = {
    200      bagId: this.bagId,
    201      bagValue: this.bagValue.toJSON()
    202    };
    203 
    204    if (this.bagAttributes) {
    205      output.bagAttributes = Array.from(this.bagAttributes, o => o.toJSON());
    206    }
    207 
    208    return output;
    209  }
    210 
    211 }
    212 
    213 import { type BagType, SafeBagValueFactory, BagTypeJson } from "./SafeBagValueFactory";
    214 import { EMPTY_STRING } from "./constants";