@rapidmx/activesync-plugin 1.0.0-beta.2 → 1.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/README.md +4 -4
  2. package/dist/lib/BaseDeviceSyncStateRoute.js +32 -0
  3. package/dist/lib/BaseDeviceSyncStateRoute.js.map +1 -1
  4. package/dist/lib/BaseEasRoute.js +91 -15
  5. package/dist/lib/BaseEasRoute.js.map +1 -1
  6. package/dist/lib/EasAuditLog.js +56 -0
  7. package/dist/lib/EasAuditLog.js.map +1 -0
  8. package/dist/lib/EasCollectionLease.js +199 -0
  9. package/dist/lib/EasCollectionLease.js.map +1 -0
  10. package/dist/lib/EasCollectionStore.js +102 -0
  11. package/dist/lib/EasCollectionStore.js.map +1 -0
  12. package/dist/lib/EasCollectionSync.js +294 -0
  13. package/dist/lib/EasCollectionSync.js.map +1 -0
  14. package/dist/lib/EasSyncKeyUtils.js +125 -62
  15. package/dist/lib/EasSyncKeyUtils.js.map +1 -1
  16. package/dist/lib/MessageMoveRules.js +100 -0
  17. package/dist/lib/MessageMoveRules.js.map +1 -0
  18. package/dist/lib/MimeHeaderUtils.js +395 -0
  19. package/dist/lib/MimeHeaderUtils.js.map +1 -0
  20. package/dist/lib/RegexPatternUtils.js +30 -0
  21. package/dist/lib/RegexPatternUtils.js.map +1 -0
  22. package/dist/lib/RestapiCompat.js +41 -0
  23. package/dist/lib/RestapiCompat.js.map +1 -0
  24. package/dist/lib/adapters/CalendarSyncAdapter.js +142 -33
  25. package/dist/lib/adapters/CalendarSyncAdapter.js.map +1 -1
  26. package/dist/lib/adapters/EmailSyncAdapter.js +114 -27
  27. package/dist/lib/adapters/EmailSyncAdapter.js.map +1 -1
  28. package/dist/lib/adapters/mongo/EmailSyncAdapterMongo.js +2 -1
  29. package/dist/lib/adapters/mongo/EmailSyncAdapterMongo.js.map +1 -1
  30. package/dist/lib/adapters/sql/EmailSyncAdapterSQL.js +2 -1
  31. package/dist/lib/adapters/sql/EmailSyncAdapterSQL.js.map +1 -1
  32. package/dist/lib/codec/WbxmlDecoder.js +86 -34
  33. package/dist/lib/codec/WbxmlDecoder.js.map +1 -1
  34. package/dist/lib/codec/WbxmlEncoder.js +103 -22
  35. package/dist/lib/codec/WbxmlEncoder.js.map +1 -1
  36. package/dist/lib/commands/ComposeMailCommand.js +105 -31
  37. package/dist/lib/commands/ComposeMailCommand.js.map +1 -1
  38. package/dist/lib/commands/FolderSyncCommand.js +67 -27
  39. package/dist/lib/commands/FolderSyncCommand.js.map +1 -1
  40. package/dist/lib/commands/GetItemEstimateCommand.js +80 -59
  41. package/dist/lib/commands/GetItemEstimateCommand.js.map +1 -1
  42. package/dist/lib/commands/ItemOperationsCommand.js +219 -56
  43. package/dist/lib/commands/ItemOperationsCommand.js.map +1 -1
  44. package/dist/lib/commands/MeetingResponseCommand.js +212 -53
  45. package/dist/lib/commands/MeetingResponseCommand.js.map +1 -1
  46. package/dist/lib/commands/MoveItemsCommand.js +54 -21
  47. package/dist/lib/commands/MoveItemsCommand.js.map +1 -1
  48. package/dist/lib/commands/PingCommand.js +288 -56
  49. package/dist/lib/commands/PingCommand.js.map +1 -1
  50. package/dist/lib/commands/ProvisionCommand.js +34 -17
  51. package/dist/lib/commands/ProvisionCommand.js.map +1 -1
  52. package/dist/lib/commands/ResolveRecipientsCommand.js +43 -5
  53. package/dist/lib/commands/ResolveRecipientsCommand.js.map +1 -1
  54. package/dist/lib/commands/SearchCommand.js +92 -17
  55. package/dist/lib/commands/SearchCommand.js.map +1 -1
  56. package/dist/lib/commands/SettingsCommand.js +2 -1
  57. package/dist/lib/commands/SettingsCommand.js.map +1 -1
  58. package/dist/lib/commands/SmartForwardCommand.js +2 -1
  59. package/dist/lib/commands/SmartForwardCommand.js.map +1 -1
  60. package/dist/lib/commands/SmartReplyCommand.js +2 -1
  61. package/dist/lib/commands/SmartReplyCommand.js.map +1 -1
  62. package/dist/lib/commands/SyncCommand.js +481 -244
  63. package/dist/lib/commands/SyncCommand.js.map +1 -1
  64. package/dist/lib/commands/mongo/GetItemEstimateCommandMongo.js +6 -1
  65. package/dist/lib/commands/mongo/GetItemEstimateCommandMongo.js.map +1 -1
  66. package/dist/lib/commands/mongo/ItemOperationsCommandMongo.js +3 -1
  67. package/dist/lib/commands/mongo/ItemOperationsCommandMongo.js.map +1 -1
  68. package/dist/lib/commands/mongo/MeetingResponseCommandMongo.js +2 -1
  69. package/dist/lib/commands/mongo/MeetingResponseCommandMongo.js.map +1 -1
  70. package/dist/lib/commands/mongo/PingCommandMongo.js +23 -0
  71. package/dist/lib/commands/mongo/PingCommandMongo.js.map +1 -0
  72. package/dist/lib/commands/mongo/SearchCommandMongo.js +3 -1
  73. package/dist/lib/commands/mongo/SearchCommandMongo.js.map +1 -1
  74. package/dist/lib/commands/mongo/SendMailCommandMongo.js +2 -1
  75. package/dist/lib/commands/mongo/SendMailCommandMongo.js.map +1 -1
  76. package/dist/lib/commands/mongo/SmartForwardCommandMongo.js +2 -1
  77. package/dist/lib/commands/mongo/SmartForwardCommandMongo.js.map +1 -1
  78. package/dist/lib/commands/mongo/SmartReplyCommandMongo.js +2 -1
  79. package/dist/lib/commands/mongo/SmartReplyCommandMongo.js.map +1 -1
  80. package/dist/lib/commands/mongo/SyncCommandMongo.js +7 -1
  81. package/dist/lib/commands/mongo/SyncCommandMongo.js.map +1 -1
  82. package/dist/lib/commands/mongo/index.js +1 -0
  83. package/dist/lib/commands/mongo/index.js.map +1 -1
  84. package/dist/lib/commands/sql/GetItemEstimateCommandSQL.js +6 -1
  85. package/dist/lib/commands/sql/GetItemEstimateCommandSQL.js.map +1 -1
  86. package/dist/lib/commands/sql/ItemOperationsCommandSQL.js +3 -1
  87. package/dist/lib/commands/sql/ItemOperationsCommandSQL.js.map +1 -1
  88. package/dist/lib/commands/sql/MeetingResponseCommandSQL.js +2 -1
  89. package/dist/lib/commands/sql/MeetingResponseCommandSQL.js.map +1 -1
  90. package/dist/lib/commands/sql/PingCommandSQL.js +23 -0
  91. package/dist/lib/commands/sql/PingCommandSQL.js.map +1 -0
  92. package/dist/lib/commands/sql/SearchCommandSQL.js +3 -1
  93. package/dist/lib/commands/sql/SearchCommandSQL.js.map +1 -1
  94. package/dist/lib/commands/sql/SendMailCommandSQL.js +2 -1
  95. package/dist/lib/commands/sql/SendMailCommandSQL.js.map +1 -1
  96. package/dist/lib/commands/sql/SmartForwardCommandSQL.js +2 -1
  97. package/dist/lib/commands/sql/SmartForwardCommandSQL.js.map +1 -1
  98. package/dist/lib/commands/sql/SmartReplyCommandSQL.js +2 -1
  99. package/dist/lib/commands/sql/SmartReplyCommandSQL.js.map +1 -1
  100. package/dist/lib/commands/sql/SyncCommandSQL.js +7 -1
  101. package/dist/lib/commands/sql/SyncCommandSQL.js.map +1 -1
  102. package/dist/lib/commands/sql/index.js +1 -0
  103. package/dist/lib/commands/sql/index.js.map +1 -1
  104. package/dist/lib/index.js +5 -0
  105. package/dist/lib/index.js.map +1 -1
  106. package/dist/lib/jobs/EasDeviceStateCleanupJob.js +44 -2
  107. package/dist/lib/jobs/EasDeviceStateCleanupJob.js.map +1 -1
  108. package/dist/lib/jobs/mongo/EasDeviceStateCleanupJobMongo.js +4 -0
  109. package/dist/lib/jobs/mongo/EasDeviceStateCleanupJobMongo.js.map +1 -1
  110. package/dist/lib/jobs/sql/EasDeviceStateCleanupJobSQL.js +9 -0
  111. package/dist/lib/jobs/sql/EasDeviceStateCleanupJobSQL.js.map +1 -1
  112. package/dist/lib/models/EasCollectionChunk.js +2 -0
  113. package/dist/lib/models/EasCollectionChunk.js.map +1 -0
  114. package/dist/lib/models/EasCollectionState.js +2 -0
  115. package/dist/lib/models/EasCollectionState.js.map +1 -0
  116. package/dist/lib/models/mongo/DeviceSyncStateMongo.js +7 -0
  117. package/dist/lib/models/mongo/DeviceSyncStateMongo.js.map +1 -1
  118. package/dist/lib/models/mongo/EasCollectionChunkMongo.js +83 -0
  119. package/dist/lib/models/mongo/EasCollectionChunkMongo.js.map +1 -0
  120. package/dist/lib/models/mongo/EasCollectionStateMongo.js +162 -0
  121. package/dist/lib/models/mongo/EasCollectionStateMongo.js.map +1 -0
  122. package/dist/lib/models/sql/DeviceSyncStateSQL.js +7 -0
  123. package/dist/lib/models/sql/DeviceSyncStateSQL.js.map +1 -1
  124. package/dist/lib/models/sql/EasCollectionChunkSQL.js +83 -0
  125. package/dist/lib/models/sql/EasCollectionChunkSQL.js.map +1 -0
  126. package/dist/lib/models/sql/EasCollectionStateSQL.js +162 -0
  127. package/dist/lib/models/sql/EasCollectionStateSQL.js.map +1 -0
  128. package/dist/lib/mongo/EasRouteMongo.js +2 -2
  129. package/dist/lib/mongo/EasRouteMongo.js.map +1 -1
  130. package/dist/lib/mongo.js +2 -0
  131. package/dist/lib/mongo.js.map +1 -1
  132. package/dist/lib/sql/EasRouteSQL.js +2 -2
  133. package/dist/lib/sql/EasRouteSQL.js.map +1 -1
  134. package/dist/lib/sql.js +2 -0
  135. package/dist/lib/sql.js.map +1 -1
  136. package/dist/types/BaseDeviceSyncStateRoute.d.ts +10 -0
  137. package/dist/types/BaseEasRoute.d.ts +15 -4
  138. package/dist/types/EasAuditLog.d.ts +47 -0
  139. package/dist/types/EasCollectionLease.d.ts +60 -0
  140. package/dist/types/EasCollectionStore.d.ts +51 -0
  141. package/dist/types/EasCollectionSync.d.ts +96 -0
  142. package/dist/types/EasCommandHandler.d.ts +7 -4
  143. package/dist/types/EasSyncKeyUtils.d.ts +73 -42
  144. package/dist/types/MessageMoveRules.d.ts +45 -0
  145. package/dist/types/MimeHeaderUtils.d.ts +73 -0
  146. package/dist/types/RegexPatternUtils.d.ts +14 -0
  147. package/dist/types/RestapiCompat.d.ts +24 -0
  148. package/dist/types/adapters/CalendarSyncAdapter.d.ts +47 -18
  149. package/dist/types/adapters/EasCollectionSyncAdapter.d.ts +18 -2
  150. package/dist/types/adapters/EmailSyncAdapter.d.ts +24 -7
  151. package/dist/types/adapters/mongo/EmailSyncAdapterMongo.d.ts +1 -0
  152. package/dist/types/adapters/sql/EmailSyncAdapterSQL.d.ts +1 -0
  153. package/dist/types/codec/WbxmlDecoder.d.ts +39 -0
  154. package/dist/types/codec/WbxmlEncoder.d.ts +36 -1
  155. package/dist/types/commands/ComposeMailCommand.d.ts +33 -15
  156. package/dist/types/commands/FolderSyncCommand.d.ts +4 -1
  157. package/dist/types/commands/GetItemEstimateCommand.d.ts +20 -15
  158. package/dist/types/commands/ItemOperationsCommand.d.ts +29 -4
  159. package/dist/types/commands/MeetingResponseCommand.d.ts +52 -13
  160. package/dist/types/commands/MoveItemsCommand.d.ts +13 -3
  161. package/dist/types/commands/PingCommand.d.ts +72 -14
  162. package/dist/types/commands/ProvisionCommand.d.ts +16 -11
  163. package/dist/types/commands/ResolveRecipientsCommand.d.ts +4 -0
  164. package/dist/types/commands/SearchCommand.d.ts +13 -1
  165. package/dist/types/commands/SyncCommand.d.ts +102 -62
  166. package/dist/types/commands/mongo/GetItemEstimateCommandMongo.d.ts +3 -0
  167. package/dist/types/commands/mongo/ItemOperationsCommandMongo.d.ts +2 -0
  168. package/dist/types/commands/mongo/MeetingResponseCommandMongo.d.ts +1 -0
  169. package/dist/types/commands/mongo/PingCommandMongo.d.ts +8 -0
  170. package/dist/types/commands/mongo/SearchCommandMongo.d.ts +2 -0
  171. package/dist/types/commands/mongo/SendMailCommandMongo.d.ts +1 -0
  172. package/dist/types/commands/mongo/SmartForwardCommandMongo.d.ts +1 -0
  173. package/dist/types/commands/mongo/SmartReplyCommandMongo.d.ts +1 -0
  174. package/dist/types/commands/mongo/SyncCommandMongo.d.ts +4 -0
  175. package/dist/types/commands/mongo/index.d.ts +1 -0
  176. package/dist/types/commands/sql/GetItemEstimateCommandSQL.d.ts +3 -0
  177. package/dist/types/commands/sql/ItemOperationsCommandSQL.d.ts +2 -0
  178. package/dist/types/commands/sql/MeetingResponseCommandSQL.d.ts +1 -0
  179. package/dist/types/commands/sql/PingCommandSQL.d.ts +8 -0
  180. package/dist/types/commands/sql/SearchCommandSQL.d.ts +2 -0
  181. package/dist/types/commands/sql/SendMailCommandSQL.d.ts +1 -0
  182. package/dist/types/commands/sql/SmartForwardCommandSQL.d.ts +1 -0
  183. package/dist/types/commands/sql/SmartReplyCommandSQL.d.ts +1 -0
  184. package/dist/types/commands/sql/SyncCommandSQL.d.ts +4 -0
  185. package/dist/types/commands/sql/index.d.ts +1 -0
  186. package/dist/types/index.d.ts +5 -0
  187. package/dist/types/jobs/EasDeviceStateCleanupJob.d.ts +15 -0
  188. package/dist/types/jobs/mongo/EasDeviceStateCleanupJobMongo.d.ts +2 -0
  189. package/dist/types/jobs/sql/EasDeviceStateCleanupJobSQL.d.ts +4 -0
  190. package/dist/types/models/DeviceSyncState.d.ts +13 -2
  191. package/dist/types/models/EasCollectionChunk.d.ts +20 -0
  192. package/dist/types/models/EasCollectionState.d.ts +79 -0
  193. package/dist/types/models/mongo/DeviceSyncStateMongo.d.ts +1 -0
  194. package/dist/types/models/mongo/EasCollectionChunkMongo.d.ts +16 -0
  195. package/dist/types/models/mongo/EasCollectionStateMongo.d.ts +27 -0
  196. package/dist/types/models/sql/DeviceSyncStateSQL.d.ts +1 -0
  197. package/dist/types/models/sql/EasCollectionChunkSQL.d.ts +16 -0
  198. package/dist/types/models/sql/EasCollectionStateSQL.d.ts +27 -0
  199. package/dist/types/mongo.d.ts +2 -0
  200. package/dist/types/sql.d.ts +2 -0
  201. package/package.json +267 -238
