appium-ios-device 3.1.9 → 3.1.11
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/CHANGELOG.md +12 -0
- package/build/lib/afc/index.d.ts +1 -1
- package/build/lib/afc/index.d.ts.map +1 -1
- package/build/lib/afc/index.js +9 -9
- package/build/lib/afc/index.js.map +1 -1
- package/build/lib/afc/protocol.d.ts.map +1 -1
- package/build/lib/afc/protocol.js +16 -16
- package/build/lib/afc/protocol.js.map +1 -1
- package/build/lib/afc/streams.d.ts.map +1 -1
- package/build/lib/afc/streams.js.map +1 -1
- package/build/lib/afc/transformer/afcdecoder.d.ts.map +1 -1
- package/build/lib/afc/transformer/afcdecoder.js.map +1 -1
- package/build/lib/afc/transformer/afcencoder.d.ts.map +1 -1
- package/build/lib/afc/transformer/afcencoder.js.map +1 -1
- package/build/lib/base-service.d.ts.map +1 -1
- package/build/lib/base-service.js.map +1 -1
- package/build/lib/house-arrest/index.d.ts.map +1 -1
- package/build/lib/house-arrest/index.js.map +1 -1
- package/build/lib/imagemounter/index.d.ts.map +1 -1
- package/build/lib/imagemounter/index.js +4 -4
- package/build/lib/imagemounter/index.js.map +1 -1
- package/build/lib/imagemounter/utils/list_developer_image.d.ts.map +1 -1
- package/build/lib/imagemounter/utils/list_developer_image.js +3 -3
- package/build/lib/imagemounter/utils/list_developer_image.js.map +1 -1
- package/build/lib/installation-proxy/index.d.ts +11 -11
- package/build/lib/installation-proxy/index.d.ts.map +1 -1
- package/build/lib/installation-proxy/index.js +19 -17
- package/build/lib/installation-proxy/index.js.map +1 -1
- package/build/lib/instrument/headers.d.ts.map +1 -1
- package/build/lib/instrument/headers.js +7 -7
- package/build/lib/instrument/headers.js.map +1 -1
- package/build/lib/instrument/index.d.ts +1 -1
- package/build/lib/instrument/index.d.ts.map +1 -1
- package/build/lib/instrument/index.js +13 -7
- package/build/lib/instrument/index.js.map +1 -1
- package/build/lib/instrument/transformer/dtx-decode.d.ts.map +1 -1
- package/build/lib/instrument/transformer/dtx-decode.js +9 -3
- package/build/lib/instrument/transformer/dtx-decode.js.map +1 -1
- package/build/lib/instrument/transformer/dtx-encode.d.ts.map +1 -1
- package/build/lib/instrument/transformer/dtx-encode.js +1 -1
- package/build/lib/instrument/transformer/dtx-encode.js.map +1 -1
- package/build/lib/instrument/transformer/nskeyed.d.ts.map +1 -1
- package/build/lib/instrument/transformer/nskeyed.js +16 -9
- package/build/lib/instrument/transformer/nskeyed.js.map +1 -1
- package/build/lib/lockdown/index.d.ts +5 -5
- package/build/lib/lockdown/index.d.ts.map +1 -1
- package/build/lib/lockdown/index.js +9 -10
- package/build/lib/lockdown/index.js.map +1 -1
- package/build/lib/logger.js.map +1 -1
- package/build/lib/mcinstall/index.d.ts.map +1 -1
- package/build/lib/mcinstall/index.js +14 -6
- package/build/lib/mcinstall/index.js.map +1 -1
- package/build/lib/notification-proxy/index.d.ts.map +1 -1
- package/build/lib/notification-proxy/index.js +2 -2
- package/build/lib/notification-proxy/index.js.map +1 -1
- package/build/lib/plist-service/index.d.ts.map +1 -1
- package/build/lib/plist-service/index.js.map +1 -1
- package/build/lib/plist-service/transformer/plist-service-decoder.d.ts.map +1 -1
- package/build/lib/plist-service/transformer/plist-service-decoder.js.map +1 -1
- package/build/lib/plist-service/transformer/plist-service-encoder.d.ts.map +1 -1
- package/build/lib/plist-service/transformer/plist-service-encoder.js.map +1 -1
- package/build/lib/services.d.ts.map +1 -1
- package/build/lib/services.js +3 -3
- package/build/lib/services.js.map +1 -1
- package/build/lib/simulatelocation/index.d.ts.map +1 -1
- package/build/lib/simulatelocation/index.js.map +1 -1
- package/build/lib/ssl-helper.js +3 -3
- package/build/lib/ssl-helper.js.map +1 -1
- package/build/lib/syslog/index.d.ts +1 -1
- package/build/lib/syslog/index.d.ts.map +1 -1
- package/build/lib/syslog/index.js +1 -1
- package/build/lib/syslog/index.js.map +1 -1
- package/build/lib/syslog/transformer/syslog-decoder.d.ts.map +1 -1
- package/build/lib/syslog/transformer/syslog-decoder.js +4 -2
- package/build/lib/syslog/transformer/syslog-decoder.js.map +1 -1
- package/build/lib/testmanagerd/index.d.ts.map +1 -1
- package/build/lib/testmanagerd/index.js.map +1 -1
- package/build/lib/usbmux/index.d.ts.map +1 -1
- package/build/lib/usbmux/index.js +16 -13
- package/build/lib/usbmux/index.js.map +1 -1
- package/build/lib/usbmux/transformer/usbmux-decoder.d.ts.map +1 -1
- package/build/lib/usbmux/transformer/usbmux-decoder.js +1 -1
- package/build/lib/usbmux/transformer/usbmux-decoder.js.map +1 -1
- package/build/lib/usbmux/transformer/usbmux-encoder.d.ts.map +1 -1
- package/build/lib/usbmux/transformer/usbmux-encoder.js +1 -1
- package/build/lib/usbmux/transformer/usbmux-encoder.js.map +1 -1
- package/build/lib/util/transformer/length-based-splitter.d.ts.map +1 -1
- package/build/lib/util/transformer/length-based-splitter.js +9 -4
- package/build/lib/util/transformer/length-based-splitter.js.map +1 -1
- package/build/lib/util/transformer/stream-logger.d.ts.map +1 -1
- package/build/lib/util/transformer/stream-logger.js +4 -3
- package/build/lib/util/transformer/stream-logger.js.map +1 -1
- package/build/lib/util/uuid/parse.js.map +1 -1
- package/build/lib/util/uuid/stringify.js.map +1 -1
- package/build/lib/util/uuid/validate.d.ts.map +1 -1
- package/build/lib/util/uuid/validate.js.map +1 -1
- package/build/lib/utilities.d.ts.map +1 -1
- package/build/lib/utilities.js +12 -12
- package/build/lib/utilities.js.map +1 -1
- package/build/lib/webinspector/index.d.ts.map +1 -1
- package/build/lib/webinspector/index.js +11 -9
- package/build/lib/webinspector/index.js.map +1 -1
- package/build/lib/webinspector/transformer/webinspector-decoder.d.ts.map +1 -1
- package/build/lib/webinspector/transformer/webinspector-decoder.js.map +1 -1
- package/build/lib/webinspector/transformer/webinspector-encoder.d.ts.map +1 -1
- package/build/lib/webinspector/transformer/webinspector-encoder.js.map +1 -1
- package/build/lib/xctest.d.ts.map +1 -1
- package/build/lib/xctest.js +3 -6
- package/build/lib/xctest.js.map +1 -1
- package/lib/afc/index.js +49 -43
- package/lib/afc/protocol.js +53 -50
- package/lib/afc/streams.js +7 -9
- package/lib/afc/transformer/afcdecoder.js +8 -10
- package/lib/afc/transformer/afcencoder.js +7 -10
- package/lib/base-service.js +2 -4
- package/lib/constants.js +1 -1
- package/lib/house-arrest/index.js +16 -14
- package/lib/imagemounter/index.js +107 -104
- package/lib/imagemounter/utils/list_developer_image.js +115 -100
- package/lib/installation-proxy/index.js +31 -27
- package/lib/instrument/headers.js +51 -40
- package/lib/instrument/index.js +32 -21
- package/lib/instrument/transformer/dtx-decode.js +30 -16
- package/lib/instrument/transformer/dtx-encode.js +6 -8
- package/lib/instrument/transformer/nskeyed.js +40 -21
- package/lib/lockdown/index.js +44 -35
- package/lib/logger.js +1 -1
- package/lib/mcinstall/index.js +20 -13
- package/lib/notification-proxy/index.js +18 -17
- package/lib/plist-service/index.js +13 -14
- package/lib/plist-service/transformer/plist-service-decoder.js +6 -7
- package/lib/plist-service/transformer/plist-service-encoder.js +6 -7
- package/lib/services.js +45 -29
- package/lib/simulatelocation/index.js +4 -5
- package/lib/ssl-helper.js +6 -7
- package/lib/syslog/index.js +7 -8
- package/lib/syslog/transformer/syslog-decoder.js +11 -10
- package/lib/testmanagerd/index.js +10 -7
- package/lib/usbmux/index.js +52 -41
- package/lib/usbmux/transformer/usbmux-decoder.js +8 -10
- package/lib/usbmux/transformer/usbmux-encoder.js +10 -8
- package/lib/util/transformer/length-based-splitter.js +62 -24
- package/lib/util/transformer/stream-logger.js +14 -11
- package/lib/util/uuid/parse.ts +2 -2
- package/lib/util/uuid/stringify.ts +1 -1
- package/lib/util/uuid/validate.ts +2 -1
- package/lib/utilities.js +39 -28
- package/lib/webinspector/index.js +59 -46
- package/lib/webinspector/transformer/webinspector-decoder.js +22 -11
- package/lib/webinspector/transformer/webinspector-encoder.js +6 -8
- package/lib/xctest.js +284 -245
- package/package.json +4 -2
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import Stream from 'node:stream';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import {log} from '../../logger';
|
|
3
|
+
import {util} from '@appium/support';
|
|
4
4
|
|
|
5
5
|
// Debug configuration
|
|
6
6
|
const DEBUG_CONFIG = {
|
|
7
7
|
enableFrameSizeLogging: process.env.APPIUM_IOS_DEBUG_FRAME_SIZE === 'true',
|
|
8
8
|
enableLargeFrameLogging: process.env.APPIUM_IOS_LOG_LARGE_FRAMES === 'true',
|
|
9
9
|
largeFrameThreshold: parseInt(process.env.APPIUM_IOS_LARGE_FRAME_THRESHOLD || '10485760', 10), // 10MB
|
|
10
|
-
enableMemoryMonitoring: process.env.APPIUM_IOS_MONITOR_MEMORY === 'true'
|
|
10
|
+
enableMemoryMonitoring: process.env.APPIUM_IOS_MONITOR_MEMORY === 'true',
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
export class LengthBasedSplitter extends Stream.Transform {
|
|
14
|
-
constructor
|
|
14
|
+
constructor(opts) {
|
|
15
15
|
super();
|
|
16
16
|
|
|
17
17
|
const {
|
|
@@ -36,7 +36,7 @@ export class LengthBasedSplitter extends Stream.Transform {
|
|
|
36
36
|
this._frameBuffer = Buffer.allocUnsafeSlow(maxFrameLength);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
_transform
|
|
39
|
+
_transform(data, encoding, onData) {
|
|
40
40
|
for (let i = 0; i < data.length; i = this._decode(data, i)) {
|
|
41
41
|
if (this.isShutdown) {
|
|
42
42
|
return this._pushBack(i, data.length, data);
|
|
@@ -45,11 +45,23 @@ export class LengthBasedSplitter extends Stream.Transform {
|
|
|
45
45
|
onData();
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
_decode
|
|
48
|
+
_decode(data, pos) {
|
|
49
49
|
let bufferMarker = pos;
|
|
50
50
|
|
|
51
|
-
let bytesToRead = Math.max(
|
|
52
|
-
|
|
51
|
+
let bytesToRead = Math.max(
|
|
52
|
+
this.lengthFieldOffset + this.lengthFieldLength - this._frameBufferIndex,
|
|
53
|
+
0,
|
|
54
|
+
);
|
|
55
|
+
let nBytesRead =
|
|
56
|
+
bytesToRead === 0
|
|
57
|
+
? 0
|
|
58
|
+
: this._readBytes(
|
|
59
|
+
data,
|
|
60
|
+
bufferMarker,
|
|
61
|
+
this._frameBuffer,
|
|
62
|
+
this._frameBufferIndex,
|
|
63
|
+
bytesToRead,
|
|
64
|
+
);
|
|
53
65
|
bufferMarker += nBytesRead;
|
|
54
66
|
this._frameBufferIndex += nBytesRead;
|
|
55
67
|
|
|
@@ -57,11 +69,17 @@ export class LengthBasedSplitter extends Stream.Transform {
|
|
|
57
69
|
return bufferMarker;
|
|
58
70
|
}
|
|
59
71
|
|
|
60
|
-
const messageLength = this._readLength(
|
|
72
|
+
const messageLength = this._readLength(
|
|
73
|
+
this._frameBuffer,
|
|
74
|
+
this.lengthFieldOffset,
|
|
75
|
+
this.littleEndian,
|
|
76
|
+
);
|
|
61
77
|
|
|
62
78
|
// Debug logging for frame sizes
|
|
63
79
|
if (DEBUG_CONFIG.enableFrameSizeLogging) {
|
|
64
|
-
log.debug(
|
|
80
|
+
log.debug(
|
|
81
|
+
`Frame size detected: ${messageLength} bytes, max allowed: ${this.maxFrameLength} bytes`,
|
|
82
|
+
);
|
|
65
83
|
}
|
|
66
84
|
|
|
67
85
|
// Log large frames for investigation
|
|
@@ -76,7 +94,16 @@ export class LengthBasedSplitter extends Stream.Transform {
|
|
|
76
94
|
const completeMessageLength = messageLength + this.lengthAdjustment + this.lengthFieldOffset;
|
|
77
95
|
|
|
78
96
|
bytesToRead = completeMessageLength - this._frameBufferIndex;
|
|
79
|
-
nBytesRead =
|
|
97
|
+
nBytesRead =
|
|
98
|
+
bytesToRead === 0
|
|
99
|
+
? 0
|
|
100
|
+
: this._readBytes(
|
|
101
|
+
data,
|
|
102
|
+
bufferMarker,
|
|
103
|
+
this._frameBuffer,
|
|
104
|
+
this._frameBufferIndex,
|
|
105
|
+
bytesToRead,
|
|
106
|
+
);
|
|
80
107
|
bufferMarker += nBytesRead;
|
|
81
108
|
this._frameBufferIndex += nBytesRead;
|
|
82
109
|
|
|
@@ -92,16 +119,16 @@ export class LengthBasedSplitter extends Stream.Transform {
|
|
|
92
119
|
return bufferMarker;
|
|
93
120
|
}
|
|
94
121
|
|
|
95
|
-
_readBytes
|
|
122
|
+
_readBytes(src, srcIndex, target, targetIndex, nBytesToBeRead) {
|
|
96
123
|
let availableBytes = Math.min(nBytesToBeRead, src.length - srcIndex);
|
|
97
124
|
src.copy(target, targetIndex, srcIndex, srcIndex + availableBytes);
|
|
98
125
|
return availableBytes;
|
|
99
126
|
}
|
|
100
|
-
_resetBuffers
|
|
127
|
+
_resetBuffers() {
|
|
101
128
|
this._frameBufferIndex = 0;
|
|
102
129
|
}
|
|
103
130
|
|
|
104
|
-
_pushBack
|
|
131
|
+
_pushBack(start, end, data) {
|
|
105
132
|
if (start > end) {
|
|
106
133
|
log.error('More data was read than the buffer size. This should not happen');
|
|
107
134
|
}
|
|
@@ -113,7 +140,7 @@ export class LengthBasedSplitter extends Stream.Transform {
|
|
|
113
140
|
process.nextTick(() => this.readableStream.unshift(leftover));
|
|
114
141
|
}
|
|
115
142
|
|
|
116
|
-
shutdown
|
|
143
|
+
shutdown() {
|
|
117
144
|
this.isShutdown = true;
|
|
118
145
|
}
|
|
119
146
|
|
|
@@ -123,12 +150,16 @@ export class LengthBasedSplitter extends Stream.Transform {
|
|
|
123
150
|
*/
|
|
124
151
|
_logLargeFrame(messageLength) {
|
|
125
152
|
log.warn(`Large frame detected: ${util.toReadableSizeString(messageLength)}`);
|
|
126
|
-
log.warn(
|
|
153
|
+
log.warn(
|
|
154
|
+
`Service: ${this.serviceName}, Max allowed: ${util.toReadableSizeString(this.maxFrameLength)}`,
|
|
155
|
+
);
|
|
127
156
|
|
|
128
157
|
// Log memory usage if monitoring is enabled
|
|
129
158
|
if (DEBUG_CONFIG.enableMemoryMonitoring) {
|
|
130
159
|
const memUsage = process.memoryUsage();
|
|
131
|
-
log.warn(
|
|
160
|
+
log.warn(
|
|
161
|
+
`Memory usage - RSS: ${util.toReadableSizeString(memUsage.rss)}, Heap: ${util.toReadableSizeString(memUsage.heapUsed)}`,
|
|
162
|
+
);
|
|
132
163
|
}
|
|
133
164
|
}
|
|
134
165
|
|
|
@@ -138,30 +169,37 @@ export class LengthBasedSplitter extends Stream.Transform {
|
|
|
138
169
|
* @returns {Error} The constructed error object
|
|
139
170
|
*/
|
|
140
171
|
_makeFrameSizeError(messageLength) {
|
|
141
|
-
const errorMsg =
|
|
172
|
+
const errorMsg =
|
|
173
|
+
`The frame is bigger than expected. ` +
|
|
142
174
|
`Length: ${util.toReadableSizeString(messageLength)}, ` +
|
|
143
175
|
`max: ${util.toReadableSizeString(this.maxFrameLength)}`;
|
|
144
176
|
log.error(errorMsg);
|
|
145
|
-
log.error(
|
|
146
|
-
`
|
|
147
|
-
|
|
177
|
+
log.error(
|
|
178
|
+
`Service: ${this.serviceName}, ` +
|
|
179
|
+
`Frame offset: ${this.lengthFieldOffset}, ` +
|
|
180
|
+
`Frame length: ${this.lengthFieldLength}`,
|
|
181
|
+
);
|
|
148
182
|
|
|
149
183
|
// Only suggest debugging steps if debug mode is not already enabled
|
|
150
184
|
if (!DEBUG_CONFIG.enableFrameSizeLogging) {
|
|
151
|
-
log.error(
|
|
185
|
+
log.error(
|
|
186
|
+
'To debug this issue, see: https://github.com/appium/appium-ios-device/blob/master/docs/DEBUG_FRAME_SIZE.md',
|
|
187
|
+
);
|
|
152
188
|
}
|
|
153
189
|
|
|
154
190
|
return new Error(errorMsg);
|
|
155
191
|
}
|
|
156
192
|
|
|
157
|
-
_readLength
|
|
193
|
+
_readLength(data, index, littleEndian) {
|
|
158
194
|
switch (this.lengthFieldLength) {
|
|
159
195
|
case 4:
|
|
160
196
|
return littleEndian ? data.readUInt32LE(index) : data.readUInt32BE(index);
|
|
161
197
|
case 8:
|
|
162
198
|
return littleEndian ? data.readUInt32LE(index) : data.readUInt32BE(index + 4);
|
|
163
199
|
default:
|
|
164
|
-
throw new Error(
|
|
200
|
+
throw new Error(
|
|
201
|
+
`${this.lengthFieldLength} is not supported. Only 4 and 8 are supported at the moment`,
|
|
202
|
+
);
|
|
165
203
|
}
|
|
166
204
|
}
|
|
167
205
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import Stream from 'node:stream';
|
|
2
2
|
import _ from 'lodash';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {log} from '../../logger';
|
|
5
4
|
|
|
6
5
|
const MIN_PRINTABLE_CHAR = 32;
|
|
7
6
|
const MAX_PRINTABLE_CHAR = 126;
|
|
@@ -9,14 +8,14 @@ const MAX_PRINTABLE_CHAR = 126;
|
|
|
9
8
|
const CHARACTERS_PER_LINE = 19;
|
|
10
9
|
|
|
11
10
|
export class StreamLogger extends Stream.Transform {
|
|
12
|
-
constructor
|
|
13
|
-
super({
|
|
11
|
+
constructor(direction, verbose = false) {
|
|
12
|
+
super({objectMode: true});
|
|
14
13
|
|
|
15
14
|
this._direction = direction;
|
|
16
15
|
this._verbose = verbose;
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
_transform
|
|
18
|
+
_transform(data, encoding, onData) {
|
|
20
19
|
if (this._verbose) {
|
|
21
20
|
try {
|
|
22
21
|
this._log(data);
|
|
@@ -31,15 +30,18 @@ export class StreamLogger extends Stream.Transform {
|
|
|
31
30
|
onData();
|
|
32
31
|
}
|
|
33
32
|
|
|
34
|
-
_log
|
|
35
|
-
log.debug(
|
|
33
|
+
_log(data) {
|
|
34
|
+
log.debug(
|
|
35
|
+
`Data ${this._direction === StreamLogger.SEND ? 'sent' : 'received'}, length: ${data.length}`,
|
|
36
|
+
);
|
|
36
37
|
|
|
37
38
|
// format as used by ios-webkit-debug-proxy as well as tools like socat
|
|
38
39
|
// print out the data in two sections, one the hexadecimal renderings of the characters,
|
|
39
40
|
// the other the printable characters (with '.' for unprintable characters).
|
|
40
41
|
let i = 0;
|
|
41
42
|
while (i < data.length) {
|
|
42
|
-
let hex = [],
|
|
43
|
+
let hex = [],
|
|
44
|
+
char = [];
|
|
43
45
|
// create each line of text to output
|
|
44
46
|
for (let j = 0; j < CHARACTERS_PER_LINE; j++) {
|
|
45
47
|
if (i >= data.length) {
|
|
@@ -52,9 +54,10 @@ export class StreamLogger extends Stream.Transform {
|
|
|
52
54
|
// hexadecimal representation, forced into 2 places
|
|
53
55
|
hex[j] = _.padStart(charCode.toString(16).toUpperCase(), 2, '0');
|
|
54
56
|
// character representation, with '.' when unprintable
|
|
55
|
-
char[j] =
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
char[j] =
|
|
58
|
+
charCode < MIN_PRINTABLE_CHAR || charCode > MAX_PRINTABLE_CHAR
|
|
59
|
+
? '.'
|
|
60
|
+
: String.fromCharCode(charCode);
|
|
58
61
|
}
|
|
59
62
|
log.debug(`${hex.join(' ')} ${char.join('')}`);
|
|
60
63
|
}
|
package/lib/util/uuid/parse.ts
CHANGED
|
@@ -21,7 +21,7 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
21
21
|
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import {
|
|
24
|
+
import {validate} from './validate';
|
|
25
25
|
|
|
26
26
|
export function parse(uuid: string): Uint8Array {
|
|
27
27
|
if (!validate(uuid)) {
|
|
@@ -54,6 +54,6 @@ export function parse(uuid: string): Uint8Array {
|
|
|
54
54
|
(v >>> 24) & 0xff,
|
|
55
55
|
(v >>> 16) & 0xff,
|
|
56
56
|
(v >>> 8) & 0xff,
|
|
57
|
-
v & 0xff
|
|
57
|
+
v & 0xff,
|
|
58
58
|
);
|
|
59
59
|
}
|
|
@@ -21,7 +21,8 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
21
21
|
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
const REGEX =
|
|
24
|
+
const REGEX =
|
|
25
|
+
/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;
|
|
25
26
|
|
|
26
27
|
export function validate(uuid: unknown): boolean {
|
|
27
28
|
return typeof uuid === 'string' && REGEX.test(uuid);
|
package/lib/utilities.js
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import {Usbmux, getDefaultSocket} from './usbmux';
|
|
2
|
+
import {upgradeToSSL, enableSSLHandshakeOnly} from './ssl-helper';
|
|
3
3
|
import _ from 'lodash';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import {log} from './logger';
|
|
5
|
+
import {findDeveloperImage} from './imagemounter/utils/list_developer_image';
|
|
6
6
|
|
|
7
7
|
// https://github.com/samdmarshall/iOS-Internals/blob/master/lockbot/lockbot/lockdown_keys.h
|
|
8
8
|
const LOCKDOWN_REQUEST = {
|
|
9
|
-
DEVICE_TIME: {
|
|
10
|
-
DEVICE_UTC_OFFSET: {
|
|
11
|
-
DEVICE_TIME_ZONE: {
|
|
12
|
-
DEVICE_VERSION: {
|
|
13
|
-
DEVICE_NAME: {
|
|
9
|
+
DEVICE_TIME: {Key: 'TimeIntervalSince1970'},
|
|
10
|
+
DEVICE_UTC_OFFSET: {Key: 'TimeZoneOffsetFromUTC'},
|
|
11
|
+
DEVICE_TIME_ZONE: {Key: 'TimeZone'},
|
|
12
|
+
DEVICE_VERSION: {Key: 'ProductVersion'},
|
|
13
|
+
DEVICE_NAME: {Key: 'DeviceName'},
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
|
|
17
16
|
/**
|
|
18
17
|
* Retrieves the udids of the connected devices
|
|
19
18
|
*
|
|
@@ -24,7 +23,7 @@ const LOCKDOWN_REQUEST = {
|
|
|
24
23
|
async function getConnectedDevices(socket = null) {
|
|
25
24
|
let usbmux;
|
|
26
25
|
try {
|
|
27
|
-
usbmux = new Usbmux(socket || await getDefaultSocket());
|
|
26
|
+
usbmux = new Usbmux(socket || (await getDefaultSocket()));
|
|
28
27
|
} catch (e) {
|
|
29
28
|
log.debug(e);
|
|
30
29
|
return [];
|
|
@@ -46,7 +45,7 @@ async function getConnectedDevices(socket = null) {
|
|
|
46
45
|
* @returns {Promise<string>}
|
|
47
46
|
*/
|
|
48
47
|
async function getOSVersion(udid, socket = null) {
|
|
49
|
-
const usbmux = new Usbmux(socket || await getDefaultSocket());
|
|
48
|
+
const usbmux = new Usbmux(socket || (await getDefaultSocket()));
|
|
50
49
|
try {
|
|
51
50
|
// lockdown doesn't need to be closed since it uses the same socket usbmux uses
|
|
52
51
|
const lockdown = await usbmux.connectLockdown(udid);
|
|
@@ -64,7 +63,7 @@ async function getOSVersion(udid, socket = null) {
|
|
|
64
63
|
* @returns {Promise<string>}
|
|
65
64
|
*/
|
|
66
65
|
async function getDeviceName(udid, socket = null) {
|
|
67
|
-
const usbmux = new Usbmux(socket || await getDefaultSocket());
|
|
66
|
+
const usbmux = new Usbmux(socket || (await getDefaultSocket()));
|
|
68
67
|
try {
|
|
69
68
|
// lockdown doesn't need to be closed since it uses the same socket usbmux uses
|
|
70
69
|
const lockdown = await usbmux.connectLockdown(udid);
|
|
@@ -114,7 +113,7 @@ async function getDeviceName(udid, socket = null) {
|
|
|
114
113
|
* }
|
|
115
114
|
*/
|
|
116
115
|
async function getDeviceInfo(udid, socket = null) {
|
|
117
|
-
const usbmux = new Usbmux(socket || await getDefaultSocket());
|
|
116
|
+
const usbmux = new Usbmux(socket || (await getDefaultSocket()));
|
|
118
117
|
try {
|
|
119
118
|
const lockdown = await usbmux.connectLockdown(udid);
|
|
120
119
|
return await lockdown.getValue();
|
|
@@ -145,7 +144,7 @@ async function getDeviceTime(udid, socket = null) {
|
|
|
145
144
|
return {
|
|
146
145
|
timestamp: await lockdown.getValue(LOCKDOWN_REQUEST.DEVICE_TIME),
|
|
147
146
|
// Apple returns utcOffset in seconds which doesnt comply with the general standard
|
|
148
|
-
utcOffset: await lockdown.getValue(LOCKDOWN_REQUEST.DEVICE_UTC_OFFSET) / 60,
|
|
147
|
+
utcOffset: (await lockdown.getValue(LOCKDOWN_REQUEST.DEVICE_UTC_OFFSET)) / 60,
|
|
149
148
|
timeZone: await lockdown.getValue(LOCKDOWN_REQUEST.DEVICE_TIME_ZONE),
|
|
150
149
|
};
|
|
151
150
|
} finally {
|
|
@@ -161,11 +160,13 @@ async function getDeviceTime(udid, socket = null) {
|
|
|
161
160
|
* @returns {Promise<import('./lockdown').Lockdown>}
|
|
162
161
|
*/
|
|
163
162
|
async function startLockdownSession(udid, socket = null) {
|
|
164
|
-
const usbmux = new Usbmux(socket || await getDefaultSocket());
|
|
163
|
+
const usbmux = new Usbmux(socket || (await getDefaultSocket()));
|
|
165
164
|
try {
|
|
166
165
|
const pairRecord = await usbmux.readPairRecord(udid);
|
|
167
166
|
if (!pairRecord) {
|
|
168
|
-
throw new Error(
|
|
167
|
+
throw new Error(
|
|
168
|
+
`Could not find a pair record for device '${udid}'. Please first pair with the device`,
|
|
169
|
+
);
|
|
169
170
|
}
|
|
170
171
|
// lockdown doesn't need to be closed since it uses the same socket usbmux uses
|
|
171
172
|
const lockdown = await usbmux.connectLockdown(udid);
|
|
@@ -188,7 +189,7 @@ async function startLockdownSession(udid, socket = null) {
|
|
|
188
189
|
* @returns {Promise<import('tls').TLSSocket|Object>} The socket or the object returned in the callback if the callback function exists
|
|
189
190
|
*/
|
|
190
191
|
async function connectPortSSL(udid, port, socket = null, handshakeOnly = false) {
|
|
191
|
-
const usbmux = new Usbmux(socket || await getDefaultSocket());
|
|
192
|
+
const usbmux = new Usbmux(socket || (await getDefaultSocket()));
|
|
192
193
|
try {
|
|
193
194
|
const device = await usbmux.findDevice(udid);
|
|
194
195
|
if (!device) {
|
|
@@ -196,12 +197,14 @@ async function connectPortSSL(udid, port, socket = null, handshakeOnly = false)
|
|
|
196
197
|
}
|
|
197
198
|
const pairRecord = await usbmux.readPairRecord(udid);
|
|
198
199
|
if (!pairRecord) {
|
|
199
|
-
throw new Error(
|
|
200
|
+
throw new Error(
|
|
201
|
+
`Could not find a pair record for device '${udid}'. Please first pair with the device`,
|
|
202
|
+
);
|
|
200
203
|
}
|
|
201
204
|
const socket = await usbmux.connect(device.Properties.DeviceID, port, undefined);
|
|
202
|
-
return handshakeOnly
|
|
203
|
-
await enableSSLHandshakeOnly(socket, pairRecord.HostPrivateKey, pairRecord.HostCertificate)
|
|
204
|
-
upgradeToSSL(socket, pairRecord.HostPrivateKey, pairRecord.HostCertificate);
|
|
205
|
+
return handshakeOnly
|
|
206
|
+
? await enableSSLHandshakeOnly(socket, pairRecord.HostPrivateKey, pairRecord.HostCertificate)
|
|
207
|
+
: upgradeToSSL(socket, pairRecord.HostPrivateKey, pairRecord.HostCertificate);
|
|
205
208
|
} catch (e) {
|
|
206
209
|
usbmux.close();
|
|
207
210
|
throw e;
|
|
@@ -217,7 +220,7 @@ async function connectPortSSL(udid, port, socket = null, handshakeOnly = false)
|
|
|
217
220
|
* @returns {Promise<NodeJS.Socket|Object>} The socket or the object returned in the callback if the callback function exists
|
|
218
221
|
*/
|
|
219
222
|
async function connectPort(udid, port, socket = null) {
|
|
220
|
-
const usbmux = new Usbmux(socket || await getDefaultSocket());
|
|
223
|
+
const usbmux = new Usbmux(socket || (await getDefaultSocket()));
|
|
221
224
|
try {
|
|
222
225
|
const device = await usbmux.findDevice(udid);
|
|
223
226
|
if (!device) {
|
|
@@ -247,12 +250,13 @@ async function connectPort(udid, port, socket = null) {
|
|
|
247
250
|
async function fetchImageFromGithubRepo(udid, opts) {
|
|
248
251
|
const osVersion = await getOSVersion(udid);
|
|
249
252
|
if (!opts.githubRepo) {
|
|
250
|
-
throw new TypeError(
|
|
253
|
+
throw new TypeError(
|
|
254
|
+
`Mount option should contains local path or github repo, got ${JSON.stringify(opts)} instead`,
|
|
255
|
+
);
|
|
251
256
|
}
|
|
252
257
|
return await findDeveloperImage(osVersion, opts);
|
|
253
258
|
}
|
|
254
259
|
|
|
255
|
-
|
|
256
260
|
/**
|
|
257
261
|
* Get maxFrameLength from environment variable or use default value
|
|
258
262
|
* @param {number} defaultSize - Default frame size in bytes
|
|
@@ -270,7 +274,14 @@ function getMaxFrameLength(defaultSize) {
|
|
|
270
274
|
}
|
|
271
275
|
|
|
272
276
|
export {
|
|
273
|
-
getConnectedDevices,
|
|
274
|
-
|
|
275
|
-
|
|
277
|
+
getConnectedDevices,
|
|
278
|
+
getOSVersion,
|
|
279
|
+
getDeviceName,
|
|
280
|
+
getDeviceTime,
|
|
281
|
+
startLockdownSession,
|
|
282
|
+
connectPort,
|
|
283
|
+
connectPortSSL,
|
|
284
|
+
getDeviceInfo,
|
|
285
|
+
fetchImageFromGithubRepo,
|
|
286
|
+
getMaxFrameLength,
|
|
276
287
|
};
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import {WebInspectorDecoder} from './transformer/webinspector-decoder';
|
|
2
|
+
import {WebInspectorEncoder} from './transformer/webinspector-encoder';
|
|
3
|
+
import {PlistServiceDecoder} from '../plist-service/transformer/plist-service-decoder';
|
|
4
|
+
import {PlistServiceEncoder} from '../plist-service/transformer/plist-service-encoder';
|
|
5
|
+
import {LengthBasedSplitter} from '../util/transformer/length-based-splitter';
|
|
6
|
+
import {StreamLogger} from '../util/transformer/stream-logger';
|
|
7
7
|
import _ from 'lodash';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
8
|
+
import {util} from '@appium/support';
|
|
9
|
+
import {MB} from '../constants';
|
|
10
|
+
import {log} from '../logger';
|
|
11
|
+
import {BaseServiceSocket} from '../base-service';
|
|
12
|
+
import {getMaxFrameLength} from '../utilities';
|
|
14
13
|
|
|
15
14
|
const WEB_INSPECTOR_SERVICE_NAME = 'com.apple.webinspector';
|
|
16
15
|
const MAX_FRAME_SIZE = 20 * MB;
|
|
17
16
|
|
|
18
17
|
const PARTIAL_MESSAGE_SUPPORT_DEPRECATION_VERSION = 11;
|
|
19
18
|
|
|
20
|
-
function cleanupRpcObject
|
|
19
|
+
function cleanupRpcObject(obj) {
|
|
21
20
|
const isArray = _.isArray(obj);
|
|
22
21
|
if (!_.isPlainObject(obj) && !isArray) {
|
|
23
22
|
return obj;
|
|
@@ -27,12 +26,16 @@ function cleanupRpcObject (obj) {
|
|
|
27
26
|
return _.filter(obj, _.negate(_.isNil));
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
return _.reduce(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
return _.reduce(
|
|
30
|
+
obj,
|
|
31
|
+
(result, value, key) => {
|
|
32
|
+
if (!_.isNil(value)) {
|
|
33
|
+
result[key] = cleanupRpcObject(value);
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
},
|
|
37
|
+
{},
|
|
38
|
+
);
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
/**
|
|
@@ -62,7 +65,7 @@ class WebInspectorService extends BaseServiceSocket {
|
|
|
62
65
|
*
|
|
63
66
|
* @param {Partial<WebInspectorServiceOptions>} opts
|
|
64
67
|
*/
|
|
65
|
-
constructor
|
|
68
|
+
constructor(opts = {}) {
|
|
66
69
|
const {
|
|
67
70
|
majorOsVersion,
|
|
68
71
|
isSimulator = false,
|
|
@@ -76,7 +79,11 @@ class WebInspectorService extends BaseServiceSocket {
|
|
|
76
79
|
super(socketClient);
|
|
77
80
|
|
|
78
81
|
// set the largest fragment size for the socket, if the option is there
|
|
79
|
-
if (
|
|
82
|
+
if (
|
|
83
|
+
_.isFunction(socketClient.setMaxSendFragment) &&
|
|
84
|
+
_.isNumber(socketChunkSize) &&
|
|
85
|
+
socketChunkSize > 0
|
|
86
|
+
) {
|
|
80
87
|
if (socketClient.setMaxSendFragment(socketChunkSize)) {
|
|
81
88
|
log.debug(`Maximum TLS fragment size set to '${socketChunkSize}'`);
|
|
82
89
|
} else {
|
|
@@ -89,7 +96,11 @@ class WebInspectorService extends BaseServiceSocket {
|
|
|
89
96
|
this._isSimulator = isSimulator;
|
|
90
97
|
this._majorOsVersion = majorOsVersion;
|
|
91
98
|
|
|
92
|
-
if (
|
|
99
|
+
if (
|
|
100
|
+
!isSimulator &&
|
|
101
|
+
_.isNumber(majorOsVersion) &&
|
|
102
|
+
majorOsVersion < PARTIAL_MESSAGE_SUPPORT_DEPRECATION_VERSION
|
|
103
|
+
) {
|
|
93
104
|
this._initializePartialMessageSupport(verboseHexDump, maxFrameLength);
|
|
94
105
|
} else {
|
|
95
106
|
this._initializeFullMessageSupport(verboseHexDump, maxFrameLength);
|
|
@@ -103,25 +114,25 @@ class WebInspectorService extends BaseServiceSocket {
|
|
|
103
114
|
* @param {number} maxFrameLength - The maximum size in bytes of a single data frame
|
|
104
115
|
* in the device communication protocol
|
|
105
116
|
*/
|
|
106
|
-
_initializeFullMessageSupport
|
|
117
|
+
_initializeFullMessageSupport(verbose, maxFrameLength) {
|
|
107
118
|
this._decoder = new PlistServiceDecoder();
|
|
108
119
|
this._socketClient
|
|
109
120
|
// log first, in case there is a problem in processing
|
|
110
121
|
.pipe(new StreamLogger(StreamLogger.RECEIVE, verbose))
|
|
111
|
-
.pipe(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
122
|
+
.pipe(
|
|
123
|
+
(this._splitter = new LengthBasedSplitter({
|
|
124
|
+
readableStream: this._socketClient,
|
|
125
|
+
littleEndian: false,
|
|
126
|
+
maxFrameLength,
|
|
127
|
+
lengthFieldOffset: 0,
|
|
128
|
+
lengthFieldLength: 4,
|
|
129
|
+
lengthAdjustment: 4,
|
|
130
|
+
})),
|
|
131
|
+
)
|
|
119
132
|
.pipe(this._decoder);
|
|
120
133
|
|
|
121
134
|
this._encoder = new PlistServiceEncoder();
|
|
122
|
-
this._encoder
|
|
123
|
-
.pipe(new StreamLogger(StreamLogger.SEND, verbose))
|
|
124
|
-
.pipe(this._socketClient);
|
|
135
|
+
this._encoder.pipe(new StreamLogger(StreamLogger.SEND, verbose)).pipe(this._socketClient);
|
|
125
136
|
}
|
|
126
137
|
|
|
127
138
|
/**
|
|
@@ -132,20 +143,22 @@ class WebInspectorService extends BaseServiceSocket {
|
|
|
132
143
|
* @param {number} maxFrameLength - The maximum size in bytes of a single data frame
|
|
133
144
|
* in the device communication protocol
|
|
134
145
|
*/
|
|
135
|
-
_initializePartialMessageSupport
|
|
146
|
+
_initializePartialMessageSupport(verbose, maxFrameLength) {
|
|
136
147
|
// 1MB as buffer for building webinspector full messages. We can increase the value if more buffer is needed
|
|
137
148
|
this._decoder = new WebInspectorDecoder(MB);
|
|
138
149
|
this._socketClient
|
|
139
150
|
// log first, in case there is a problem in processing
|
|
140
151
|
.pipe(new StreamLogger(StreamLogger.RECEIVE, verbose))
|
|
141
|
-
.pipe(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
152
|
+
.pipe(
|
|
153
|
+
(this._splitter = new LengthBasedSplitter({
|
|
154
|
+
readableStream: this._socketClient,
|
|
155
|
+
littleEndian: false,
|
|
156
|
+
maxFrameLength,
|
|
157
|
+
lengthFieldOffset: 0,
|
|
158
|
+
lengthFieldLength: 4,
|
|
159
|
+
lengthAdjustment: 4,
|
|
160
|
+
})),
|
|
161
|
+
)
|
|
149
162
|
.pipe(new PlistServiceDecoder())
|
|
150
163
|
.pipe(this._decoder);
|
|
151
164
|
|
|
@@ -161,7 +174,7 @@ class WebInspectorService extends BaseServiceSocket {
|
|
|
161
174
|
* @param {Object} rpcObject The object that will be sent
|
|
162
175
|
* @throws Will throw an error when the object is null or undefined
|
|
163
176
|
*/
|
|
164
|
-
sendMessage
|
|
177
|
+
sendMessage(rpcObject) {
|
|
165
178
|
if (_.isNil(rpcObject)) {
|
|
166
179
|
throw new Error('Cannot send a null object');
|
|
167
180
|
}
|
|
@@ -219,7 +232,7 @@ class WebInspectorService extends BaseServiceSocket {
|
|
|
219
232
|
* Listen to messages coming from webinspectord
|
|
220
233
|
* @param {MessageCallback} onData
|
|
221
234
|
*/
|
|
222
|
-
listenMessage
|
|
235
|
+
listenMessage(onData) {
|
|
223
236
|
// @ts-ignore _decoder must be present
|
|
224
237
|
this._decoder.on('data', (data) => {
|
|
225
238
|
if (this._verbose) {
|
|
@@ -231,5 +244,5 @@ class WebInspectorService extends BaseServiceSocket {
|
|
|
231
244
|
}
|
|
232
245
|
}
|
|
233
246
|
|
|
234
|
-
export {
|
|
247
|
+
export {WebInspectorService, WEB_INSPECTOR_SERVICE_NAME, cleanupRpcObject};
|
|
235
248
|
export default WebInspectorService;
|