appium-ios-remotexpc 0.0.3 → 0.0.5

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 (213) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/src/base-plist-service.d.ts +51 -0
  3. package/build/src/base-plist-service.d.ts.map +1 -0
  4. package/build/src/base-plist-service.js +61 -0
  5. package/build/src/base-socket-service.d.ts +15 -0
  6. package/build/src/base-socket-service.d.ts.map +1 -0
  7. package/build/src/base-socket-service.js +46 -0
  8. package/build/src/index.d.ts +9 -0
  9. package/build/src/index.d.ts.map +1 -0
  10. package/build/src/index.js +7 -0
  11. package/build/src/lib/apple-tv/constants.d.ts +77 -0
  12. package/build/src/lib/apple-tv/constants.d.ts.map +1 -0
  13. package/build/src/lib/apple-tv/constants.js +106 -0
  14. package/build/src/lib/apple-tv/encryption/chacha20-poly1305.d.ts +22 -0
  15. package/build/src/lib/apple-tv/encryption/chacha20-poly1305.d.ts.map +1 -0
  16. package/build/src/lib/apple-tv/encryption/chacha20-poly1305.js +97 -0
  17. package/build/src/lib/apple-tv/encryption/ed25519.d.ts +16 -0
  18. package/build/src/lib/apple-tv/encryption/ed25519.d.ts.map +1 -0
  19. package/build/src/lib/apple-tv/encryption/ed25519.js +93 -0
  20. package/build/src/lib/apple-tv/encryption/hkdf.d.ts +18 -0
  21. package/build/src/lib/apple-tv/encryption/hkdf.d.ts.map +1 -0
  22. package/build/src/lib/apple-tv/encryption/hkdf.js +73 -0
  23. package/build/src/lib/apple-tv/encryption/index.d.ts +5 -0
  24. package/build/src/lib/apple-tv/encryption/index.d.ts.map +1 -0
  25. package/build/src/lib/apple-tv/encryption/index.js +4 -0
  26. package/build/src/lib/apple-tv/encryption/opack2.d.ts +57 -0
  27. package/build/src/lib/apple-tv/encryption/opack2.d.ts.map +1 -0
  28. package/build/src/lib/apple-tv/encryption/opack2.js +203 -0
  29. package/build/src/lib/apple-tv/errors.d.ts +17 -0
  30. package/build/src/lib/apple-tv/errors.d.ts.map +1 -0
  31. package/build/src/lib/apple-tv/errors.js +30 -0
  32. package/build/src/lib/apple-tv/tlv/decoder.d.ts +19 -0
  33. package/build/src/lib/apple-tv/tlv/decoder.d.ts.map +1 -0
  34. package/build/src/lib/apple-tv/tlv/decoder.js +49 -0
  35. package/build/src/lib/apple-tv/tlv/encoder.d.ts +10 -0
  36. package/build/src/lib/apple-tv/tlv/encoder.d.ts.map +1 -0
  37. package/build/src/lib/apple-tv/tlv/encoder.js +20 -0
  38. package/build/src/lib/apple-tv/tlv/index.d.ts +4 -0
  39. package/build/src/lib/apple-tv/tlv/index.d.ts.map +1 -0
  40. package/build/src/lib/apple-tv/tlv/index.js +3 -0
  41. package/build/src/lib/apple-tv/tlv/pairing-tlv.d.ts +14 -0
  42. package/build/src/lib/apple-tv/tlv/pairing-tlv.d.ts.map +1 -0
  43. package/build/src/lib/apple-tv/tlv/pairing-tlv.js +27 -0
  44. package/build/src/lib/apple-tv/types.d.ts +36 -0
  45. package/build/src/lib/apple-tv/types.d.ts.map +1 -0
  46. package/build/src/lib/apple-tv/types.js +1 -0
  47. package/build/src/lib/apple-tv/utils/buffer-utils.d.ts +40 -0
  48. package/build/src/lib/apple-tv/utils/buffer-utils.d.ts.map +1 -0
  49. package/build/src/lib/apple-tv/utils/buffer-utils.js +76 -0
  50. package/build/src/lib/apple-tv/utils/index.d.ts +3 -0
  51. package/build/src/lib/apple-tv/utils/index.d.ts.map +1 -0
  52. package/build/src/lib/apple-tv/utils/index.js +2 -0
  53. package/build/src/lib/apple-tv/utils/uuid-generator.d.ts +9 -0
  54. package/build/src/lib/apple-tv/utils/uuid-generator.d.ts.map +1 -0
  55. package/build/src/lib/apple-tv/utils/uuid-generator.js +36 -0
  56. package/build/src/lib/lockdown/index.d.ts +87 -0
  57. package/build/src/lib/lockdown/index.d.ts.map +1 -0
  58. package/build/src/lib/lockdown/index.js +324 -0
  59. package/build/src/lib/pair-record/index.d.ts +3 -0
  60. package/build/src/lib/pair-record/index.d.ts.map +1 -0
  61. package/build/src/lib/pair-record/index.js +2 -0
  62. package/build/src/lib/pair-record/pair-record.d.ts +48 -0
  63. package/build/src/lib/pair-record/pair-record.d.ts.map +1 -0
  64. package/build/src/lib/pair-record/pair-record.js +85 -0
  65. package/build/src/lib/plist/binary-plist-creator.d.ts +14 -0
  66. package/build/src/lib/plist/binary-plist-creator.d.ts.map +1 -0
  67. package/build/src/lib/plist/binary-plist-creator.js +475 -0
  68. package/build/src/lib/plist/binary-plist-parser.d.ts +14 -0
  69. package/build/src/lib/plist/binary-plist-parser.d.ts.map +1 -0
  70. package/build/src/lib/plist/binary-plist-parser.js +449 -0
  71. package/build/src/lib/plist/constants.d.ts +36 -0
  72. package/build/src/lib/plist/constants.d.ts.map +1 -0
  73. package/build/src/lib/plist/constants.js +43 -0
  74. package/build/src/lib/plist/index.d.ts +14 -0
  75. package/build/src/lib/plist/index.d.ts.map +1 -0
  76. package/build/src/lib/plist/index.js +16 -0
  77. package/build/src/lib/plist/length-based-splitter.d.ts +43 -0
  78. package/build/src/lib/plist/length-based-splitter.d.ts.map +1 -0
  79. package/build/src/lib/plist/length-based-splitter.js +228 -0
  80. package/build/src/lib/plist/plist-creator.d.ts +8 -0
  81. package/build/src/lib/plist/plist-creator.d.ts.map +1 -0
  82. package/build/src/lib/plist/plist-creator.js +33 -0
  83. package/build/src/lib/plist/plist-decoder.d.ts +25 -0
  84. package/build/src/lib/plist/plist-decoder.d.ts.map +1 -0
  85. package/build/src/lib/plist/plist-decoder.js +103 -0
  86. package/build/src/lib/plist/plist-encoder.d.ts +10 -0
  87. package/build/src/lib/plist/plist-encoder.d.ts.map +1 -0
  88. package/build/src/lib/plist/plist-encoder.js +27 -0
  89. package/build/src/lib/plist/plist-parser.d.ts +9 -0
  90. package/build/src/lib/plist/plist-parser.d.ts.map +1 -0
  91. package/build/src/lib/plist/plist-parser.js +109 -0
  92. package/build/src/lib/plist/plist-service.d.ts +86 -0
  93. package/build/src/lib/plist/plist-service.d.ts.map +1 -0
  94. package/build/src/lib/plist/plist-service.js +180 -0
  95. package/build/src/lib/plist/unified-plist-creator.d.ts +9 -0
  96. package/build/src/lib/plist/unified-plist-creator.d.ts.map +1 -0
  97. package/build/src/lib/plist/unified-plist-creator.js +14 -0
  98. package/build/src/lib/plist/unified-plist-parser.d.ts +8 -0
  99. package/build/src/lib/plist/unified-plist-parser.d.ts.map +1 -0
  100. package/build/src/lib/plist/unified-plist-parser.js +23 -0
  101. package/build/src/lib/plist/utils.d.ts +97 -0
  102. package/build/src/lib/plist/utils.d.ts.map +1 -0
  103. package/build/src/lib/plist/utils.js +287 -0
  104. package/build/src/lib/remote-xpc/constants.d.ts +20 -0
  105. package/build/src/lib/remote-xpc/constants.d.ts.map +1 -0
  106. package/build/src/lib/remote-xpc/constants.js +21 -0
  107. package/build/src/lib/remote-xpc/handshake-frames.d.ts +74 -0
  108. package/build/src/lib/remote-xpc/handshake-frames.d.ts.map +1 -0
  109. package/build/src/lib/remote-xpc/handshake-frames.js +285 -0
  110. package/build/src/lib/remote-xpc/handshake.d.ts +14 -0
  111. package/build/src/lib/remote-xpc/handshake.d.ts.map +1 -0
  112. package/build/src/lib/remote-xpc/handshake.js +95 -0
  113. package/build/src/lib/remote-xpc/remote-xpc-connection.d.ts +55 -0
  114. package/build/src/lib/remote-xpc/remote-xpc-connection.d.ts.map +1 -0
  115. package/build/src/lib/remote-xpc/remote-xpc-connection.js +365 -0
  116. package/build/src/lib/remote-xpc/xpc-protocol.d.ts +22 -0
  117. package/build/src/lib/remote-xpc/xpc-protocol.d.ts.map +1 -0
  118. package/build/src/lib/remote-xpc/xpc-protocol.js +368 -0
  119. package/build/src/lib/tunnel/index.d.ts +69 -0
  120. package/build/src/lib/tunnel/index.d.ts.map +1 -0
  121. package/build/src/lib/tunnel/index.js +205 -0
  122. package/build/src/lib/tunnel/packet-stream-client.d.ts +46 -0
  123. package/build/src/lib/tunnel/packet-stream-client.d.ts.map +1 -0
  124. package/build/src/lib/tunnel/packet-stream-client.js +152 -0
  125. package/build/src/lib/tunnel/packet-stream-server.d.ts +37 -0
  126. package/build/src/lib/tunnel/packet-stream-server.d.ts.map +1 -0
  127. package/build/src/lib/tunnel/packet-stream-server.js +109 -0
  128. package/build/src/lib/tunnel/tunnel-api-client.d.ts +85 -0
  129. package/build/src/lib/tunnel/tunnel-api-client.d.ts.map +1 -0
  130. package/build/src/lib/tunnel/tunnel-api-client.js +207 -0
  131. package/build/src/lib/tunnel/tunnel-registry-server.d.ts +68 -0
  132. package/build/src/lib/tunnel/tunnel-registry-server.d.ts.map +1 -0
  133. package/build/src/lib/tunnel/tunnel-registry-server.js +351 -0
  134. package/build/src/lib/types.d.ts +238 -0
  135. package/build/src/lib/types.d.ts.map +1 -0
  136. package/build/src/lib/types.js +4 -0
  137. package/build/src/lib/usbmux/index.d.ts +177 -0
  138. package/build/src/lib/usbmux/index.d.ts.map +1 -0
  139. package/build/src/lib/usbmux/index.js +490 -0
  140. package/build/src/lib/usbmux/usbmux-decoder.d.ts +19 -0
  141. package/build/src/lib/usbmux/usbmux-decoder.d.ts.map +1 -0
  142. package/build/src/lib/usbmux/usbmux-decoder.js +38 -0
  143. package/build/src/lib/usbmux/usbmux-encoder.d.ts +12 -0
  144. package/build/src/lib/usbmux/usbmux-encoder.d.ts.map +1 -0
  145. package/build/src/lib/usbmux/usbmux-encoder.js +32 -0
  146. package/build/src/service-connection.d.ts +34 -0
  147. package/build/src/service-connection.d.ts.map +1 -0
  148. package/build/src/service-connection.js +51 -0
  149. package/build/src/services/index.d.ts +6 -0
  150. package/build/src/services/index.d.ts.map +1 -0
  151. package/build/src/services/index.js +5 -0
  152. package/build/src/services/ios/base-service.d.ts +35 -0
  153. package/build/src/services/ios/base-service.d.ts.map +1 -0
  154. package/build/src/services/ios/base-service.js +55 -0
  155. package/build/src/services/ios/diagnostic-service/index.d.ts +46 -0
  156. package/build/src/services/ios/diagnostic-service/index.d.ts.map +1 -0
  157. package/build/src/services/ios/diagnostic-service/index.js +169 -0
  158. package/build/src/services/ios/diagnostic-service/keys.d.ts +5 -0
  159. package/build/src/services/ios/diagnostic-service/keys.d.ts.map +1 -0
  160. package/build/src/services/ios/diagnostic-service/keys.js +770 -0
  161. package/build/src/services/ios/syslog-service/index.d.ts +91 -0
  162. package/build/src/services/ios/syslog-service/index.d.ts.map +1 -0
  163. package/build/src/services/ios/syslog-service/index.js +323 -0
  164. package/build/src/services/ios/tunnel-service/index.d.ts +17 -0
  165. package/build/src/services/ios/tunnel-service/index.d.ts.map +1 -0
  166. package/build/src/services/ios/tunnel-service/index.js +57 -0
  167. package/build/src/services.d.ts +14 -0
  168. package/build/src/services.d.ts.map +1 -0
  169. package/build/src/services.js +48 -0
  170. package/package.json +12 -3
  171. package/src/lib/apple-tv/constants.ts +42 -0
  172. package/src/lib/apple-tv/encryption/chacha20-poly1305.ts +147 -0
  173. package/src/lib/apple-tv/encryption/ed25519.ts +126 -0
  174. package/src/lib/apple-tv/encryption/hkdf.ts +95 -0
  175. package/src/lib/apple-tv/encryption/index.ts +11 -0
  176. package/src/lib/apple-tv/encryption/opack2.ts +257 -0
  177. package/.github/dependabot.yml +0 -38
  178. package/.github/workflows/format-check.yml +0 -43
  179. package/.github/workflows/lint-and-build.yml +0 -40
  180. package/.github/workflows/pr-title.yml +0 -16
  181. package/.github/workflows/publish.js.yml +0 -43
  182. package/.github/workflows/test-validation.yml +0 -40
  183. package/.mocharc.json +0 -8
  184. package/.prettierignore +0 -3
  185. package/.prettierrc +0 -17
  186. package/.releaserc +0 -48
  187. package/assets/images/ios-arch.png +0 -0
  188. package/eslint.config.js +0 -45
  189. package/npm-shrinkwrap.json +0 -2711
  190. package/test/integration/diagnostics-test.ts +0 -44
  191. package/test/integration/read-pair-record-test.ts +0 -39
  192. package/test/integration/tunnel-test.ts +0 -104
  193. package/test/unit/apple-tv/tlv/decoder.spec.ts +0 -144
  194. package/test/unit/apple-tv/tlv/encoder.spec.ts +0 -91
  195. package/test/unit/apple-tv/tlv/pairing-tlv.spec.ts +0 -101
  196. package/test/unit/apple-tv/tlv/tlv-integration.spec.ts +0 -146
  197. package/test/unit/apple-tv/utils/buffer-utils.spec.ts +0 -74
  198. package/test/unit/apple-tv/utils/uuid-generator.spec.ts +0 -39
  199. package/test/unit/fixtures/index.ts +0 -88
  200. package/test/unit/fixtures/usbmuxconnectmessage.bin +0 -0
  201. package/test/unit/fixtures/usbmuxlistdevicemessage.bin +0 -0
  202. package/test/unit/plist/error-handling.spec.ts +0 -101
  203. package/test/unit/plist/fixtures/sample.binary.plist +0 -0
  204. package/test/unit/plist/fixtures/sample.xml.plist +0 -38
  205. package/test/unit/plist/plist-parser.spec.ts +0 -283
  206. package/test/unit/plist/plist.spec.ts +0 -205
  207. package/test/unit/plist/tag-position-handling.spec.ts +0 -90
  208. package/test/unit/plist/unified-plist-parser.spec.ts +0 -227
  209. package/test/unit/plist/utils.spec.ts +0 -249
  210. package/test/unit/plist/xml-cleaning.spec.ts +0 -60
  211. package/test/unit/tunnel/tunnel-registry-server.spec.ts +0 -194
  212. package/test/unit/usbmux/usbmux-specs.ts +0 -71
  213. package/tsconfig.json +0 -36
