UNPKG

@expo/cli

Version:
204 lines (203 loc) 8.6 kB
/** * Copyright (c) 2021 Expo, Inc. * Copyright (c) 2018 Drifty Co. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "ClientManager", { enumerable: true, get: ()=>ClientManager }); function _stream() { const data = require("stream"); _stream = function() { return data; }; return data; } function _tls() { const data = /*#__PURE__*/ _interopRequireWildcard(require("tls")); _tls = function() { return data; }; return data; } const _afcclient = require("./client/AFCClient"); const _debugserverClient = require("./client/DebugserverClient"); const _installationProxyClient = require("./client/InstallationProxyClient"); const _lockdowndClient = require("./client/LockdowndClient"); const _mobileImageMounterClient = require("./client/MobileImageMounterClient"); const _usbmuxdClient = require("./client/UsbmuxdClient"); const _errors = require("../../../utils/errors"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for(var key in obj){ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } class ClientManager { constructor(pairRecord, device, lockdowndClient){ this.pairRecord = pairRecord; this.device = device; this.lockdowndClient = lockdowndClient; this.connections = [ lockdowndClient.socket ]; } static async create(udid) { const usbmuxClient = new _usbmuxdClient.UsbmuxdClient(_usbmuxdClient.UsbmuxdClient.connectUsbmuxdSocket()); const device = await usbmuxClient.getDevice(udid); const pairRecord = await usbmuxClient.readPairRecord(device.Properties.SerialNumber); const lockdownSocket = await usbmuxClient.connect(device, 62078); const lockdownClient = new _lockdowndClient.LockdowndClient(lockdownSocket); await lockdownClient.doHandshake(pairRecord); return new ClientManager(pairRecord, device, lockdownClient); } async getUsbmuxdClient() { const usbmuxClient = new _usbmuxdClient.UsbmuxdClient(_usbmuxdClient.UsbmuxdClient.connectUsbmuxdSocket()); this.connections.push(usbmuxClient.socket); return usbmuxClient; } async getLockdowndClient() { const usbmuxClient = new _usbmuxdClient.UsbmuxdClient(_usbmuxdClient.UsbmuxdClient.connectUsbmuxdSocket()); const lockdownSocket = await usbmuxClient.connect(this.device, 62078); const lockdownClient = new _lockdowndClient.LockdowndClient(lockdownSocket); this.connections.push(lockdownClient.socket); return lockdownClient; } async getLockdowndClientWithHandshake() { const lockdownClient = await this.getLockdowndClient(); await lockdownClient.doHandshake(this.pairRecord); return lockdownClient; } async getAFCClient() { return this.getServiceClient("com.apple.afc", _afcclient.AFCClient); } async getInstallationProxyClient() { return this.getServiceClient("com.apple.mobile.installation_proxy", _installationProxyClient.InstallationProxyClient); } async getMobileImageMounterClient() { return this.getServiceClient("com.apple.mobile.mobile_image_mounter", _mobileImageMounterClient.MobileImageMounterClient); } async getDebugserverClient() { try { // iOS 14 added support for a secure debug service so try to connect to that first return await this.getServiceClient("com.apple.debugserver.DVTSecureSocketProxy", _debugserverClient.DebugserverClient); } catch { // otherwise, fall back to the previous implementation return this.getServiceClient("com.apple.debugserver", _debugserverClient.DebugserverClient, true); } } async getServiceClient(name, ServiceType, disableSSL = false) { const { port: servicePort , enableServiceSSL } = await this.lockdowndClient.startService(name); const usbmuxClient = new _usbmuxdClient.UsbmuxdClient(_usbmuxdClient.UsbmuxdClient.connectUsbmuxdSocket()); let usbmuxdSocket = await usbmuxClient.connect(this.device, servicePort); if (enableServiceSSL) { const tlsOptions = { rejectUnauthorized: false, secureContext: _tls().createSecureContext({ // Avoid using `secureProtocol` fixing the socket to a single TLS version. // Newer Node versions might not support older TLS versions. // By using the default `minVersion` and `maxVersion` options, // The socket will automatically use the appropriate TLS version. // See: https://nodejs.org/api/tls.html#tlscreatesecurecontextoptions cert: this.pairRecord.RootCertificate, key: this.pairRecord.RootPrivateKey }) }; // Some services seem to not support TLS/SSL after the initial handshake // More info: https://github.com/libimobiledevice/libimobiledevice/issues/793 if (disableSSL) { // According to https://nodejs.org/api/tls.html#tls_tls_connect_options_callback we can // pass any Duplex in to tls.connect instead of a Socket. So we'll use our proxy to keep // the TLS wrapper and underlying usbmuxd socket separate. const proxy = new UsbmuxdProxy(usbmuxdSocket); tlsOptions.socket = proxy; await new Promise((resolve, reject)=>{ const timeoutId = setTimeout(()=>{ reject(new _errors.CommandError("APPLE_DEVICE", "The TLS handshake failed to complete after 5s.")); }, 5000); _tls().connect(tlsOptions, function() { clearTimeout(timeoutId); // After the handshake, we don't need TLS or the proxy anymore, // since we'll just pass in the naked usbmuxd socket to the service client this.destroy(); resolve(); }); }); } else { tlsOptions.socket = usbmuxdSocket; usbmuxdSocket = _tls().connect(tlsOptions); } } const client = new ServiceType(usbmuxdSocket); this.connections.push(client.socket); return client; } end() { for (const socket of this.connections){ // may already be closed try { socket.end(); } catch {} } } } class UsbmuxdProxy extends _stream().Duplex { constructor(usbmuxdSock){ super(); this.usbmuxdSock = usbmuxdSock; this.usbmuxdSock.on("data", (data)=>{ this.push(data); }); } _write(chunk, encoding, callback) { this.usbmuxdSock.write(chunk); callback(); } _read(size) { // Stub so we don't error, since we push everything we get from usbmuxd as it comes in. // TODO: better way to do this? } _destroy() { this.usbmuxdSock.removeAllListeners(); } } //# sourceMappingURL=ClientManager.js.map