@@ -2,7 +2,7 @@
2
2
  // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
3
  // SPDX-License-Identifier: MPL-2.0
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
- import { LabelMongo } from "@rapidmx/restapi/mongo";
5
+ import { FolderMongo, LabelMongo } from "@rapidmx/restapi/mongo";
6
6
  import { EmailSyncAdapter } from "../EmailSyncAdapter.js";
7
7
  /**
8
8
  * @author Jean-Philippe Steinmetz
@@ -11,6 +11,7 @@ export class EmailSyncAdapterMongo extends EmailSyncAdapter {
11
11
  constructor() {
12
12
  super(...arguments);
13
13
  this.labelClass = LabelMongo;
14
+ this.folderClass = FolderMongo;
14
15
  }
15
16
  }
16
17
  //# sourceMappingURL=EmailSyncAdapterMongo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"EmailSyncAdapterMongo.js","sourceRoot":"","sources":["../../../../src/adapters/mongo/EmailSyncAdapterMongo.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;GAEG;AACH,MAAM,OAAO,qBAAsB,SAAQ,gBAAgB;IAA3D;;QACc,eAAU,GAAQ,UAAU,CAAC;IAC3C,CAAC;CAAA"}
1
+ {"version":3,"file":"EmailSyncAdapterMongo.js","sourceRoot":"","sources":["../../../../src/adapters/mongo/EmailSyncAdapterMongo.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;GAEG;AACH,MAAM,OAAO,qBAAsB,SAAQ,gBAAgB;IAA3D;;QACc,eAAU,GAAQ,UAAU,CAAC;QAC7B,gBAAW,GAAQ,WAAW,CAAC;IAC7C,CAAC;CAAA"}
@@ -2,7 +2,7 @@
2
2
  // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
3
  // SPDX-License-Identifier: MPL-2.0
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
- import { LabelSQL } from "@rapidmx/restapi/sql";
5
+ import { FolderSQL, LabelSQL } from "@rapidmx/restapi/sql";
6
6
  import { EmailSyncAdapter } from "../EmailSyncAdapter.js";
7
7
  /**
8
8
  * @author Jean-Philippe Steinmetz
@@ -11,6 +11,7 @@ export class EmailSyncAdapterSQL extends EmailSyncAdapter {
11
11
  constructor() {
12
12
  super(...arguments);
13
13
  this.labelClass = LabelSQL;
14
+ this.folderClass = FolderSQL;
14
15
  }
15
16
  }
16
17
  //# sourceMappingURL=EmailSyncAdapterSQL.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"EmailSyncAdapterSQL.js","sourceRoot":"","sources":["../../../../src/adapters/sql/EmailSyncAdapterSQL.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,gBAAgB;IAAzD;;QACc,eAAU,GAAQ,QAAQ,CAAC;IACzC,CAAC;CAAA"}
1
+ {"version":3,"file":"EmailSyncAdapterSQL.js","sourceRoot":"","sources":["../../../../src/adapters/sql/EmailSyncAdapterSQL.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,gBAAgB;IAAzD;;QACc,eAAU,GAAQ,QAAQ,CAAC;QAC3B,gBAAW,GAAQ,SAAS,CAAC;IAC3C,CAAC;CAAA"}
@@ -11,18 +11,49 @@ const OPAQUE = 0xc3;
11
11
  const CONTENT_FLAG = 0x40;
12
12
  const ATTR_FLAG = 0x80;
13
13
  const TAG_CODE_MASK = 0x3f;
14
- /** Caps `readTagElement`/`readContentUntilEnd`'s mutual recursion depth - unlike every length-prefixed field in
15
- * this format, element nesting has no size-based bound at all, and costs as little as ~2 bytes of wire format
16
- * per level (a content-flagged tag byte immediately followed by its own `END`), so an unbounded decoder lets a
17
- * tiny crafted request drive the recursion deep enough to exhaust the call stack. No real EAS document (the
18
- * deepest legitimate shape here is roughly `Sync > Collections > Collection > Commands > Add > ApplicationData
19
- * > Body > ...`, well under 20 levels) comes anywhere close to this limit. */
20
- const MAX_NESTING_DEPTH = 200;
14
+ /** Default cap on the total number of elements decoded from one document. An element costs as little as one
15
+ * wire byte (an empty tag token), so without this a small body could allocate millions of element objects. */
16
+ export const WBXML_DEFAULT_MAX_ELEMENTS = 50000;
17
+ /** Default cap on the number of direct children of any single element. */
18
+ export const WBXML_DEFAULT_MAX_CHILDREN_PER_ELEMENT = 10000;
19
+ /** Default cap on element nesting depth (the root is depth 1). Nesting costs ~2 wire bytes per level and drives
20
+ * the decoder's recursion, so it needs its own bound; real EAS documents stay well under 20 levels. */
21
+ export const WBXML_DEFAULT_MAX_DEPTH = 64;
22
+ /** Thrown by `WbxmlDecoder.decode()` for malformed or unsupported input (truncated buffer, unterminated string,
23
+ * attribute-flagged tag, a length field running past the end of the buffer, ...). */
24
+ export class WbxmlDecodeError extends Error {
25
+ constructor(message) {
26
+ super(message);
27
+ this.name = "WbxmlDecodeError";
28
+ }
29
+ }
30
+ /** Thrown by `WbxmlDecoder.decode()` when a document exceeds a configured resource limit (element count,
31
+ * children per element, or nesting depth). A subclass of `WbxmlDecodeError`, so callers that treat every
32
+ * decoder failure as a bad request can catch just the base class. */
33
+ export class WbxmlLimitError extends WbxmlDecodeError {
34
+ constructor(message) {
35
+ super(message);
36
+ this.name = "WbxmlLimitError";
37
+ }
38
+ }
39
+ function positiveIntOption(name, value, fallback) {
40
+ if (value === undefined) {
41
+ return fallback;
42
+ }
43
+ if (!Number.isInteger(value) || value <= 0) {
44
+ throw new RangeError(`WbxmlDecoder: option ${name} must be a positive integer, got ${value}`);
45
+ }
46
+ return value;
47
+ }
21
48
  /**
22
49
  * Decodes a WBXML byte stream (an EAS request/response body) back into a `WbxmlElement` tree — the exact
23
50
  * inverse of `WbxmlEncoder`. Reads the fixed EAS document header, skips its (always-empty, in real
24
51
  * ActiveSync traffic) string table, then parses the single root element.
25
52
  *
53
+ * Input is untrusted, so decoding is bounded: total elements, children per element and nesting depth are
54
+ * capped (see `WbxmlDecoderOptions`), throwing `WbxmlLimitError` when exceeded; all other malformed input throws
55
+ * `WbxmlDecodeError`. Text and opaque payloads are bounded by the input buffer itself.
56
+ *
26
57
  * The `publicid` header field is read via the same generic `mb_u_int32` reader used everywhere else, which is
27
58
  * only a partial implementation of the full WBXML spec for that field (a raw leading `0x00` byte would
28
59
  * signal "public identifier is a string-table reference" under the full spec, a form real ActiveSync traffic
@@ -32,38 +63,55 @@ const MAX_NESTING_DEPTH = 200;
32
63
  * @author Jean-Philippe Steinmetz
33
64
  */