@@ -0,0 +1,228 @@
1
+ import { logger } from '@appium/support';
2
+ import { Transform } from 'stream';
3
+ import { BINARY_PLIST_HEADER_LENGTH, BINARY_PLIST_MAGIC, IBINARY_PLIST_MAGIC, LENGTH_FIELD_1_BYTE, LENGTH_FIELD_2_BYTES, LENGTH_FIELD_4_BYTES, LENGTH_FIELD_8_BYTES, PLIST_CLOSING_TAG, UINT32_HIGH_MULTIPLIER, UTF8_ENCODING, XML_DECLARATION, } from './constants.js';
4
+ import { isXmlPlistContent } from './utils.js';
5
+ const log = logger.getLogger('Plist');
6
+ // Constants
7
+ const DEFAULT_MAX_FRAME_LENGTH = 100 * 1024 * 1024; // 100MB default for large IORegistry responses
8
+ const DEFAULT_LENGTH_FIELD_OFFSET = 0;
9
+ const DEFAULT_LENGTH_FIELD_LENGTH = 4;
10
+ const DEFAULT_LENGTH_ADJUSTMENT = 0;
11
+ const MAX_PREVIEW_LENGTH = 100; // Maximum number of bytes to preview for content type detection
12
+ /**
13
+ * Splits incoming data into length-prefixed chunks
14
+ */
15
+ export class LengthBasedSplitter extends Transform {
16
+ buffer;
17
+ littleEndian;
18
+ maxFrameLength;
19
+ lengthFieldOffset;
20
+ lengthFieldLength;
21
+ lengthAdjustment;
22
+ isXmlMode = false;
23
+ /**
24
+ * Creates a new LengthBasedSplitter
25
+ * @param options Configuration options
26
+ */
27
+ constructor(options = {}) {
28
+ super();
29
+ this.buffer = Buffer.alloc(0);
30
+ this.littleEndian = options.littleEndian ?? false;
31
+ this.maxFrameLength = options.maxFrameLength ?? DEFAULT_MAX_FRAME_LENGTH;
32
+ this.lengthFieldOffset =
33
+ options.lengthFieldOffset ?? DEFAULT_LENGTH_FIELD_OFFSET;
34
+ this.lengthFieldLength =
35
+ options.lengthFieldLength ?? DEFAULT_LENGTH_FIELD_LENGTH;
36
+ this.lengthAdjustment =
37
+ options.lengthAdjustment ?? DEFAULT_LENGTH_ADJUSTMENT;
38
+ // If readableStream is provided, pipe it to this
39
+ if (options.readableStream) {
40
+ options.readableStream.pipe(this);
41
+ }
42
+ }
43
+ /**
44
+ * Shutdown the splitter and remove all listeners
45
+ */
46
+ shutdown() {
47
+ // Reset internal state
48
+ this.buffer = Buffer.alloc(0);
49
+ this.isXmlMode = false;
50
+ // Remove all listeners
51
+ this.removeAllListeners();
52
+ log.debug('LengthBasedSplitter shutdown complete');
53
+ }
54
+ _transform(chunk, encoding, callback) {
55
+ try {
56
+ // Add the new chunk to our buffer
57
+ this.buffer = Buffer.concat([this.buffer, chunk]);
58
+ // Check if this is XML data or binary plist before doing any other processing
59
+ const bufferString = this.buffer.toString(UTF8_ENCODING, 0, Math.min(MAX_PREVIEW_LENGTH, this.buffer.length));
60
+ // Check for XML format
61
+ if (isXmlPlistContent(bufferString) || this.isXmlMode) {
62
+ // This is XML data, set XML mode
63
+ this.isXmlMode = true;
64
+ this.processXmlData(callback);
65
+ return;
66
+ }
67
+ // Check for binary plist format (bplist00 or Ibplist00)
68
+ if (this.buffer.length >= BINARY_PLIST_HEADER_LENGTH) {
69
+ const possibleBplistHeader = this.buffer.toString(UTF8_ENCODING, 0, BINARY_PLIST_HEADER_LENGTH);
70
+ if (possibleBplistHeader === BINARY_PLIST_MAGIC ||
71
+ possibleBplistHeader.includes(BINARY_PLIST_MAGIC)) {
72
+ log.debug('Detected standard binary plist format');
73
+ this.push(this.buffer);
74
+ this.buffer = Buffer.alloc(0);
75
+ return callback();
76
+ }
77
+ if (possibleBplistHeader === IBINARY_PLIST_MAGIC ||
78
+ possibleBplistHeader.includes(IBINARY_PLIST_MAGIC)) {
79
+ log.debug('Detected non-standard Ibplist00 format');
80
+ this.push(this.buffer);
81
+ this.buffer = Buffer.alloc(0);
82
+ return callback();
83
+ }
84
+ }
85
+ // Process as many complete messages as possible for binary data
86
+ this.processBinaryData(callback);
87
+ }
88
+ catch (err) {
89
+ callback(err);
90
+ }
91
+ }
92
+ /**
93
+ * Process data as XML
94
+ */
95
+ processXmlData(callback) {
96
+ const fullBufferString = this.buffer.toString(UTF8_ENCODING);
97
+ let startIndex = 0;
98
+ if (!fullBufferString.startsWith(XML_DECLARATION)) {
99
+ const declIndex = fullBufferString.indexOf(XML_DECLARATION);
100
+ if (declIndex >= 0) {
101
+ startIndex = declIndex;
102
+ }
103
+ else {
104
+ return callback();
105
+ }
106
+ }
107
+ // Now search for the closing tag in the string starting at startIndex.
108
+ const plistEndIndex = fullBufferString.indexOf(PLIST_CLOSING_TAG, startIndex);
109
+ if (plistEndIndex >= 0) {
110
+ const endPos = plistEndIndex + PLIST_CLOSING_TAG.length;
111
+ const xmlData = this.buffer.slice(0, endPos);
112
+ // Push the complete XML document downstream.
113
+ this.push(xmlData);
114
+ // Remove the processed data from the buffer.
115
+ this.buffer = this.buffer.slice(endPos);
116
+ // If there's remaining data, check if it still looks XML.
117
+ if (this.buffer.length === 0) {
118
+ this.isXmlMode = false;
119
+ }
120
+ else {
121
+ const remainingData = this.buffer.toString(UTF8_ENCODING, 0, Math.min(MAX_PREVIEW_LENGTH, this.buffer.length));
122
+ this.isXmlMode = isXmlPlistContent(remainingData);
123
+ }
124
+ }
125
+ callback();
126
+ }
127
+ /**
128
+ * Process data as binary with length prefix
129
+ */
130
+ processBinaryData(callback) {
131
+ while (this.buffer.length >=
132
+ this.lengthFieldOffset + this.lengthFieldLength) {
133
+ let messageLength;
134
+ // Read the length prefix according to configuration
135
+ if (this.lengthFieldLength === LENGTH_FIELD_4_BYTES) {
136
+ messageLength = this.littleEndian
137
+ ? this.buffer.readUInt32LE(this.lengthFieldOffset)
138
+ : this.buffer.readUInt32BE(this.lengthFieldOffset);
139
+ }
140
+ else if (this.lengthFieldLength === LENGTH_FIELD_2_BYTES) {
141
+ messageLength = this.littleEndian
142
+ ? this.buffer.readUInt16LE(this.lengthFieldOffset)
143
+ : this.buffer.readUInt16BE(this.lengthFieldOffset);
144
+ }
145
+ else if (this.lengthFieldLength === LENGTH_FIELD_1_BYTE) {
146
+ messageLength = this.buffer.readUInt8(this.lengthFieldOffset);
147
+ }
148
+ else if (this.lengthFieldLength === LENGTH_FIELD_8_BYTES) {
149
+ const high = this.littleEndian
150
+ ? this.buffer.readUInt32LE(this.lengthFieldOffset + LENGTH_FIELD_4_BYTES)
151
+ : this.buffer.readUInt32BE(this.lengthFieldOffset);
152
+ const low = this.littleEndian
153
+ ? this.buffer.readUInt32LE(this.lengthFieldOffset)
154
+ : this.buffer.readUInt32BE(this.lengthFieldOffset + LENGTH_FIELD_4_BYTES);
155
+ messageLength = high * UINT32_HIGH_MULTIPLIER + low;
156
+ }
157
+ else {
158
+ throw new Error(`Unsupported lengthFieldLength: ${this.lengthFieldLength}`);
159
+ }
160
+ // Apply adjustment
161
+ messageLength += this.lengthAdjustment;
162
+ // Check if the extracted message length seems suspicious
163
+ if (messageLength < 0 || messageLength > this.maxFrameLength) {
164
+ let alternateLength;
165
+ if (this.lengthFieldLength === LENGTH_FIELD_4_BYTES) {
166
+ alternateLength = this.littleEndian
167
+ ? this.buffer.readUInt32BE(this.lengthFieldOffset)
168
+ : this.buffer.readUInt32LE(this.lengthFieldOffset);
169
+ if (alternateLength > 0 && alternateLength <= this.maxFrameLength) {
170
+ messageLength = alternateLength;
171
+ }
172
+ else {
173
+ // If length is still invalid, check if this might actually be XML
174
+ const suspiciousData = this.buffer.toString(UTF8_ENCODING, 0, Math.min(MAX_PREVIEW_LENGTH, this.buffer.length));
175
+ if (isXmlPlistContent(suspiciousData)) {
176
+ this.isXmlMode = true;
177
+ // Process as XML on next iteration
178
+ return callback();
179
+ }
180
+ // Invalid length - skip one byte and try again
181
+ this.buffer = this.buffer.slice(1);
182
+ continue;
183
+ }
184
+ }
185
+ else {
186
+ // For non-4-byte length fields, just use the original approach
187
+ // If length is invalid, check if this might actually be XML
188
+ const suspiciousData = this.buffer.toString(UTF8_ENCODING, 0, Math.min(MAX_PREVIEW_LENGTH, this.buffer.length));
189
+ if (isXmlPlistContent(suspiciousData)) {
190
+ this.isXmlMode = true;
191
+ // Process as XML on next iteration
192
+ return callback();
193
+ }
194
+ // Invalid length - skip one byte and try again
195
+ this.buffer = this.buffer.slice(1);
196
+ continue;
197
+ }
198
+ }
199
+ // Total length of frame = lengthFieldOffset + lengthFieldLength + messageLength
200
+ const totalLength = this.lengthFieldOffset + this.lengthFieldLength + messageLength;
201
+ // If we don't have the complete message yet, wait for more data
202
+ if (this.buffer.length < totalLength) {
203
+ break;
204
+ }
205
+ // Extract the message
206
+ try {
207
+ // Extract the complete message
208
+ const message = this.buffer.slice(0, totalLength);
209
+ // Check if this message is actually XML
210
+ const messageStart = message.toString(UTF8_ENCODING, 0, Math.min(MAX_PREVIEW_LENGTH, message.length));
211
+ if (isXmlPlistContent(messageStart)) {
212
+ // Switch to XML mode
213
+ this.isXmlMode = true;
214
+ return callback();
215
+ }
216
+ // Push the message
217
+ this.push(message);
218
+ // Remove the processed message from the buffer
219
+ this.buffer = this.buffer.slice(totalLength);
220
+ }
221
+ catch {
222
+ // move forward by 1 byte and try again
223
+ this.buffer = this.buffer.slice(1);
224
+ }
225
+ }
226
+ callback();
227
+ }
228
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Creates an XML plist string from a JavaScript object
3
+ * @param obj - The JavaScript object to convert
4
+ * @returns - XML plist string
5
+ */
6
+ import type { PlistDictionary } from '../types.js';
7
+ export declare function createPlist(obj: PlistDictionary): string;
8
+ //# sourceMappingURL=plist-creator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plist-creator.d.ts","sourceRoot":"","sources":["../../../../src/lib/plist/plist-creator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,eAAe,EAAc,MAAM,aAAa,CAAC;AAG/D,wBAAgB,WAAW,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAiCxD"}
@@ -0,0 +1,33 @@
1
+ import { escapeXml } from './utils.js';
2
+ export function createPlist(obj) {
3
+ function convert(value) {
4
+ if (typeof value === 'number') {
5
+ return `<integer>${value}</integer>`;
6
+ }
7
+ if (typeof value === 'boolean') {
8
+ return value ? '<true/>' : '<false/>';
9
+ }
10
+ if (typeof value === 'string') {
11
+ return `<string>${escapeXml(value)}</string>`;
12
+ }
13
+ if (Array.isArray(value)) {
14
+ return `<array>${value.map((item) => convert(item)).join('')}</array>`;
15
+ }
16
+ if (typeof value === 'object' && value !== null) {
17
+ const entries = Object.entries(value)
18
+ .map(([k, v]) => `<key>${escapeXml(k)}</key>${convert(v)}`)
19
+ .join('');
20
+ return `<dict>${entries}</dict>`;
21
+ }
22
+ return '<string></string>';
23
+ }
24
+ const body = Object.entries(obj)
25
+ .map(([key, val]) => `<key>${escapeXml(key)}</key>${convert(val)}`)
26
+ .join('');
27
+ return `<?xml version="1.0" encoding="UTF-8"?>
28
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
29
+ "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
30
+ <plist version="1.0">
31
+ <dict>${body}</dict>
32
+ </plist>`;
33
+ }
@@ -0,0 +1,25 @@
1
+ import { Transform, type TransformCallback } from 'stream';
2
+ /**
3
+ * Decodes plist format data with length prefix to JavaScript objects
4
+ */
5
+ export declare class PlistServiceDecoder extends Transform {
6
+ static lastDecodedResult: any;
7
+ constructor();
8
+ _transform(data: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
9
+ /**
10
+ * Parse plist data and process the result
11
+ *
12
+ * @param data - The plist data to parse
13
+ * @param callback - The transform callback
14
+ */
15
+ private _parseAndProcess;
16
+ /**
17
+ * Process a successfully parsed result
18
+ * Stores the result in the static property and pushes it to the stream
19
+ *
20
+ * @param result - The parsed plist result
21
+ * @param callback - The transform callback
22
+ */
23
+ private _processResult;
24
+ }
25
+ //# sourceMappingURL=plist-decoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plist-decoder.d.ts","sourceRoot":"","sources":["../../../../src/lib/plist/plist-decoder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,KAAK,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAa3D;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;IAEhD,MAAM,CAAC,iBAAiB,EAAE,GAAG,CAAQ;;IAKrC,UAAU,CACR,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,iBAAiB,GAC1B,IAAI;IA+EP;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAKxB;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;CASvB"}
@@ -0,0 +1,103 @@
1
+ import { logger } from '@appium/support';
2
+ import { Transform } from 'stream';
3
+ import { UTF8_ENCODING } from './constants.js';
4
+ import { parsePlist } from './plist-parser.js';
5
+ import { ensureString, findFirstReplacementCharacter, fixMultipleXmlDeclarations, hasUnicodeReplacementCharacter, } from './utils.js';
6
+ const log = logger.getLogger('Plist');
7
+ /**
8
+ * Decodes plist format data with length prefix to JavaScript objects
9
+ */
10
+ export class PlistServiceDecoder extends Transform {
11
+ // Static property to store the last decoded result
12
+ static lastDecodedResult = null;
13
+ constructor() {
14
+ super({ objectMode: true });
15
+ }
16
+ _transform(data, encoding, callback) {
17
+ try {
18
+ // Get the plist data without the 4-byte header
19
+ let plistData = data.slice(4);
20
+ // Skip empty data
21
+ if (plistData.length === 0) {
22
+ return callback();
23
+ }
24
+ // Check if this is XML data with potential binary header and trim content before XML declaration
25
+ const dataStr = plistData.toString(UTF8_ENCODING, 0, Math.min(100, plistData.length));
26
+ const xmlIndex = dataStr.indexOf('<?xml');
27
+ if (xmlIndex > 0) {
28
+ // There's content before the XML declaration, remove it
29
+ log.debug(`Found XML declaration at position ${xmlIndex}, trimming preceding content`);
30
+ plistData = plistData.slice(xmlIndex);
31
+ }
32
+ // Check for multiple XML declarations which can cause parsing errors
33
+ const fullDataStr = ensureString(plistData);
34
+ // Check for potential corruption indicators and handle them
35
+ if (hasUnicodeReplacementCharacter(plistData)) {
36
+ log.debug('Detected Unicode replacement characters in plist data, which may indicate encoding issues');
37
+ // Try to find and clean the corrupted data
38
+ const firstReplacementPos = findFirstReplacementCharacter(fullDataStr);
39
+ if (firstReplacementPos >= 0) {
40
+ log.debug(`Found replacement character at position ${firstReplacementPos}, attempting to clean data`);
41
+ }
42
+ }
43
+ const xmlDeclMatches = fullDataStr.match(/(<\?xml[^>]*\?>)/g) || [];
44
+ if (xmlDeclMatches.length > 1) {
45
+ log.debug(`Found ${xmlDeclMatches.length} XML declarations, which may cause parsing errors`);
46
+ // Fix multiple XML declarations
47
+ plistData = Buffer.from(fixMultipleXmlDeclarations(plistData));
48
+ }
49
+ try {
50
+ // Parse the plist
51
+ this._parseAndProcess(plistData, callback);
52
+ }
53
+ catch (error) {
54
+ // If parsing fails, try to recover by cleaning up the data more aggressively
55
+ const parseError = error;
56
+ try {
57
+ // Find the first valid XML tag
58
+ const firstTagIndex = fullDataStr.indexOf('<');
59
+ if (firstTagIndex > 0) {
60
+ const cleanedData = plistData.slice(firstTagIndex);
61
+ this._parseAndProcess(cleanedData, callback);
62
+ }
63
+ else {
64
+ // If we can't find a valid starting point, propagate the original error
65
+ throw parseError;
66
+ }
67
+ }
68
+ catch (error) {
69
+ // If recovery also fails, propagate the original error
70
+ callback(error);
71
+ }
72
+ }
73
+ }
74
+ catch (err) {
75
+ callback(err);
76
+ }
77
+ }
78
+ /**
79
+ * Parse plist data and process the result
80
+ *
81
+ * @param data - The plist data to parse
82
+ * @param callback - The transform callback
83
+ */
84
+ _parseAndProcess(data, callback) {
85
+ const result = parsePlist(data);
86
+ this._processResult(result, callback);
87
+ }
88
+ /**
89
+ * Process a successfully parsed result
90
+ * Stores the result in the static property and pushes it to the stream
91
+ *
92
+ * @param result - The parsed plist result
93
+ * @param callback - The transform callback
94
+ */
95
+ _processResult(result, callback) {
96
+ // Store the result in the static property for later access
97
+ if (typeof result === 'object' && result !== null) {
98
+ PlistServiceDecoder.lastDecodedResult = result;
99
+ }
100
+ this.push(result);
101
+ callback();
102
+ }
103
+ }
@@ -0,0 +1,10 @@
1
+ import { Transform, type TransformCallback } from 'stream';
2
+ import type { PlistDictionary } from '../types.js';
3
+ /**
4
+ * Encodes JavaScript objects to plist format with length prefix
5
+ */
6
+ export declare class PlistServiceEncoder extends Transform {
7
+ constructor();
8
+ _transform(data: PlistDictionary, encoding: BufferEncoding, callback: TransformCallback): void;
9
+ }
10
+ //# sourceMappingURL=plist-encoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plist-encoder.d.ts","sourceRoot":"","sources":["../../../../src/lib/plist/plist-encoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAE3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAInD;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;;IAKhD,UAAU,CACR,IAAI,EAAE,eAAe,EACrB,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,iBAAiB,GAC1B,IAAI;CAiBR"}
@@ -0,0 +1,27 @@
1
+ import { Transform } from 'stream';
2
+ import { UTF8_ENCODING } from './constants.js';
3
+ import { createPlist } from './plist-creator.js';
4
+ /**
5
+ * Encodes JavaScript objects to plist format with length prefix
6
+ */
7
+ export class PlistServiceEncoder extends Transform {
8
+ constructor() {
9
+ super({ objectMode: true });
10
+ }
11
+ _transform(data, encoding, callback) {
12
+ try {
13
+ // Convert object to plist
14
+ const plist = createPlist(data);
15
+ const plistBuffer = Buffer.from(plist, UTF8_ENCODING);
16
+ // Create length header (4 bytes, big endian)
17
+ const header = Buffer.alloc(4);
18
+ header.writeUInt32BE(plistBuffer.length, 0);
19
+ // Send header + plist
20
+ this.push(Buffer.concat([header, plistBuffer]));
21
+ callback();
22
+ }
23
+ catch (err) {
24
+ callback(err);
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,9 @@
1
+ import type { PlistDictionary } from '../types.js';
2
+ /**
3
+ * Parses an XML plist string into a JavaScript object
4
+ *
5
+ * @param xmlData - XML plist data as string or Buffer
6
+ * @returns Parsed JavaScript object
7
+ */
8
+ export declare function parsePlist(xmlData: string | Buffer): PlistDictionary;
9
+ //# sourceMappingURL=plist-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plist-parser.d.ts","sourceRoot":"","sources":["../../../../src/lib/plist/plist-parser.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAc,eAAe,EAAc,MAAM,aAAa,CAAC;AAe3E;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,eAAe,CAuHpE"}
@@ -0,0 +1,109 @@
1
+ import { logger } from '@appium/support';
2
+ import { DOMParser, Element, Node } from '@xmldom/xmldom';
3
+ import { PlistService } from './plist-service.js';
4
+ import { cleanXmlWithReplacementChar, ensureString, findFirstReplacementCharacter, fixMultipleXmlDeclarations, hasUnicodeReplacementCharacter, isValidXml, removeExtraContentAfterPlist, trimBeforeXmlDeclaration, } from './utils.js';
5
+ const errorLog = logger.getLogger('PlistError');
6
+ /**
7
+ * Parses an XML plist string into a JavaScript object
8
+ *
9
+ * @param xmlData - XML plist data as string or Buffer
10
+ * @returns Parsed JavaScript object
11
+ */
12
+ export function parsePlist(xmlData) {
13
+ let xmlStr = ensureString(xmlData);
14
+ xmlStr = trimBeforeXmlDeclaration(xmlStr);
15
+ if (hasUnicodeReplacementCharacter(xmlStr)) {
16
+ const badCharPos = findFirstReplacementCharacter(xmlStr);
17
+ xmlStr = cleanXmlWithReplacementChar(xmlStr, badCharPos);
18
+ }
19
+ if (!isValidXml(xmlStr)) {
20
+ if (PlistService.isVerboseErrorLoggingEnabled()) {
21
+ errorLog.debug(`Invalid XML: missing root element - XML content: ${xmlStr.substring(0, 200)}...`);
22
+ }
23
+ throw new Error('Invalid XML: missing root element or malformed XML');
24
+ }
25
+ xmlStr = fixMultipleXmlDeclarations(xmlStr);
26
+ xmlStr = removeExtraContentAfterPlist(xmlStr);
27
+ const parser = new DOMParser({
28
+ errorHandler(level, message) {
29
+ if (level === 'fatalError') {
30
+ throw new Error(`Fatal XML parsing error: ${message}`);
31
+ }
32
+ return true;
33
+ },
34
+ });
35
+ const doc = parser.parseFromString(xmlStr, 'text/xml');
36
+ if (!doc) {
37
+ throw new Error('Invalid XML response');
38
+ }
39
+ const plistElements = doc.getElementsByTagName('plist');
40
+ if (plistElements.length === 0) {
41
+ throw new Error('No plist element found in XML');
42
+ }
43
+ const rootDict = doc.getElementsByTagName('dict')[0];
44
+ if (!rootDict) {
45
+ return {};
46
+ }
47
+ return parseDict(rootDict);
48
+ function parseNode(node) {
49
+ if (!node) {
50
+ return null;
51
+ }
52
+ switch (node.nodeName) {
53
+ case 'dict':
54
+ return parseDict(node);
55
+ case 'array':
56
+ return parseArray(node);
57
+ case 'string':
58
+ return node.textContent || '';
59
+ case 'integer':
60
+ return parseInt(node.textContent || '0', 10);
61
+ case 'real':
62
+ return parseFloat(node.textContent || '0');
63
+ case 'true':
64
+ return true;
65
+ case 'false':
66
+ return false;
67
+ case 'date':
68
+ return new Date(node.textContent || '');
69
+ case 'data':
70
+ if (!node.textContent) {
71
+ return null;
72
+ }
73
+ try {
74
+ return Buffer.from(node.textContent, 'base64');
75
+ }
76
+ catch {
77
+ return node.textContent;
78
+ }
79
+ default:
80
+ return node.textContent || null;
81
+ }
82
+ }
83
+ function parseDict(dictNode) {
84
+ const obj = {};
85
+ const keys = dictNode.getElementsByTagName('key');
86
+ for (let i = 0; i < keys.length; i++) {
87
+ const keyName = keys[i].textContent || '';
88
+ let valueNode = keys[i].nextSibling;
89
+ while (valueNode && valueNode.nodeType !== Node.ELEMENT_NODE) {
90
+ valueNode = valueNode.nextSibling;
91
+ }
92
+ if (valueNode) {
93
+ obj[keyName] = parseNode(valueNode);
94
+ }
95
+ }
96
+ return obj;
97
+ }
98
+ function parseArray(arrayNode) {
99
+ const result = [];
100
+ let childNode = arrayNode.firstChild;
101
+ while (childNode) {
102
+ if (childNode.nodeType === Node.ELEMENT_NODE) {
103
+ result.push(parseNode(childNode));
104
+ }
105
+ childNode = childNode.nextSibling;
106
+ }
107
+ return result;
108
+ }
109
+ }
@@ -0,0 +1,86 @@
1
+ import { Socket } from 'net';
2
+ import { TLSSocket } from 'tls';
3
+ import type { PlistDictionary } from '../types.js';
4
+ /**
5
+ * Message type for plist communications
6
+ */
7
+ type PlistMessage = PlistDictionary;
8
+ /**
9
+ * Options for PlistService
10
+ */
11
+ export interface PlistServiceOptions {
12
+ maxFrameLength?: number;
13
+ }
14
+ /**
15
+ * Service for communication using plist protocol
16
+ */
17
+ export declare class PlistService {
18
+ /**
19
+ * Enable verbose error logging
20
+ */
21
+ static enableVerboseErrorLogging(): void;
22
+ /**
23
+ * Disable verbose error logging
24
+ */
25
+ static disableVerboseErrorLogging(): void;
26
+ /**
27
+ * Check if verbose error logging is enabled
28
+ * @returns True if verbose error logging is enabled
29
+ */
30
+ static isVerboseErrorLoggingEnabled(): boolean;
31
+ /**
32
+ * Gets the underlying socket
33
+ * @returns The socket used by this service
34
+ */
35
+ getSocket(): Socket | TLSSocket;
36
+ private readonly _socket;
37
+ private readonly _splitter;
38
+ private readonly _decoder;
39
+ private _encoder;
40
+ private _messageQueue;
41
+ /**
42
+ * Creates a new PlistService instance
43
+ * @param socket The socket to use for communication
44
+ * @param options Configuration options
45
+ */
46
+ constructor(socket: Socket, options?: PlistServiceOptions);
47
+ /**
48
+ * Send a plist message and receive a response
49
+ * @param data Message to send
50
+ * @param timeout Response timeout in ms
51
+ * @returns Promise resolving to the received message
52
+ */
53
+ sendPlistAndReceive(data: PlistMessage, timeout?: number): Promise<PlistMessage>;
54
+ /**
55
+ * Send a plist message
56
+ * @param data Message to send
57
+ * @throws Error if data is null or undefined
58
+ */
59
+ sendPlist(data: PlistMessage): void;
60
+ /**
61
+ * Receive a plist message with timeout
62
+ * @param timeout Timeout in ms
63
+ * @returns Promise resolving to the received message
64
+ * @throws Error if timeout is reached before receiving a message
65
+ */
66
+ receivePlist(timeout?: number): Promise<PlistMessage>;
67
+ /**
68
+ * Close the connection and clean up resources
69
+ */
70
+ close(): void;
71
+ /**
72
+ * Sets up the data pipeline between socket and transformers
73
+ */
74
+ private setupPipeline;
75
+ /**
76
+ * Sets up error handlers for socket and transformers
77
+ */
78
+ private setupErrorHandlers;
79
+ /**
80
+ * Handles errors from any component
81
+ * @param error The error that occurred
82
+ */
83
+ private handleError;
84
+ }
85
+ export {};
86
+ //# sourceMappingURL=plist-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plist-service.d.ts","sourceRoot":"","sources":["../../../../src/lib/plist/plist-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAYnD;;GAEG;AACH,KAAK,YAAY,GAAG,eAAe,CAAC;AAEpC;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB;;OAEG;IACH,MAAM,CAAC,yBAAyB,IAAI,IAAI;IAKxC;;OAEG;IACH,MAAM,CAAC,0BAA0B,IAAI,IAAI;IAIzC;;;OAGG;IACH,MAAM,CAAC,4BAA4B,IAAI,OAAO;IAI9C;;;OAGG;IACI,SAAS,IAAI,MAAM,GAAG,SAAS;IAGtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsB;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,aAAa,CAAiB;IAEtC;;;;OAIG;gBACS,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB;IAuB7D;;;;;OAKG;IACU,mBAAmB,CAC9B,IAAI,EAAE,YAAY,EAClB,OAAO,SAAO,GACb,OAAO,CAAC,YAAY,CAAC;IAKxB;;;;OAIG;IACI,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAO1C;;;;;OAKG;IACU,YAAY,CAAC,OAAO,SAAO,GAAG,OAAO,CAAC,YAAY,CAAC;IA4BhE;;OAEG;IACI,KAAK,IAAI,IAAI;IAgCpB;;OAEG;IACH,OAAO,CAAC,aAAa;IAMrB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAO1B;;;OAGG;IACH,OAAO,CAAC,WAAW;CAgBpB"}