@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.
- package/README.md +4 -4
- package/dist/lib/BaseDeviceSyncStateRoute.js +32 -0
- package/dist/lib/BaseDeviceSyncStateRoute.js.map +1 -1
- package/dist/lib/BaseEasRoute.js +91 -15
- package/dist/lib/BaseEasRoute.js.map +1 -1
- package/dist/lib/EasAuditLog.js +56 -0
- package/dist/lib/EasAuditLog.js.map +1 -0
- package/dist/lib/EasCollectionLease.js +199 -0
- package/dist/lib/EasCollectionLease.js.map +1 -0
- package/dist/lib/EasCollectionStore.js +102 -0
- package/dist/lib/EasCollectionStore.js.map +1 -0
- package/dist/lib/EasCollectionSync.js +294 -0
- package/dist/lib/EasCollectionSync.js.map +1 -0
- package/dist/lib/EasSyncKeyUtils.js +125 -62
- package/dist/lib/EasSyncKeyUtils.js.map +1 -1
- package/dist/lib/MessageMoveRules.js +100 -0
- package/dist/lib/MessageMoveRules.js.map +1 -0
- package/dist/lib/MimeHeaderUtils.js +395 -0
- package/dist/lib/MimeHeaderUtils.js.map +1 -0
- package/dist/lib/RegexPatternUtils.js +30 -0
- package/dist/lib/RegexPatternUtils.js.map +1 -0
- package/dist/lib/RestapiCompat.js +41 -0
- package/dist/lib/RestapiCompat.js.map +1 -0
- package/dist/lib/adapters/CalendarSyncAdapter.js +142 -33
- package/dist/lib/adapters/CalendarSyncAdapter.js.map +1 -1
- package/dist/lib/adapters/EmailSyncAdapter.js +114 -27
- package/dist/lib/adapters/EmailSyncAdapter.js.map +1 -1
- package/dist/lib/adapters/mongo/EmailSyncAdapterMongo.js +2 -1
- package/dist/lib/adapters/mongo/EmailSyncAdapterMongo.js.map +1 -1
- package/dist/lib/adapters/sql/EmailSyncAdapterSQL.js +2 -1
- package/dist/lib/adapters/sql/EmailSyncAdapterSQL.js.map +1 -1
- package/dist/lib/codec/WbxmlDecoder.js +86 -34
- package/dist/lib/codec/WbxmlDecoder.js.map +1 -1
- package/dist/lib/codec/WbxmlEncoder.js +103 -22
- package/dist/lib/codec/WbxmlEncoder.js.map +1 -1
- package/dist/lib/commands/ComposeMailCommand.js +105 -31
- package/dist/lib/commands/ComposeMailCommand.js.map +1 -1
- package/dist/lib/commands/FolderSyncCommand.js +67 -27
- package/dist/lib/commands/FolderSyncCommand.js.map +1 -1
- package/dist/lib/commands/GetItemEstimateCommand.js +80 -59
- package/dist/lib/commands/GetItemEstimateCommand.js.map +1 -1
- package/dist/lib/commands/ItemOperationsCommand.js +219 -56
- package/dist/lib/commands/ItemOperationsCommand.js.map +1 -1
- package/dist/lib/commands/MeetingResponseCommand.js +212 -53
- package/dist/lib/commands/MeetingResponseCommand.js.map +1 -1
- package/dist/lib/commands/MoveItemsCommand.js +54 -21
- package/dist/lib/commands/MoveItemsCommand.js.map +1 -1
- package/dist/lib/commands/PingCommand.js +288 -56
- package/dist/lib/commands/PingCommand.js.map +1 -1
- package/dist/lib/commands/ProvisionCommand.js +34 -17
- package/dist/lib/commands/ProvisionCommand.js.map +1 -1
- package/dist/lib/commands/ResolveRecipientsCommand.js +43 -5
- package/dist/lib/commands/ResolveRecipientsCommand.js.map +1 -1
- package/dist/lib/commands/SearchCommand.js +92 -17
- package/dist/lib/commands/SearchCommand.js.map +1 -1
- package/dist/lib/commands/SettingsCommand.js +2 -1
- package/dist/lib/commands/SettingsCommand.js.map +1 -1
- package/dist/lib/commands/SmartForwardCommand.js +2 -1
- package/dist/lib/commands/SmartForwardCommand.js.map +1 -1
- package/dist/lib/commands/SmartReplyCommand.js +2 -1
- package/dist/lib/commands/SmartReplyCommand.js.map +1 -1
- package/dist/lib/commands/SyncCommand.js +481 -244
- package/dist/lib/commands/SyncCommand.js.map +1 -1
- package/dist/lib/commands/mongo/GetItemEstimateCommandMongo.js +6 -1
- package/dist/lib/commands/mongo/GetItemEstimateCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/ItemOperationsCommandMongo.js +3 -1
- package/dist/lib/commands/mongo/ItemOperationsCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/MeetingResponseCommandMongo.js +2 -1
- package/dist/lib/commands/mongo/MeetingResponseCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/PingCommandMongo.js +23 -0
- package/dist/lib/commands/mongo/PingCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/SearchCommandMongo.js +3 -1
- package/dist/lib/commands/mongo/SearchCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/SendMailCommandMongo.js +2 -1
- package/dist/lib/commands/mongo/SendMailCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/SmartForwardCommandMongo.js +2 -1
- package/dist/lib/commands/mongo/SmartForwardCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/SmartReplyCommandMongo.js +2 -1
- package/dist/lib/commands/mongo/SmartReplyCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/SyncCommandMongo.js +7 -1
- package/dist/lib/commands/mongo/SyncCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/index.js +1 -0
- package/dist/lib/commands/mongo/index.js.map +1 -1
- package/dist/lib/commands/sql/GetItemEstimateCommandSQL.js +6 -1
- package/dist/lib/commands/sql/GetItemEstimateCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/ItemOperationsCommandSQL.js +3 -1
- package/dist/lib/commands/sql/ItemOperationsCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/MeetingResponseCommandSQL.js +2 -1
- package/dist/lib/commands/sql/MeetingResponseCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/PingCommandSQL.js +23 -0
- package/dist/lib/commands/sql/PingCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/SearchCommandSQL.js +3 -1
- package/dist/lib/commands/sql/SearchCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/SendMailCommandSQL.js +2 -1
- package/dist/lib/commands/sql/SendMailCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/SmartForwardCommandSQL.js +2 -1
- package/dist/lib/commands/sql/SmartForwardCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/SmartReplyCommandSQL.js +2 -1
- package/dist/lib/commands/sql/SmartReplyCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/SyncCommandSQL.js +7 -1
- package/dist/lib/commands/sql/SyncCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/index.js +1 -0
- package/dist/lib/commands/sql/index.js.map +1 -1
- package/dist/lib/index.js +5 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/jobs/EasDeviceStateCleanupJob.js +44 -2
- package/dist/lib/jobs/EasDeviceStateCleanupJob.js.map +1 -1
- package/dist/lib/jobs/mongo/EasDeviceStateCleanupJobMongo.js +4 -0
- package/dist/lib/jobs/mongo/EasDeviceStateCleanupJobMongo.js.map +1 -1
- package/dist/lib/jobs/sql/EasDeviceStateCleanupJobSQL.js +9 -0
- package/dist/lib/jobs/sql/EasDeviceStateCleanupJobSQL.js.map +1 -1
- package/dist/lib/models/EasCollectionChunk.js +2 -0
- package/dist/lib/models/EasCollectionChunk.js.map +1 -0
- package/dist/lib/models/EasCollectionState.js +2 -0
- package/dist/lib/models/EasCollectionState.js.map +1 -0
- package/dist/lib/models/mongo/DeviceSyncStateMongo.js +7 -0
- package/dist/lib/models/mongo/DeviceSyncStateMongo.js.map +1 -1
- package/dist/lib/models/mongo/EasCollectionChunkMongo.js +83 -0
- package/dist/lib/models/mongo/EasCollectionChunkMongo.js.map +1 -0
- package/dist/lib/models/mongo/EasCollectionStateMongo.js +162 -0
- package/dist/lib/models/mongo/EasCollectionStateMongo.js.map +1 -0
- package/dist/lib/models/sql/DeviceSyncStateSQL.js +7 -0
- package/dist/lib/models/sql/DeviceSyncStateSQL.js.map +1 -1
- package/dist/lib/models/sql/EasCollectionChunkSQL.js +83 -0
- package/dist/lib/models/sql/EasCollectionChunkSQL.js.map +1 -0
- package/dist/lib/models/sql/EasCollectionStateSQL.js +162 -0
- package/dist/lib/models/sql/EasCollectionStateSQL.js.map +1 -0
- package/dist/lib/mongo/EasRouteMongo.js +2 -2
- package/dist/lib/mongo/EasRouteMongo.js.map +1 -1
- package/dist/lib/mongo.js +2 -0
- package/dist/lib/mongo.js.map +1 -1
- package/dist/lib/sql/EasRouteSQL.js +2 -2
- package/dist/lib/sql/EasRouteSQL.js.map +1 -1
- package/dist/lib/sql.js +2 -0
- package/dist/lib/sql.js.map +1 -1
- package/dist/types/BaseDeviceSyncStateRoute.d.ts +10 -0
- package/dist/types/BaseEasRoute.d.ts +15 -4
- package/dist/types/EasAuditLog.d.ts +47 -0
- package/dist/types/EasCollectionLease.d.ts +60 -0
- package/dist/types/EasCollectionStore.d.ts +51 -0
- package/dist/types/EasCollectionSync.d.ts +96 -0
- package/dist/types/EasCommandHandler.d.ts +7 -4
- package/dist/types/EasSyncKeyUtils.d.ts +73 -42
- package/dist/types/MessageMoveRules.d.ts +45 -0
- package/dist/types/MimeHeaderUtils.d.ts +73 -0
- package/dist/types/RegexPatternUtils.d.ts +14 -0
- package/dist/types/RestapiCompat.d.ts +24 -0
- package/dist/types/adapters/CalendarSyncAdapter.d.ts +47 -18
- package/dist/types/adapters/EasCollectionSyncAdapter.d.ts +18 -2
- package/dist/types/adapters/EmailSyncAdapter.d.ts +24 -7
- package/dist/types/adapters/mongo/EmailSyncAdapterMongo.d.ts +1 -0
- package/dist/types/adapters/sql/EmailSyncAdapterSQL.d.ts +1 -0
- package/dist/types/codec/WbxmlDecoder.d.ts +39 -0
- package/dist/types/codec/WbxmlEncoder.d.ts +36 -1
- package/dist/types/commands/ComposeMailCommand.d.ts +33 -15
- package/dist/types/commands/FolderSyncCommand.d.ts +4 -1
- package/dist/types/commands/GetItemEstimateCommand.d.ts +20 -15
- package/dist/types/commands/ItemOperationsCommand.d.ts +29 -4
- package/dist/types/commands/MeetingResponseCommand.d.ts +52 -13
- package/dist/types/commands/MoveItemsCommand.d.ts +13 -3
- package/dist/types/commands/PingCommand.d.ts +72 -14
- package/dist/types/commands/ProvisionCommand.d.ts +16 -11
- package/dist/types/commands/ResolveRecipientsCommand.d.ts +4 -0
- package/dist/types/commands/SearchCommand.d.ts +13 -1
- package/dist/types/commands/SyncCommand.d.ts +102 -62
- package/dist/types/commands/mongo/GetItemEstimateCommandMongo.d.ts +3 -0
- package/dist/types/commands/mongo/ItemOperationsCommandMongo.d.ts +2 -0
- package/dist/types/commands/mongo/MeetingResponseCommandMongo.d.ts +1 -0
- package/dist/types/commands/mongo/PingCommandMongo.d.ts +8 -0
- package/dist/types/commands/mongo/SearchCommandMongo.d.ts +2 -0
- package/dist/types/commands/mongo/SendMailCommandMongo.d.ts +1 -0
- package/dist/types/commands/mongo/SmartForwardCommandMongo.d.ts +1 -0
- package/dist/types/commands/mongo/SmartReplyCommandMongo.d.ts +1 -0
- package/dist/types/commands/mongo/SyncCommandMongo.d.ts +4 -0
- package/dist/types/commands/mongo/index.d.ts +1 -0
- package/dist/types/commands/sql/GetItemEstimateCommandSQL.d.ts +3 -0
- package/dist/types/commands/sql/ItemOperationsCommandSQL.d.ts +2 -0
- package/dist/types/commands/sql/MeetingResponseCommandSQL.d.ts +1 -0
- package/dist/types/commands/sql/PingCommandSQL.d.ts +8 -0
- package/dist/types/commands/sql/SearchCommandSQL.d.ts +2 -0
- package/dist/types/commands/sql/SendMailCommandSQL.d.ts +1 -0
- package/dist/types/commands/sql/SmartForwardCommandSQL.d.ts +1 -0
- package/dist/types/commands/sql/SmartReplyCommandSQL.d.ts +1 -0
- package/dist/types/commands/sql/SyncCommandSQL.d.ts +4 -0
- package/dist/types/commands/sql/index.d.ts +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/jobs/EasDeviceStateCleanupJob.d.ts +15 -0
- package/dist/types/jobs/mongo/EasDeviceStateCleanupJobMongo.d.ts +2 -0
- package/dist/types/jobs/sql/EasDeviceStateCleanupJobSQL.d.ts +4 -0
- package/dist/types/models/DeviceSyncState.d.ts +13 -2
- package/dist/types/models/EasCollectionChunk.d.ts +20 -0
- package/dist/types/models/EasCollectionState.d.ts +79 -0
- package/dist/types/models/mongo/DeviceSyncStateMongo.d.ts +1 -0
- package/dist/types/models/mongo/EasCollectionChunkMongo.d.ts +16 -0
- package/dist/types/models/mongo/EasCollectionStateMongo.d.ts +27 -0
- package/dist/types/models/sql/DeviceSyncStateSQL.d.ts +1 -0
- package/dist/types/models/sql/EasCollectionChunkSQL.d.ts +16 -0
- package/dist/types/models/sql/EasCollectionStateSQL.d.ts +27 -0
- package/dist/types/mongo.d.ts +2 -0
- package/dist/types/sql.d.ts +2 -0
- 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;
|
|
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;
|
|
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
|
-
/**
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
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
|
-
|
|
82
|
-
|
|
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
|
-
|
|
88
|
-
this.
|
|
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.
|
|
93
|
-
throw new
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
36
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
64
|
-
|
|
65
|
-
|
|
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.
|
|
151
|
+
this.writeByte(OPAQUE);
|
|
71
152
|
this.writeMbUint(data.length);
|
|
72
|
-
|
|
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
|
-
|
|
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":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,wGAAwG;AACxG,mEAAmE;AACnE,MAAM,WAAW,GAAG,IAAI,CAAC;AACzB,MAAM,GAAG,GAAG,IAAI,CAAC;AACjB,MAAM,KAAK,GAAG,IAAI,CAAC;AACnB,MAAM,MAAM,GAAG,IAAI,CAAC;AAEpB;oGACoG;AACpG,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B
|
|
1
|
+
{"version":3,"file":"WbxmlEncoder.js","sourceRoot":"","sources":["../../../src/codec/WbxmlEncoder.ts"],"names":[],"mappings":"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"}
|