@irdk/usbmux 0.2.0 → 0.2.2

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015 Sterling DeMille <sterlingdemille@gmail.com>
3
+ Copyright (c) 2015-2025 Sterling DeMille <sterlingdemille@gmail.com>, Maksim Alzhanov <me@alzhanov.ru>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
@@ -17,4 +17,4 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
17
  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
18
  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
19
  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -52,7 +52,7 @@ irelay --help
52
52
  ## Module Usage
53
53
 
54
54
  ```javascript
55
- var usbmux = require('usbmux');
55
+ import * as usbmux from 'usbmux';
56
56
 
57
57
  // usbmux.Relay()
58
58
  // usbmux.createListener()
@@ -278,7 +278,7 @@ The `Number` field indicates status. 0 is success, other numbers indicate an err
278
278
 
279
279
  The MIT License (MIT)
280
280
 
281
- Copyright (c) 2015 Sterling DeMille &lt;sterlingdemille@gmail.com&gt;
281
+ Copyright (c) 2015-2025 Sterling DeMille &lt;sterlingdemille@gmail.com&gt;, Maksim Alzhanov &lt;me@alzhanov.ru&gt;
282
282
 
283
283
  Permission is hereby granted, free of charge, to any person obtaining a copy of
284
284
  this software and associated documentation files (the "Software"), to deal in
@@ -295,4 +295,4 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
295
295
  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
296
296
  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
297
297
  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
298
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
298
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,317 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // lib/usbmux.ts
30
+ var usbmux_exports = {};
31
+ __export(usbmux_exports, {
32
+ Relay: () => Relay,
33
+ UsbmuxdError: () => UsbmuxdError,
34
+ address: () => address,
35
+ connect: () => connect,
36
+ createListener: () => createListener,
37
+ devices: () => devices,
38
+ findDevice: () => findDevice,
39
+ getTunnel: () => getTunnel,
40
+ protocol: () => protocol
41
+ });
42
+ module.exports = __toCommonJS(usbmux_exports);
43
+ var import_node_net = __toESM(require("net"), 1);
44
+ var import_events = require("events");
45
+ var import_plist = __toESM(require("plist"), 1);
46
+ var import_debug = __toESM(require("debug"), 1);
47
+ var debug = {
48
+ relay: (0, import_debug.default)("usbmux:relay"),
49
+ listen: (0, import_debug.default)("usbmux:listen"),
50
+ connect: (0, import_debug.default)("usbmux:connect")
51
+ };
52
+ var devices = {};
53
+ var address = process.platform === "win32" ? { port: 27015, family: 4 } : { path: "/var/run/usbmuxd" };
54
+ var protocol = function() {
55
+ function pack(payload_obj) {
56
+ const payload_plist = import_plist.default.build(payload_obj);
57
+ const payload_buf = Buffer.from(payload_plist);
58
+ var header = {
59
+ len: payload_buf.length + 16,
60
+ version: 1,
61
+ request: 8,
62
+ tag: 1
63
+ };
64
+ const header_buf = Buffer.alloc(16);
65
+ header_buf.fill(0);
66
+ header_buf.writeUInt32LE(header.len, 0);
67
+ header_buf.writeUInt32LE(header.version, 4);
68
+ header_buf.writeUInt32LE(header.request, 8);
69
+ header_buf.writeUInt32LE(header.tag, 12);
70
+ return Buffer.concat([header_buf, payload_buf]);
71
+ }
72
+ function byteSwap16(val) {
73
+ return (val & 255) << 8 | val >> 8 & 255;
74
+ }
75
+ const listen = pack({
76
+ MessageType: "Listen",
77
+ ClientVersionString: "node-usbmux",
78
+ ProgName: "node-usbmux"
79
+ });
80
+ function connect2(deviceID, port) {
81
+ return pack({
82
+ MessageType: "Connect",
83
+ ClientVersionString: "node-usbmux",
84
+ ProgName: "node-usbmux",
85
+ DeviceID: deviceID,
86
+ PortNumber: byteSwap16(port)
87
+ });
88
+ }
89
+ function makeParser(onComplete) {
90
+ let len, msg;
91
+ return function parse(data) {
92
+ if (!len) {
93
+ len = data.readUInt32LE(0) - 16;
94
+ msg = "";
95
+ data = data.subarray(16);
96
+ if (!data.length) return;
97
+ }
98
+ var body = data.subarray(0, len);
99
+ msg += body;
100
+ len -= body.length;
101
+ if (len === 0) onComplete(import_plist.default.parse(msg));
102
+ data = data.subarray(body.length);
103
+ if (data.length) parse(data);
104
+ };
105
+ }
106
+ return {
107
+ listen,
108
+ connect: connect2,
109
+ makeParser
110
+ };
111
+ }();
112
+ var UsbmuxdError = class extends Error {
113
+ constructor(message, number) {
114
+ if (number) {
115
+ message += ", Err #" + number;
116
+ }
117
+ if (number === 2) message += ": Device isn't connected";
118
+ if (number === 3) message += ": Port isn't available or open";
119
+ if (number === 5) message += ": Malformed request";
120
+ super(message);
121
+ if (number) {
122
+ this.number = number;
123
+ }
124
+ }
125
+ };
126
+ function createListener() {
127
+ const conn = import_node_net.default.connect(address);
128
+ const req = protocol.listen;
129
+ const parse = protocol.makeParser(function onMsgComplete(msg) {
130
+ debug.listen("Response: \n%o", msg);
131
+ if (msg.MessageType === "Result" && msg.Number !== 0) {
132
+ conn.emit("error", new UsbmuxdError("Listen failed", msg.Number));
133
+ conn.end();
134
+ }
135
+ if (msg.MessageType === "Attached") {
136
+ devices[msg.Properties.SerialNumber] = msg.Properties;
137
+ conn.emit("attached", msg.Properties.SerialNumber);
138
+ }
139
+ if (msg.MessageType === "Detached") {
140
+ Object.keys(devices).forEach(function(key) {
141
+ if (devices[key].DeviceID === msg.DeviceID) {
142
+ conn.emit("detached", devices[key].SerialNumber);
143
+ delete devices[key];
144
+ }
145
+ });
146
+ }
147
+ });
148
+ debug.listen("Request: \n%s", req.subarray(16).toString());
149
+ conn.on("data", parse);
150
+ process.nextTick(function() {
151
+ conn.write(req);
152
+ });
153
+ return conn;
154
+ }
155
+ function connect(deviceID, devicePort) {
156
+ return new Promise(function(resolve, reject) {
157
+ const conn = import_node_net.default.connect(address), req = protocol.connect(deviceID, devicePort);
158
+ var parse = protocol.makeParser(function onMsgComplete(msg) {
159
+ debug.connect("Response: \n%o", msg);
160
+ if (msg.MessageType === "Result" && msg.Number === 0) {
161
+ conn.removeListener("data", parse);
162
+ resolve(conn);
163
+ return;
164
+ }
165
+ reject(new UsbmuxdError("Tunnel failed", msg.Number));
166
+ conn.end();
167
+ });
168
+ debug.connect("Request: \n%s", req.subarray(16).toString());
169
+ conn.on("data", parse);
170
+ process.nextTick(function() {
171
+ conn.write(req);
172
+ });
173
+ });
174
+ }
175
+ var Relay = class extends import_events.EventEmitter {
176
+ constructor(devicePort, relayPort, opts) {
177
+ super();
178
+ /**
179
+ * Stops the relay
180
+ */
181
+ this.stop = function() {
182
+ this._listener.end();
183
+ this._server.close();
184
+ };
185
+ /**
186
+ * Debugging wrapper for emits
187
+ */
188
+ this._emit = function(event, data) {
189
+ debug.relay("Emit: %s", event + (data ? ", Data: " + data : ""));
190
+ this.emit(event, data);
191
+ };
192
+ /**
193
+ * Starts a usbmuxd listener
194
+ *
195
+ * Relay will start searching for connected devices and issue a warning if a
196
+ * device is not found within the timeout. If/when a device is found, it will
197
+ * emit a ready event.
198
+ *
199
+ * Listener events (attach, detach, error) are passed through as relay events.
200
+ */
201
+ this._startListener = function(timeout) {
202
+ var _this = this;
203
+ var timer = setTimeout(function() {
204
+ if (!_this._udid && !Object.keys(devices).length) {
205
+ _this._emit("warning", new Error("No devices connected"));
206
+ }
207
+ if (_this._udid && !devices[_this._udid]) {
208
+ _this._emit("warning", new Error("Requested device not connected"));
209
+ }
210
+ }, timeout || 1e3);
211
+ function readyCheck(udid) {
212
+ if (_this._udid && _this._udid !== udid) return;
213
+ _this._emit("ready", udid);
214
+ _this._listener.removeListener("attached", readyCheck);
215
+ clearTimeout(timer);
216
+ }
217
+ this._listener = createListener().on("attached", readyCheck).on("attached", _this._emit.bind(this, "attached")).on("detached", _this._emit.bind(this, "detached")).on("error", _this._emit.bind(this, "error"));
218
+ };
219
+ /**
220
+ * Start local TCP server that will pipe to the usbmuxd tunnel
221
+ *
222
+ * Server events (close and error) are passed through as relay events.
223
+ */
224
+ this._startServer = function() {
225
+ var _this = this;
226
+ this._server = import_node_net.default.createServer(this._handler.bind(this)).on("close", _this._emit.bind(this, "close")).on("error", function(err) {
227
+ _this._listener.end();
228
+ _this._emit("error", err);
229
+ }).listen(this._relayPort);
230
+ };
231
+ /**
232
+ * Handle & pipe connections from local server
233
+ *
234
+ * Fires error events and connection begin / disconnect events
235
+ */
236
+ this._handler = function(conn) {
237
+ if (!Object.keys(devices).length) {
238
+ this._emit("error", new Error("No devices connected"));
239
+ conn.end();
240
+ return;
241
+ }
242
+ if (this._udid && !devices[this._udid]) {
243
+ this._emit("error", new Error("Requested device not connected"));
244
+ conn.end();
245
+ return;
246
+ }
247
+ var _this = this, udid = this._udid || Object.keys(devices)[0], deviceID = devices[udid].DeviceID;
248
+ connect(deviceID, this._devicePort).then(function(tunnel) {
249
+ conn.pipe(tunnel).pipe(conn);
250
+ _this._emit("connect");
251
+ conn.on("end", function() {
252
+ _this._emit("disconnect");
253
+ tunnel.end();
254
+ conn.end();
255
+ });
256
+ conn.on("error", function() {
257
+ tunnel.end();
258
+ conn.end();
259
+ });
260
+ }).catch(function(err) {
261
+ _this._emit("error", err);
262
+ conn.end();
263
+ });
264
+ };
265
+ this._devicePort = devicePort;
266
+ this._relayPort = relayPort;
267
+ opts = opts || {};
268
+ this._udid = opts.udid;
269
+ this._startListener(opts.timeout || 1e3);
270
+ this._startServer();
271
+ }
272
+ };
273
+ function findDevice(opts) {
274
+ return new Promise(function(resolve, reject) {
275
+ var listener = createListener();
276
+ opts = opts || {};
277
+ var timer = setTimeout(function() {
278
+ listener.end();
279
+ opts.udid ? reject(new Error("Requested device not connected")) : reject(new Error("No devices connected"));
280
+ }, opts.timeout || 1e3);
281
+ listener.on("attached", function(udid) {
282
+ if (opts.udid && opts.udid !== udid) return;
283
+ listener.end();
284
+ clearTimeout(timer);
285
+ resolve(devices[udid].DeviceID);
286
+ });
287
+ });
288
+ }
289
+ async function getTunnel(devicePort, opts) {
290
+ opts = opts || {};
291
+ let udid;
292
+ let deviceID;
293
+ if (opts.udid && devices[opts.udid]) {
294
+ deviceID = devices[opts.udid].DeviceID;
295
+ return connect(deviceID, devicePort);
296
+ }
297
+ if (!opts.udid && Object.keys(devices).length) {
298
+ udid = Object.keys(devices)[0];
299
+ deviceID = devices[udid].DeviceID;
300
+ return connect(deviceID, devicePort);
301
+ }
302
+ const deviceID_2 = await findDevice(opts);
303
+ return await connect(deviceID_2, devicePort);
304
+ }
305
+ // Annotate the CommonJS export names for ESM import in node:
306
+ 0 && (module.exports = {
307
+ Relay,
308
+ UsbmuxdError,
309
+ address,
310
+ connect,
311
+ createListener,
312
+ devices,
313
+ findDevice,
314
+ getTunnel,
315
+ protocol
316
+ });
317
+ //# sourceMappingURL=usbmux.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../lib/usbmux.ts"],"sourcesContent":["import net from \"node:net\";\nimport { EventEmitter } from \"events\";\n\nimport plist from \"plist\";\n\n/**\n * Debugging\n * set with DEBUG=usbmux:* env variable\n *\n * on windows cmd set with: cmd /C \"SET DEBUG=usbmux:* && node script.js\"\n */\nimport bug from \"debug\";\nconst debug = {\n relay: bug(\"usbmux:relay\"),\n listen: bug(\"usbmux:listen\"),\n connect: bug(\"usbmux:connect\"),\n};\n\ntype Device = {\n ConnectionType: string;\n DeviceID: DeviceId;\n LocationID: number;\n ProductID: number;\n SerialNumber: string;\n};\n/**\n * Keep track of connected devices\n *\n * Maps device UDID to device properties, ie:\n * '22226dd59aaac687f555f8521f8ffddac32d394b': {\n * ConnectionType: 'USB',\n * DeviceID: 19,\n * LocationID: 0,\n * ProductID: 4776,\n * SerialNumber: '22226dd59aaac687f555f8521f8ffddac32d394b'\n * }\n *\n * Devices are added and removed to this obj only by createListener()\n *\n */\nexport const devices: Record<string, Device> = {};\n\n/**\n * usbmuxd address\n *\n * OSX usbmuxd listens on a unix socket at /var/run/usbmuxd\n * Windows usbmuxd listens on port 27015\n *\n * libimobiledevice[1] looks like it operates at /var/run/usbmuxd too, but if\n * your usbmuxd is listening somewhere else you'll need to set this manually.\n *\n * [1] github.com/libimobiledevice/usbmuxd\n */\nexport const address =\n process.platform === \"win32\"\n ? { port: 27015, family: 4 }\n : { path: \"/var/run/usbmuxd\" };\n\n/**\n * Exposes methods for dealing with usbmuxd protocol messages (send/receive)\n *\n * The usbmuxd message protocol has 2 versions. V1 doesn't look like its used\n * anymore. V2 is a header + plist format like this:\n *\n * Header:\n * UInt32LE Length - is the length of the header + plist (16 + plist.length)\n * UInt32LE Version - is 0 for binary version, 1 for plist version\n * UInt32LE Request - is always 8, for plist? from rcg4u/iphonessh\n * UInt32LE Tag - is always 1, ? from rcg4u/iphonessh\n *\n * Plist:\n * <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\"\n * \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n * <plist version=\"1.0\">\n * <dict>\n * <key>MessageType</key>\n * <string>Listen</string>\n * <key>ClientVersionString</key>\n * <string>node-usbmux</string>\n * <key>ProgName</key>\n * <string>node-usbmux</string>\n * </dict>\n * </plist>\n *\n * References:\n * - https://github.com/rcg4u/iphonessh\n * - https://www.theiphonewiki.com/wiki/Usbmux (binary protocol)\n */\n\ntype DeviceId = number;\ntype UsbMuxPlist =\n | {\n MessageType: \"Result\";\n Number: number;\n }\n | {\n MessageType: \"Attached\";\n Number: number;\n Properties: Device;\n }\n | { MessageType: \"Detached\"; Number: number; DeviceID: DeviceId };\n\nexport const protocol = (function () {\n /**\n * Pack a request object into a buffer for usbmuxd\n */\n function pack(payload_obj: plist.PlistValue): Buffer {\n const payload_plist = plist.build(payload_obj);\n const payload_buf = Buffer.from(payload_plist);\n\n var header = {\n len: payload_buf.length + 16,\n version: 1,\n request: 8,\n tag: 1,\n };\n\n const header_buf = Buffer.alloc(16);\n header_buf.fill(0);\n header_buf.writeUInt32LE(header.len, 0);\n header_buf.writeUInt32LE(header.version, 4);\n header_buf.writeUInt32LE(header.request, 8);\n header_buf.writeUInt32LE(header.tag, 12);\n\n return Buffer.concat([header_buf, payload_buf]);\n }\n\n /**\n * Swap endianness of a 16bit value\n */\n function byteSwap16(val: number) {\n return ((val & 0xff) << 8) | ((val >> 8) & 0xff);\n }\n\n /**\n * Listen request\n */\n const listen: Buffer = pack({\n MessageType: \"Listen\",\n ClientVersionString: \"node-usbmux\",\n ProgName: \"node-usbmux\",\n });\n\n /**\n * Connect request\n *\n * Note: PortNumber must be network-endian, so it gets byte swapped here\n */\n function connect(deviceID: DeviceId, port: number): Buffer {\n return pack({\n MessageType: \"Connect\",\n ClientVersionString: \"node-usbmux\",\n ProgName: \"node-usbmux\",\n DeviceID: deviceID,\n PortNumber: byteSwap16(port),\n });\n }\n\n /**\n * Creates a function that will parse messages from data events\n *\n * net.Socket data events sometimes break up the incoming message across\n * multiple events, making it necessary to combine them. This parser function\n * assembles messages using the length given in the message header and calls\n * the onComplete callback as new messages are assembled. Sometime multiple\n * messages will be within a single data buffer too.\n */\n function makeParser(\n onComplete: (msg: UsbMuxPlist) => void,\n ): (data: Buffer) => void {\n // Store status (remaining message length & msg text) of partial messages\n // across multiple calls to the parse function\n let len: number, msg: string;\n\n return function parse(data: Buffer) {\n // Check if this data represents a new incoming message or is part of an\n // existing partially completed message\n if (!len) {\n // The length of the message's body is the total length (the first\n // UInt32LE in the header) minus the length of header itself (16)\n len = data.readUInt32LE(0) - 16;\n msg = \"\";\n\n // If there is data beyond the header then continue adding data to msg\n data = data.subarray(16);\n if (!data.length) return;\n }\n\n // Add in data until our remaining length is used up\n var body = data.subarray(0, len);\n msg += body;\n len -= body.length;\n\n // If msg is finished, convert plist to obj and run callback\n if (len === 0) onComplete(plist.parse(msg) as UsbMuxPlist);\n\n // If there is any data left over that means there is another message\n // so we need to run this parse fct again using the rest of the data\n data = data.subarray(body.length);\n if (data.length) parse(data);\n };\n }\n\n // Exposed methods\n return {\n listen: listen,\n connect: connect,\n makeParser: makeParser,\n };\n})();\n\n/**\n * Custom usbmuxd error\n *\n * There's no documentation for usbmuxd responses, but I think I've figured\n * out these result numbers:\n * 0 - Success\n * 2 - Device requested isn't connected\n * 3 - Port requested isn't available \\ open\n * 5 - Malformed request\n */\nexport class UsbmuxdError extends Error {\n number: number;\n\n constructor(message: string, number: number) {\n if (number) {\n message += \", Err #\" + number;\n }\n if (number === 2) message += \": Device isn't connected\";\n if (number === 3) message += \": Port isn't available or open\";\n if (number === 5) message += \": Malformed request\";\n super(message);\n if (number) {\n this.number = number;\n }\n }\n}\n\n/**\n * Connects to usbmuxd and listens for ios devices\n *\n * This connection stays open, listening as devices are plugged/unplugged and\n * cant be upgraded into a tcp tunnel. You have to start a second connection\n * with connect() to actually make tunnel.\n *\n * @return {net.Socket} - Socket with 2 bolted on events, attached & detached:\n *\n * Fires when devices are plugged in or first found by the listener\n * @event net.Socket#attached\n * @type {string} - UDID\n *\n * Fires when devices are unplugged\n * @event net.Socket#detached\n * @type {string} - UDID\n */\nexport function createListener(): net.Socket {\n const conn = net.connect(address);\n const req = protocol.listen;\n\n /**\n * Handle complete messages from usbmuxd\n * @function\n */\n const parse = protocol.makeParser(function onMsgComplete(msg) {\n debug.listen(\"Response: \\n%o\", msg);\n\n // first response always acknowledges / denies the request:\n if (msg.MessageType === \"Result\" && msg.Number !== 0) {\n conn.emit(\"error\", new UsbmuxdError(\"Listen failed\", msg.Number));\n conn.end();\n }\n\n // subsequent responses report on connected device status:\n if (msg.MessageType === \"Attached\") {\n devices[msg.Properties.SerialNumber] = msg.Properties;\n conn.emit(\"attached\", msg.Properties.SerialNumber);\n }\n\n if (msg.MessageType === \"Detached\") {\n // given msg.DeviceID, find matching device and remove it\n Object.keys(devices).forEach(function (key) {\n if (devices[key].DeviceID === msg.DeviceID) {\n conn.emit(\"detached\", devices[key].SerialNumber);\n delete devices[key];\n }\n });\n }\n });\n\n debug.listen(\"Request: \\n%s\", req.subarray(16).toString());\n\n conn.on(\"data\", parse);\n process.nextTick(function () {\n conn.write(req);\n });\n\n return conn;\n}\n\n/**\n * Connects to a device through usbmuxd for a tunneled tcp connection\n */\nexport function connect(\n deviceID: DeviceId,\n devicePort: number,\n): Promise<net.Socket> {\n return new Promise(function (resolve, reject) {\n const conn = net.connect(address),\n req = protocol.connect(deviceID, devicePort);\n\n /**\n * Handle complete messages from usbmuxd\n * @function\n */\n var parse = protocol.makeParser(function onMsgComplete(msg) {\n debug.connect(\"Response: \\n%o\", msg);\n\n if (msg.MessageType === \"Result\" && msg.Number === 0) {\n conn.removeListener(\"data\", parse);\n resolve(conn);\n return;\n }\n\n // anything other response means it failed\n reject(new UsbmuxdError(\"Tunnel failed\", msg.Number));\n conn.end();\n });\n\n debug.connect(\"Request: \\n%s\", req.subarray(16).toString());\n\n conn.on(\"data\", parse);\n process.nextTick(function () {\n conn.write(req);\n });\n });\n}\n\ntype RelayOpts = {\n timeout?: number;\n udid?: string;\n};\n/**\n * Creates a new tcp relay to a port on connected usb device\n *\n * @constructor\n * @param {integer} devicePort - Port to connect to on device\n * @param {integer} relayPort - Local port that will listen as relay\n * @param {object} [opts] - Options\n * @param {integer} [opts.timeout=1000] - Search time (ms) before warning\n * @param {string} [opts.udid] - UDID of specific device to connect to\n *\n * @public\n */\nexport class Relay extends EventEmitter {\n _devicePort: number;\n _relayPort: number;\n _udid?: string;\n constructor(devicePort: number, relayPort: number, opts: RelayOpts) {\n super();\n this._devicePort = devicePort;\n this._relayPort = relayPort;\n\n opts = opts || {};\n this._udid = opts.udid;\n\n this._startListener(opts.timeout || 1000);\n this._startServer();\n }\n /**\n * Stops the relay\n */\n stop = function () {\n this._listener.end();\n this._server.close();\n };\n /**\n * Debugging wrapper for emits\n */\n _emit = function (event: string, data: any) {\n debug.relay(\"Emit: %s\", event + (data ? \", Data: \" + data : \"\"));\n this.emit(event, data);\n };\n /**\n * Starts a usbmuxd listener\n *\n * Relay will start searching for connected devices and issue a warning if a\n * device is not found within the timeout. If/when a device is found, it will\n * emit a ready event.\n *\n * Listener events (attach, detach, error) are passed through as relay events.\n */\n _startListener = function (timeout: number) {\n var _this = this;\n\n var timer = setTimeout(function () {\n // no UDID was given and no devices found yet\n if (!_this._udid && !Object.keys(devices).length) {\n _this._emit(\"warning\", new Error(\"No devices connected\"));\n }\n // UDID was given, but that device is not connected\n if (_this._udid && !devices[_this._udid]) {\n _this._emit(\"warning\", new Error(\"Requested device not connected\"));\n }\n }, timeout || 1000);\n\n function readyCheck(udid: string) {\n if (_this._udid && _this._udid !== udid) return;\n _this._emit(\"ready\", udid);\n _this._listener.removeListener(\"attached\", readyCheck);\n clearTimeout(timer);\n }\n\n this._listener = createListener()\n .on(\"attached\", readyCheck)\n .on(\"attached\", _this._emit.bind(this, \"attached\"))\n .on(\"detached\", _this._emit.bind(this, \"detached\"))\n .on(\"error\", _this._emit.bind(this, \"error\"));\n };\n /**\n * Start local TCP server that will pipe to the usbmuxd tunnel\n *\n * Server events (close and error) are passed through as relay events.\n */\n _startServer = function () {\n var _this = this;\n this._server = net\n .createServer(this._handler.bind(this))\n .on(\"close\", _this._emit.bind(this, \"close\"))\n .on(\"error\", function (err) {\n _this._listener.end();\n _this._emit(\"error\", err);\n })\n .listen(this._relayPort);\n };\n /**\n * Handle & pipe connections from local server\n *\n * Fires error events and connection begin / disconnect events\n */\n _handler = function (conn: net.Socket) {\n // emit error if there are no devices connected\n if (!Object.keys(devices).length) {\n this._emit(\"error\", new Error(\"No devices connected\"));\n conn.end();\n return;\n }\n\n // emit error if a udid was specified but that device isn't connected\n if (this._udid && !devices[this._udid]) {\n this._emit(\"error\", new Error(\"Requested device not connected\"));\n conn.end();\n return;\n }\n\n // Use specified device or choose one from available devices\n var _this = this,\n udid = this._udid || Object.keys(devices)[0],\n deviceID = devices[udid].DeviceID;\n\n connect(deviceID, this._devicePort)\n .then(function (tunnel) {\n // pipe connection & tunnel together\n conn.pipe(tunnel).pipe(conn);\n\n _this._emit(\"connect\");\n\n conn.on(\"end\", function () {\n _this._emit(\"disconnect\");\n tunnel.end();\n conn.end();\n });\n\n conn.on(\"error\", function () {\n tunnel.end();\n conn.end();\n });\n })\n .catch(function (err) {\n _this._emit(\"error\", err);\n conn.end();\n });\n };\n}\n\n/**\n * Find a device (specified or not) within a timeout\n *\n * Usbmuxd has IDs it assigned to devices as they are plugged in. The IDs\n * change as devices are unpplugged and plugged back in, so even if we have a\n * UDID we need to get the current ID from usbmuxd before we can connect.\n */\nexport function findDevice(opts: RelayOpts): Promise<number> {\n return new Promise(function (resolve, reject) {\n var listener = createListener();\n opts = opts || {};\n\n var timer = setTimeout(function () {\n listener.end();\n opts.udid\n ? reject(new Error(\"Requested device not connected\"))\n : reject(new Error(\"No devices connected\"));\n }, opts.timeout || 1000);\n\n listener.on(\"attached\", function (udid) {\n if (opts.udid && opts.udid !== udid) return;\n listener.end();\n clearTimeout(timer);\n resolve(devices[udid].DeviceID);\n });\n });\n}\n\n/**\n * Get a tunneled connection to a device (specified or not) within a timeout\n */\nexport async function getTunnel(\n devicePort: number,\n opts: RelayOpts,\n): Promise<net.Socket> {\n opts = opts || {};\n let udid: string;\n let deviceID: DeviceId;\n\n // If UDID was specified and that device's DeviceID is known, connect to it\n if (opts.udid && devices[opts.udid]) {\n deviceID = devices[opts.udid].DeviceID;\n return connect(deviceID, devicePort);\n }\n\n // If no UDID given, connect to any known device\n // (random because no key order, but there's probably only 1 option anyways)\n if (!opts.udid && Object.keys(devices).length) {\n udid = Object.keys(devices)[0];\n deviceID = devices[udid].DeviceID;\n return connect(deviceID, devicePort);\n }\n\n // - Try to find and connect to requested the device (given opts.UDID),\n // - or find and connect to any device (no opts.UDID given)\n const deviceID_2 = await findDevice(opts);\n return await connect(deviceID_2, devicePort);\n}\n"],"mappings":"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","names":["bug","plist","connect","net"]}
@@ -0,0 +1,196 @@
1
+ import net from 'node:net';
2
+ import { EventEmitter } from 'events';
3
+
4
+ type Device = {
5
+ ConnectionType: string;
6
+ DeviceID: DeviceId;
7
+ LocationID: number;
8
+ ProductID: number;
9
+ SerialNumber: string;
10
+ };
11
+ /**
12
+ * Keep track of connected devices
13
+ *
14
+ * Maps device UDID to device properties, ie:
15
+ * '22226dd59aaac687f555f8521f8ffddac32d394b': {
16
+ * ConnectionType: 'USB',
17
+ * DeviceID: 19,
18
+ * LocationID: 0,
19
+ * ProductID: 4776,
20
+ * SerialNumber: '22226dd59aaac687f555f8521f8ffddac32d394b'
21
+ * }
22
+ *
23
+ * Devices are added and removed to this obj only by createListener()
24
+ *
25
+ */
26
+ declare const devices: Record<string, Device>;
27
+ /**
28
+ * usbmuxd address
29
+ *
30
+ * OSX usbmuxd listens on a unix socket at /var/run/usbmuxd
31
+ * Windows usbmuxd listens on port 27015
32
+ *
33
+ * libimobiledevice[1] looks like it operates at /var/run/usbmuxd too, but if
34
+ * your usbmuxd is listening somewhere else you'll need to set this manually.
35
+ *
36
+ * [1] github.com/libimobiledevice/usbmuxd
37
+ */
38
+ declare const address: {
39
+ port: number;
40
+ family: number;
41
+ path?: undefined;
42
+ } | {
43
+ path: string;
44
+ port?: undefined;
45
+ family?: undefined;
46
+ };
47
+ /**
48
+ * Exposes methods for dealing with usbmuxd protocol messages (send/receive)
49
+ *
50
+ * The usbmuxd message protocol has 2 versions. V1 doesn't look like its used
51
+ * anymore. V2 is a header + plist format like this:
52
+ *
53
+ * Header:
54
+ * UInt32LE Length - is the length of the header + plist (16 + plist.length)
55
+ * UInt32LE Version - is 0 for binary version, 1 for plist version
56
+ * UInt32LE Request - is always 8, for plist? from rcg4u/iphonessh
57
+ * UInt32LE Tag - is always 1, ? from rcg4u/iphonessh
58
+ *
59
+ * Plist:
60
+ * <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
61
+ * "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
62
+ * <plist version="1.0">
63
+ * <dict>
64
+ * <key>MessageType</key>
65
+ * <string>Listen</string>
66
+ * <key>ClientVersionString</key>
67
+ * <string>node-usbmux</string>
68
+ * <key>ProgName</key>
69
+ * <string>node-usbmux</string>
70
+ * </dict>
71
+ * </plist>
72
+ *
73
+ * References:
74
+ * - https://github.com/rcg4u/iphonessh
75
+ * - https://www.theiphonewiki.com/wiki/Usbmux (binary protocol)
76
+ */
77
+ type DeviceId = number;
78
+ type UsbMuxPlist = {
79
+ MessageType: "Result";
80
+ Number: number;
81
+ } | {
82
+ MessageType: "Attached";
83
+ Number: number;
84
+ Properties: Device;
85
+ } | {
86
+ MessageType: "Detached";
87
+ Number: number;
88
+ DeviceID: DeviceId;
89
+ };
90
+ declare const protocol: {
91
+ listen: Buffer<ArrayBufferLike>;
92
+ connect: (deviceID: DeviceId, port: number) => Buffer;
93
+ makeParser: (onComplete: (msg: UsbMuxPlist) => void) => (data: Buffer) => void;
94
+ };
95
+ /**
96
+ * Custom usbmuxd error
97
+ *
98
+ * There's no documentation for usbmuxd responses, but I think I've figured
99
+ * out these result numbers:
100
+ * 0 - Success
101
+ * 2 - Device requested isn't connected
102
+ * 3 - Port requested isn't available \ open
103
+ * 5 - Malformed request
104
+ */
105
+ declare class UsbmuxdError extends Error {
106
+ number: number;
107
+ constructor(message: string, number: number);
108
+ }
109
+ /**
110
+ * Connects to usbmuxd and listens for ios devices
111
+ *
112
+ * This connection stays open, listening as devices are plugged/unplugged and
113
+ * cant be upgraded into a tcp tunnel. You have to start a second connection
114
+ * with connect() to actually make tunnel.
115
+ *
116
+ * @return {net.Socket} - Socket with 2 bolted on events, attached & detached:
117
+ *
118
+ * Fires when devices are plugged in or first found by the listener
119
+ * @event net.Socket#attached
120
+ * @type {string} - UDID
121
+ *
122
+ * Fires when devices are unplugged
123
+ * @event net.Socket#detached
124
+ * @type {string} - UDID
125
+ */
126
+ declare function createListener(): net.Socket;
127
+ /**
128
+ * Connects to a device through usbmuxd for a tunneled tcp connection
129
+ */
130
+ declare function connect(deviceID: DeviceId, devicePort: number): Promise<net.Socket>;
131
+ type RelayOpts = {
132
+ timeout?: number;
133
+ udid?: string;
134
+ };
135
+ /**
136
+ * Creates a new tcp relay to a port on connected usb device
137
+ *
138
+ * @constructor
139
+ * @param {integer} devicePort - Port to connect to on device
140
+ * @param {integer} relayPort - Local port that will listen as relay
141
+ * @param {object} [opts] - Options
142
+ * @param {integer} [opts.timeout=1000] - Search time (ms) before warning
143
+ * @param {string} [opts.udid] - UDID of specific device to connect to
144
+ *
145
+ * @public
146
+ */
147
+ declare class Relay extends EventEmitter {
148
+ _devicePort: number;
149
+ _relayPort: number;
150
+ _udid?: string;
151
+ constructor(devicePort: number, relayPort: number, opts: RelayOpts);
152
+ /**
153
+ * Stops the relay
154
+ */
155
+ stop: () => void;
156
+ /**
157
+ * Debugging wrapper for emits
158
+ */
159
+ _emit: (event: string, data: any) => void;
160
+ /**
161
+ * Starts a usbmuxd listener
162
+ *
163
+ * Relay will start searching for connected devices and issue a warning if a
164
+ * device is not found within the timeout. If/when a device is found, it will
165
+ * emit a ready event.
166
+ *
167
+ * Listener events (attach, detach, error) are passed through as relay events.
168
+ */
169
+ _startListener: (timeout: number) => void;
170
+ /**
171
+ * Start local TCP server that will pipe to the usbmuxd tunnel
172
+ *
173
+ * Server events (close and error) are passed through as relay events.
174
+ */
175
+ _startServer: () => void;
176
+ /**
177
+ * Handle & pipe connections from local server
178
+ *
179
+ * Fires error events and connection begin / disconnect events
180
+ */
181
+ _handler: (conn: net.Socket) => void;
182
+ }
183
+ /**
184
+ * Find a device (specified or not) within a timeout
185
+ *
186
+ * Usbmuxd has IDs it assigned to devices as they are plugged in. The IDs
187
+ * change as devices are unpplugged and plugged back in, so even if we have a
188
+ * UDID we need to get the current ID from usbmuxd before we can connect.
189
+ */
190
+ declare function findDevice(opts: RelayOpts): Promise<number>;
191
+ /**
192
+ * Get a tunneled connection to a device (specified or not) within a timeout
193
+ */
194
+ declare function getTunnel(devicePort: number, opts: RelayOpts): Promise<net.Socket>;
195
+
196
+ export { Relay, UsbmuxdError, address, connect, createListener, devices, findDevice, getTunnel, protocol };