34
65
  export class WbxmlDecoder {
35
- constructor() {
66
+ constructor(options = {}) {
36
67
  this.buf = Buffer.alloc(0);
37
68
  this.pos = 0;
38
69
  this.currentPage = 0;
39
70
  this.depth = 0;
71
+ this.elementCount = 0;
72
+ this.maxElements = positiveIntOption("maxElements", options.maxElements, WBXML_DEFAULT_MAX_ELEMENTS);
73
+ this.maxChildrenPerElement = positiveIntOption("maxChildrenPerElement", options.maxChildrenPerElement, WBXML_DEFAULT_MAX_CHILDREN_PER_ELEMENT);
74
+ this.maxDepth = positiveIntOption("maxDepth", options.maxDepth, WBXML_DEFAULT_MAX_DEPTH);
40
75
  }
41
76
  decode(data) {
42
77
  this.buf = data;
43
78
  this.pos = 0;
44
79
  this.currentPage = 0;
45
80
  this.depth = 0;
46
- this.readByte(); // version - not validated; every ActiveSync client/server variant this library
47
- // targets sends 0x03 (WBXML 1.3), but nothing here depends on that specific value.
48
- this.readMbUint(); // publicid
49
- this.readMbUint(); // charset
50
- const stringTableLength = this.readMbUint();
51
- this.pos += stringTableLength; // skip the (always empty, for ActiveSync) string table
52
- // A leading SWITCH_PAGE before the root tag is legal (and common - e.g. a `Provision` document's
53
- // root element lives on code page 14, not the page-0 `AirSync` default) and is not itself part of
54
- // any element's content, so it's consumed here rather than inside `readTagElement()`.
55
- while (this.pos < this.buf.length && this.buf[this.pos] === SWITCH_PAGE) {
56
- this.pos++;
57
- this.currentPage = this.readByte();
81
+ this.elementCount = 0;
82
+ try {
83
+ this.readByte(); // version - not validated; every ActiveSync client/server variant this library
84
+ // targets sends 0x03 (WBXML 1.3), but nothing here depends on that specific value.
85
+ this.readMbUint(); // publicid
86
+ this.readMbUint(); // charset
87
+ const stringTableLength = this.readMbUint();
88
+ this.requireAvailable(stringTableLength, "string table");
89
+ this.pos += stringTableLength; // skip the (always empty, for ActiveSync) string table
90
+ // A leading SWITCH_PAGE before the root tag is legal (and common - e.g. a `Provision` document's
91
+ // root element lives on code page 14, not the page-0 `AirSync` default) and is not itself part of
92
+ // any element's content, so it's consumed here rather than inside `readTagElement()`.
93
+ while (this.pos < this.buf.length && this.buf[this.pos] === SWITCH_PAGE) {
94
+ this.pos++;
95
+ this.currentPage = this.readByte();
96
+ }
97
+ return this.readTagElement();
98
+ }
99
+ finally {
100
+ this.buf = Buffer.alloc(0); // don't retain the caller's (possibly large) request body
58
101
  }
59
- return this.readTagElement();
60
102
  }
61
103
  readByte() {
62
104
  if (this.pos >= this.buf.length) {
63
- throw new Error("WbxmlDecoder: unexpected end of buffer");
105
+ throw new WbxmlDecodeError("WbxmlDecoder: unexpected end of buffer");
64
106
  }
65
107
  return this.buf[this.pos++];
66
108
  }
109
+ /** Throws unless at least `length` bytes remain from the current position. */
110
+ requireAvailable(length, what) {
111
+ if (length > this.buf.length - this.pos) {
112
+ throw new WbxmlDecodeError(`WbxmlDecoder: ${what} length ${length} runs past the end of the buffer (${this.buf.length - this.pos} bytes remain)`);
113
+ }
114
+ }
67
115
  /** Decodes a WBXML `mb_u_int32`: base-128 digits, most significant group first, every byte but the last
68
116
  * carrying the 0x80 continuation bit. Mirrors `WbxmlEncoder.writeMbUint()`. */
69
117
  readMbUint() {
@@ -78,24 +126,24 @@ export class WbxmlDecoder {
78
126
  }
79
127
  readCString() {
80
128
  const start = this.pos;
81
- while (this.pos < this.buf.length && this.buf[this.pos] !== 0x00) {
82
- this.pos++;
83
- }
84
- if (this.pos >= this.buf.length) {
85
- throw new Error("WbxmlDecoder: unterminated inline string (STR_I)");
129
+ const end = this.buf.indexOf(0x00, start);
130
+ if (end < 0) {
131
+ throw new WbxmlDecodeError("WbxmlDecoder: unterminated inline string (STR_I)");
86
132
  }
87
- const value = this.buf.toString("utf-8", start, this.pos);
88
- this.pos++; // skip the null terminator
89
- return value;
133
+ this.pos = end + 1; // skip the null terminator
134
+ return this.buf.toString("utf-8", start, end);
90
135
  }
91
136
  readTagElement() {
92
- if (++this.depth > MAX_NESTING_DEPTH) {
93
- throw new Error(`WbxmlDecoder: exceeded maximum nesting depth of ${MAX_NESTING_DEPTH}`);
137
+ if (++this.elementCount > this.maxElements) {
138
+ throw new WbxmlLimitError(`WbxmlDecoder: exceeded maximum element count of ${this.maxElements}`);
139
+ }
140
+ if (++this.depth > this.maxDepth) {
141
+ throw new WbxmlLimitError(`WbxmlDecoder: exceeded maximum nesting depth of ${this.maxDepth}`);
94
142
  }
95
143
  try {
96
144
  const byte = this.readByte();
97
145
  if ((byte & ATTR_FLAG) !== 0) {
98
- throw new Error("WbxmlDecoder: attributes are not supported (ActiveSync's WBXML profile never uses them)");
146
+ throw new WbxmlDecodeError("WbxmlDecoder: attributes are not supported (ActiveSync's WBXML profile never uses them)");
99
147
  }
100
148
  const page = this.currentPage;
101
149
  const tag = tagNameForCode(page, byte & TAG_CODE_MASK);
@@ -120,7 +168,7 @@ export class WbxmlDecoder {
120
168
  let opaque;
121
169
  for (;;) {
122
170
  if (this.pos >= this.buf.length) {
123
- throw new Error("WbxmlDecoder: unexpected end of buffer while reading element content");
171
+ throw new WbxmlDecodeError("WbxmlDecoder: unexpected end of buffer while reading element content");
124
172
  }
125
173
  const token = this.buf[this.pos];
126
174
  if (token === END) {
@@ -141,10 +189,14 @@ export class WbxmlDecoder {
141
189
  else if (token === OPAQUE) {
142
190
  this.pos++;
143
191
  const length = this.readMbUint();
192
+ this.requireAvailable(length, "OPAQUE");
144
193
  opaque = Buffer.from(this.buf.subarray(this.pos, this.pos + length));
145
194
  this.pos += length;
146
195
  }
147
196
  else {
197
+ if (children.length >= this.maxChildrenPerElement) {
198
+ throw new WbxmlLimitError(`WbxmlDecoder: exceeded maximum of ${this.maxChildrenPerElement} children per element`);
199
+ }
148
200
  children.push(this.readTagElement());
149
201
  }
150
202
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WbxmlDecoder.js","sourceRoot":"","sources":["../../../src/codec/WbxmlDecoder.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,6FAA6F;AAC7F,MAAM,WAAW,GAAG,IAAI,CAAC;AACzB,MAAM,GAAG,GAAG,IAAI,CAAC;AACjB,MAAM,KAAK,GAAG,IAAI,CAAC;AACnB,MAAM,MAAM,GAAG,IAAI,CAAC;AACpB,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,SAAS,GAAG,IAAI,CAAC;AACvB,MAAM,aAAa,GAAG,IAAI,CAAC;AAE3B;;;;;8EAK8E;AAC9E,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,YAAY;IAAzB;QACY,QAAG,GAAW,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9B,QAAG,GAAG,CAAC,CAAC;QACR,gBAAW,GAAG,CAAC,CAAC;QAChB,UAAK,GAAG,CAAC,CAAC;IAuHtB,CAAC;IArHU,MAAM,CAAC,IAAY;QACtB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;QAChB,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QACb,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QAEf,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,+EAA+E;QAChG,mFAAmF;QACnF,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,WAAW;QAC9B,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU;QAC7B,MAAM,iBAAiB,GAAW,IAAI,CAAC,UAAU,EAAE,CAAC;QACpD,IAAI,CAAC,GAAG,IAAI,iBAAiB,CAAC,CAAC,uDAAuD;QAEtF,iGAAiG;QACjG,kGAAkG;QAClG,sFAAsF;QACtF,OAAO,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,WAAW,EAAE,CAAC;YACtE,IAAI,CAAC,GAAG,EAAE,CAAC;YACX,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QACvC,CAAC;QAED,OAAO,IAAI,CAAC,cAAc,EAAE,CAAC;IACjC,CAAC;IAEO,QAAQ;QACZ,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAChC,CAAC;IAED;mFAC+E;IACvE,UAAU;QACd,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,SAAS,CAAC;YACN,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC7B,KAAK,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,KAAK,CAAC;YACjB,CAAC;QACL,CAAC;IACL,CAAC;IAEO,WAAW;QACf,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC;QACvB,OAAO,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;YAC/D,IAAI,CAAC,GAAG,EAAE,CAAC;QACf,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACxE,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1D,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,2BAA2B;QACvC,OAAO,KAAK,CAAC;IACjB,CAAC;IAEO,cAAc;QAClB,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,iBAAiB,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,mDAAmD,iBAAiB,EAAE,CAAC,CAAC;QAC5F,CAAC;QACD,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC7B,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,yFAAyF,CAAC,CAAC;YAC/G,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;YAC9B,MAAM,GAAG,GAAG,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,aAAa,CAAC,CAAC;YACvD,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;YACvC,CAAC;YACD,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC9D,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QACjD,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC;IACL,CAAC;IAED;;;;4CAIwC;IAChC,mBAAmB;QACvB,MAAM,QAAQ,GAAmB,EAAE,CAAC;QACpC,IAAI,IAAwB,CAAC;QAC7B,IAAI,MAA0B,CAAC;QAE/B,SAAS,CAAC;YACN,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAC;YAC5F,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;gBAChB,IAAI,CAAC,GAAG,EAAE,CAAC;gBACX,MAAM;YACV,CAAC;iBAAM,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;gBAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACX,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACvC,CAAC;iBAAM,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,GAAG,EAAE,CAAC;gBACX,4FAA4F;gBAC5F,2FAA2F;gBAC3F,uFAAuF;gBACvF,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAC7C,CAAC;iBAAM,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;gBAC1B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACX,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;gBACjC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC;gBACrE,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACJ,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;YACzC,CAAC;QACL,CAAC;QAED,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACtC,CAAC;CACJ"}
1
+ {"version":3,"file":"WbxmlDecoder.js","sourceRoot":"","sources":["../../../src/codec/WbxmlDecoder.ts"],"names":[],"mappings":"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"}
@@ -9,40 +9,120 @@ const SWITCH_PAGE = 0x00;
9
9
  const END = 0x01;
10
10
  const STR_I = 0x03;
11
11
  const OPAQUE = 0xc3;
12
+ /** U+0000, the character whose UTF-8 encoding is the `STR_I` terminator byte. */
13
+ const NUL = String.fromCharCode(0);
12
14
  /** Bit flags folded into a tag token byte alongside its 6-bit code (MS-ASWBXML §2.1.2.2 "Tag Format"). Only
13
15
  * `CONTENT_FLAG` is ever set by this encoder - ActiveSync's WBXML profile never uses attributes. */
14
16
  const CONTENT_FLAG = 0x40;
17
+ /** Token bytes are buffered in a small scratch array and flushed into a `Buffer` chunk once it reaches this
18
+ * many bytes (or before a text/opaque payload is appended as its own chunk). */
19
+ export const WBXML_ENCODER_SCRATCH_SIZE = 4096;
20
+ /** Thrown by `WbxmlEncoder.encode()` when the encoded document would exceed the configured `maxBytes`. */
21
+ export class WbxmlSizeLimitError extends Error {
22
+ constructor(maxBytes) {
23
+ super(`WbxmlEncoder: encoded document exceeds the maximum size of ${maxBytes} bytes`);
24
+ this.name = "WbxmlSizeLimitError";
25
+ this.maxBytes = maxBytes;
26
+ }
27
+ }
28
+ /** Returns the number of bytes an `mb_u_int32` encoding of `value` occupies. */
29
+ function mbUintSize(value) {
30
+ let size = 1;
31
+ while (value >= 128) {
32
+ value = Math.floor(value / 128);
33
+ size++;
34
+ }
35
+ return size;
36
+ }
37
+ /** Returns the exact wire size of an `OPAQUE` token carrying `payloadLength` bytes (token + length + payload),
38
+ * so callers can check a large payload against a size budget before building the element. */
39
+ export function wbxmlOpaqueSize(payloadLength) {
40
+ return 1 + mbUintSize(payloadLength) + payloadLength;
41
+ }
15
42
  /**
16
43
  * Encodes a `WbxmlElement` tree into a WBXML byte stream, per MS-ASWBXML's encoding algorithm. Emits the
17
44
  * fixed EAS document header (`version=1.3, publicid=unknown, charset=UTF-8, empty string table`) followed by
18
45
  * the token stream for the given root element, switching code pages only when the page actually changes from
19
46
  * whatever was last active (starting from `AirSync`, page 0, the implicit default per spec).
20
47
  *
48
+ * Output is accumulated as a list of `Buffer` chunks (token bytes batched in a small scratch array, text/opaque
49
+ * payloads appended whole) and joined once at the end, so large payloads are never copied byte-by-byte. An
50
+ * optional `maxBytes` bounds the output size, throwing `WbxmlSizeLimitError` as soon as it would be exceeded.
51
+ *
21
52
  * @author Jean-Philippe Steinmetz
22
53
  */
23
54
  export class WbxmlEncoder {
24
- constructor() {
25
- this.bytes = [];
55
+ constructor(options = {}) {
56
+ this.chunks = [];
57
+ this.scratch = [];
58
+ this.size = 0;
26
59
  this.currentPage = 0;
60
+ const maxBytes = options.maxBytes ?? Infinity;
61
+ if (maxBytes !== Infinity && !(Number.isInteger(maxBytes) && maxBytes > 0)) {
62
+ throw new RangeError(`WbxmlEncoder: option maxBytes must be a positive integer or Infinity, got ${maxBytes}`);
63
+ }
64
+ this.maxBytes = maxBytes;
27
65
  }
28
66
  encode(root) {
29
- // version=0x03 (WBXML 1.3, what real ActiveSync traffic uses despite MS-ASWBXML referencing 1.2),
30
- // publicid=0x01 (mb_u_int32 value 1: "unknown or missing" - the only form ActiveSync ever sends),
31
- // charset=0x6A (IANA MIBenum 106: UTF-8), string table length=0x00 (ActiveSync never uses one -
32
- // inline STR_I tokens carry every string literal instead).
33
- this.bytes = [0x03, 0x01, 0x6a, 0x00];
67
+ this.chunks = [];
68
+ this.scratch = [];
69
+ this.size = 0;
34
70
  this.currentPage = 0;
35
- this.writeElement(root);
36
- return Buffer.from(this.bytes);
71
+ try {
72
+ // version=0x03 (WBXML 1.3, what real ActiveSync traffic uses despite MS-ASWBXML referencing 1.2),
73
+ // publicid=0x01 (mb_u_int32 value 1: "unknown or missing" - the only form ActiveSync ever sends),
74
+ // charset=0x6A (IANA MIBenum 106: UTF-8), string table length=0x00 (ActiveSync never uses one -
75
+ // inline STR_I tokens carry every string literal instead).
76
+ this.writeByte(0x03);
77
+ this.writeByte(0x01);
78
+ this.writeByte(0x6a);
79
+ this.writeByte(0x00);
80
+ this.writeElement(root);
81
+ this.flush();
82
+ return Buffer.concat(this.chunks, this.size);
83
+ }
84
+ finally {
85
+ // Don't retain references to the caller's payload buffers between calls.
86
+ this.chunks = [];
87
+ this.scratch = [];
88
+ }
89
+ }
90
+ /** Accounts for `length` more output bytes, throwing before anything is appended if that would exceed
91
+ * `maxBytes`. */
92
+ reserve(length) {
93
+ if (this.size + length > this.maxBytes) {
94
+ throw new WbxmlSizeLimitError(this.maxBytes);
95
+ }
96
+ this.size += length;
97
+ }
98
+ writeByte(byte) {
99
+ this.reserve(1);
100
+ this.scratch.push(byte);
101
+ if (this.scratch.length >= WBXML_ENCODER_SCRATCH_SIZE) {
102
+ this.flush();
103
+ }
104
+ }
105
+ /** Appends a payload as its own chunk, after flushing any pending token bytes to preserve ordering. */
106
+ writeBuffer(data) {
107
+ this.reserve(data.length);
108
+ this.flush();
109
+ this.chunks.push(data);
110
+ }
111
+ flush() {
112
+ if (this.scratch.length > 0) {
113
+ this.chunks.push(Buffer.from(this.scratch));
114
+ this.scratch = [];
115
+ }
37
116
  }
38
117
  writeElement(el) {
39
118
  if (el.page !== this.currentPage) {
40
- this.bytes.push(SWITCH_PAGE, el.page);
119
+ this.writeByte(SWITCH_PAGE);
120
+ this.writeByte(el.page);
41
121
  this.currentPage = el.page;
42
122
  }
43
123
  const code = codeForTagName(el.page, el.tag);
44
124
  const hasContent = el.children.length > 0 || el.text !== undefined || el.opaque !== undefined;
45
- this.bytes.push(hasContent ? code | CONTENT_FLAG : code);
125
+ this.writeByte(hasContent ? code | CONTENT_FLAG : code);
46
126
  if (!hasContent) {
47
127
  return;
48
128
  }
@@ -57,21 +137,20 @@ export class WbxmlEncoder {
57
137
  this.writeElement(child);
58
138
  }
59
139
  }
60
- this.bytes.push(END);
140
+ this.writeByte(END);
61
141
  }
142
+ /** A NUL byte terminates a WBXML inline string, so any U+0000 in `text` (e.g. a label name or subject
143
+ * controlled by another user) would end the string early and let the remaining bytes be parsed as tokens.
144
+ * UTF-8 never produces a 0x00 byte for any other code point, so stripping U+0000 is sufficient. */
62
145
  writeStrI(text) {
63
- this.bytes.push(STR_I);
64
- for (const byte of Buffer.from(text, "utf-8")) {
65
- this.bytes.push(byte);
66
- }
67
- this.bytes.push(0x00);
146
+ this.writeByte(STR_I);
147
+ this.writeBuffer(Buffer.from(text.split(NUL).join(""), "utf-8"));
148
+ this.writeByte(0x00);
68
149
  }
69
150
  writeOpaque(data) {
70
- this.bytes.push(OPAQUE);
151
+ this.writeByte(OPAQUE);
71
152
  this.writeMbUint(data.length);
72
- for (const byte of data) {
73
- this.bytes.push(byte);
74
- }
153
+ this.writeBuffer(data);
75
154
  }
76
155
  /** Encodes `value` as a WBXML multi-byte unsigned integer (`mb_u_int32`): base-128 digits, most
77
156
  * significant group first, every byte but the last carrying the 0x80 continuation bit. */
@@ -82,7 +161,9 @@ export class WbxmlEncoder {
82
161
  groups.unshift((value & 0x7f) | 0x80);
83
162
  value = Math.floor(value / 128);
84
163
  }
85
- this.bytes.push(...groups);
164
+ for (const group of groups) {
165
+ this.writeByte(group);
166
+ }
86
167
  }
87
168
  }
88
169
  //# sourceMappingURL=WbxmlEncoder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WbxmlEncoder.js","sourceRoot":"","sources":["../../../src/codec/WbxmlEncoder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WbxmlEncoder.js","sourceRoot":"","sources":["../../../src/codec/WbxmlEncoder.ts"],"names":[],"mappings":"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"}