serializer.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import * as asn1js from "asn1js";
  2. import * as converters from "./converters";
  3. import { AsnPropTypes, AsnTypeTypes } from "./enums";
  4. import { isConvertible, isArrayEqual } from "./helper";
  5. import { schemaStorage } from "./storage";
  6. export class AsnSerializer {
  7. static serialize(obj) {
  8. if (obj instanceof asn1js.BaseBlock) {
  9. return obj.toBER(false);
  10. }
  11. return this.toASN(obj).toBER(false);
  12. }
  13. static toASN(obj) {
  14. if (obj && typeof obj === "object" && isConvertible(obj)) {
  15. return obj.toASN();
  16. }
  17. if (!(obj && typeof obj === "object")) {
  18. throw new TypeError("Parameter 1 should be type of Object.");
  19. }
  20. const target = obj.constructor;
  21. const schema = schemaStorage.get(target);
  22. schemaStorage.cache(target);
  23. let asn1Value = [];
  24. if (schema.itemType) {
  25. if (!Array.isArray(obj)) {
  26. throw new TypeError("Parameter 1 should be type of Array.");
  27. }
  28. if (typeof schema.itemType === "number") {
  29. const converter = converters.defaultConverter(schema.itemType);
  30. if (!converter) {
  31. throw new Error(`Cannot get default converter for array item of ${target.name} ASN1 schema`);
  32. }
  33. asn1Value = obj.map((o) => converter.toASN(o));
  34. }
  35. else {
  36. asn1Value = obj.map((o) => this.toAsnItem({ type: schema.itemType }, "[]", target, o));
  37. }
  38. }
  39. else {
  40. for (const key in schema.items) {
  41. const schemaItem = schema.items[key];
  42. const objProp = obj[key];
  43. if (objProp === undefined ||
  44. schemaItem.defaultValue === objProp ||
  45. (typeof schemaItem.defaultValue === "object" &&
  46. typeof objProp === "object" &&
  47. isArrayEqual(this.serialize(schemaItem.defaultValue), this.serialize(objProp)))) {
  48. continue;
  49. }
  50. const asn1Item = AsnSerializer.toAsnItem(schemaItem, key, target, objProp);
  51. if (typeof schemaItem.context === "number") {
  52. if (schemaItem.implicit) {
  53. if (!schemaItem.repeated &&
  54. (typeof schemaItem.type === "number" || isConvertible(schemaItem.type))) {
  55. const value = {};
  56. value.valueHex =
  57. asn1Item instanceof asn1js.Null
  58. ? asn1Item.valueBeforeDecodeView
  59. : asn1Item.valueBlock.toBER();
  60. asn1Value.push(new asn1js.Primitive({
  61. optional: schemaItem.optional,
  62. idBlock: {
  63. tagClass: 3,
  64. tagNumber: schemaItem.context,
  65. },
  66. ...value,
  67. }));
  68. }
  69. else {
  70. asn1Value.push(new asn1js.Constructed({
  71. optional: schemaItem.optional,
  72. idBlock: {
  73. tagClass: 3,
  74. tagNumber: schemaItem.context,
  75. },
  76. value: asn1Item.valueBlock.value,
  77. }));
  78. }
  79. }
  80. else {
  81. asn1Value.push(new asn1js.Constructed({
  82. optional: schemaItem.optional,
  83. idBlock: {
  84. tagClass: 3,
  85. tagNumber: schemaItem.context,
  86. },
  87. value: [asn1Item],
  88. }));
  89. }
  90. }
  91. else if (schemaItem.repeated) {
  92. asn1Value = asn1Value.concat(asn1Item);
  93. }
  94. else {
  95. asn1Value.push(asn1Item);
  96. }
  97. }
  98. }
  99. let asnSchema;
  100. switch (schema.type) {
  101. case AsnTypeTypes.Sequence:
  102. asnSchema = new asn1js.Sequence({ value: asn1Value });
  103. break;
  104. case AsnTypeTypes.Set:
  105. asnSchema = new asn1js.Set({ value: asn1Value });
  106. break;
  107. case AsnTypeTypes.Choice:
  108. if (!asn1Value[0]) {
  109. throw new Error(`Schema '${target.name}' has wrong data. Choice cannot be empty.`);
  110. }
  111. asnSchema = asn1Value[0];
  112. break;
  113. }
  114. return asnSchema;
  115. }
  116. static toAsnItem(schemaItem, key, target, objProp) {
  117. let asn1Item;
  118. if (typeof schemaItem.type === "number") {
  119. const converter = schemaItem.converter;
  120. if (!converter) {
  121. throw new Error(`Property '${key}' doesn't have converter for type ${AsnPropTypes[schemaItem.type]} in schema '${target.name}'`);
  122. }
  123. if (schemaItem.repeated) {
  124. if (!Array.isArray(objProp)) {
  125. throw new TypeError("Parameter 'objProp' should be type of Array.");
  126. }
  127. const items = Array.from(objProp, (element) => converter.toASN(element));
  128. const Container = schemaItem.repeated === "sequence" ? asn1js.Sequence : asn1js.Set;
  129. asn1Item = new Container({
  130. value: items,
  131. });
  132. }
  133. else {
  134. asn1Item = converter.toASN(objProp);
  135. }
  136. }
  137. else {
  138. if (schemaItem.repeated) {
  139. if (!Array.isArray(objProp)) {
  140. throw new TypeError("Parameter 'objProp' should be type of Array.");
  141. }
  142. const items = Array.from(objProp, (element) => this.toASN(element));
  143. const Container = schemaItem.repeated === "sequence" ? asn1js.Sequence : asn1js.Set;
  144. asn1Item = new Container({
  145. value: items,
  146. });
  147. }
  148. else {
  149. asn1Item = this.toASN(objProp);
  150. }
  151. }
  152. return asn1Item;
  153. }
  154. }