Add physical iOS support to internal build
Summary: Adds support for physical iOS devices, when the necessary dependencies are present. Unfortunately these aren't open sourced yet so the open source build won't get this feature yet. Reviewed By: priteshrnandgaonkar Differential Revision: D13001473 fbshipit-source-id: d8c2bcd53b7972bec676717c8af0112800b918d0
This commit is contained in:
committed by
Facebook Github Bot
parent
8d93946739
commit
40f50d48e3
@@ -18,7 +18,7 @@
|
|||||||
#import "FlipperClient+Testing.h"
|
#import "FlipperClient+Testing.h"
|
||||||
|
|
||||||
#if !TARGET_OS_SIMULATOR
|
#if !TARGET_OS_SIMULATOR
|
||||||
//#import <FKPortForwarding/FKPortForwardingServer.h>
|
#import <FKPortForwarding/FKPortForwardingServer.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using WrapperPlugin = facebook::flipper::FlipperCppWrapperPlugin;
|
using WrapperPlugin = facebook::flipper::FlipperCppWrapperPlugin;
|
||||||
@@ -28,7 +28,8 @@ using WrapperPlugin = facebook::flipper::FlipperCppWrapperPlugin;
|
|||||||
folly::ScopedEventBaseThread sonarThread;
|
folly::ScopedEventBaseThread sonarThread;
|
||||||
folly::ScopedEventBaseThread connectionThread;
|
folly::ScopedEventBaseThread connectionThread;
|
||||||
#if !TARGET_OS_SIMULATOR
|
#if !TARGET_OS_SIMULATOR
|
||||||
// FKPortForwardingServer *_server;
|
FKPortForwardingServer *_secureServer;
|
||||||
|
FKPortForwardingServer *_insecureServer;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,9 +120,12 @@ using WrapperPlugin = facebook::flipper::FlipperCppWrapperPlugin;
|
|||||||
- (void)start;
|
- (void)start;
|
||||||
{
|
{
|
||||||
#if !TARGET_OS_SIMULATOR
|
#if !TARGET_OS_SIMULATOR
|
||||||
// _server = [FKPortForwardingServer new];
|
_secureServer = [FKPortForwardingServer new];
|
||||||
// [_server forwardConnectionsFromPort:8088];
|
[_secureServer forwardConnectionsFromPort:8088];
|
||||||
// [_server listenForMultiplexingChannelOnPort:8078];
|
[_secureServer listenForMultiplexingChannelOnPort:8078];
|
||||||
|
_insecureServer = [FKPortForwardingServer new];
|
||||||
|
[_insecureServer forwardConnectionsFromPort:8089];
|
||||||
|
[_insecureServer listenForMultiplexingChannelOnPort:8079];
|
||||||
#endif
|
#endif
|
||||||
_cppClient->start();
|
_cppClient->start();
|
||||||
}
|
}
|
||||||
@@ -131,8 +135,10 @@ using WrapperPlugin = facebook::flipper::FlipperCppWrapperPlugin;
|
|||||||
{
|
{
|
||||||
_cppClient->stop();
|
_cppClient->stop();
|
||||||
#if !TARGET_OS_SIMULATOR
|
#if !TARGET_OS_SIMULATOR
|
||||||
// [_server close];
|
[_secureServer close];
|
||||||
// _server = nil;
|
_secureServer = nil;
|
||||||
|
[_insecureServer close];
|
||||||
|
_insecureServer = nil;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ export default class IOSDevice extends BaseDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startLogListener(retries: number = 3) {
|
startLogListener(retries: number = 3) {
|
||||||
|
if (this.deviceType === 'physical') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (retries === 0) {
|
if (retries === 0) {
|
||||||
console.error('Attaching iOS log listener continuously failed.');
|
console.error('Attaching iOS log listener continuously failed.');
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -5,13 +5,18 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type {ChildProcess} from 'child_process';
|
||||||
import type {Store} from '../reducers/index.js';
|
import type {Store} from '../reducers/index.js';
|
||||||
import type Logger from '../fb-stubs/Logger.js';
|
import type Logger from '../fb-stubs/Logger.js';
|
||||||
|
import type {DeviceType} from '../devices/BaseDevice';
|
||||||
|
|
||||||
import {promisify} from 'util';
|
import {promisify} from 'util';
|
||||||
|
import path from 'path';
|
||||||
import child_process from 'child_process';
|
import child_process from 'child_process';
|
||||||
const execFile = promisify(child_process.execFile);
|
const execFile = child_process.execFile;
|
||||||
import IOSDevice from '../devices/IOSDevice';
|
import IOSDevice from '../devices/IOSDevice';
|
||||||
|
import iosUtil from '../fb-stubs/iOSContainerUtility';
|
||||||
|
import isProduction from '../utils/isProduction.js';
|
||||||
|
|
||||||
type iOSSimulatorDevice = {|
|
type iOSSimulatorDevice = {|
|
||||||
state: 'Booted' | 'Shutdown' | 'Shutting Down',
|
state: 'Booted' | 'Shutdown' | 'Shutting Down',
|
||||||
@@ -21,66 +26,106 @@ type iOSSimulatorDevice = {|
|
|||||||
udid: string,
|
udid: string,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
type IOSDeviceMap = {[id: string]: Array<iOSSimulatorDevice>};
|
type IOSDeviceParams = {udid: string, type: DeviceType, name: string};
|
||||||
|
|
||||||
function querySimulatorDevices(store: Store): Promise<IOSDeviceMap> {
|
const portforwardingClient = isProduction()
|
||||||
|
? path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'PortForwardingMacApp.app/Contents/MacOS/PortForwardingMacApp',
|
||||||
|
)
|
||||||
|
: 'PortForwardingMacApp.app/Contents/MacOS/PortForwardingMacApp';
|
||||||
|
|
||||||
|
function forwardPort(port: number, multiplexChannelPort: number) {
|
||||||
|
return execFile(portforwardingClient, [
|
||||||
|
`-portForward=${port}`,
|
||||||
|
`-multiplexChannelPort=${multiplexChannelPort}`,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
// start port forwarding server for real device connections
|
||||||
|
const portForwarders: Array<ChildProcess> = [
|
||||||
|
forwardPort(8089, 8079),
|
||||||
|
forwardPort(8088, 8078),
|
||||||
|
];
|
||||||
|
window.addEventListener('beforeunload', () => {
|
||||||
|
portForwarders.forEach(process => process.kill());
|
||||||
|
});
|
||||||
|
|
||||||
|
function queryDevices(store: Store): Promise<void> {
|
||||||
const {connections} = store.getState();
|
const {connections} = store.getState();
|
||||||
|
const currentDeviceIDs: Set<string> = new Set(
|
||||||
|
connections.devices
|
||||||
|
.filter(device => device instanceof IOSDevice)
|
||||||
|
.map(device => device.serial),
|
||||||
|
);
|
||||||
|
return Promise.all([getActiveSimulators(), getActiveDevices()])
|
||||||
|
.then(([a, b]) => a.concat(b))
|
||||||
|
.then(activeDevices => {
|
||||||
|
for (const {udid, type, name} of activeDevices) {
|
||||||
|
if (currentDeviceIDs.has(udid)) {
|
||||||
|
currentDeviceIDs.delete(udid);
|
||||||
|
} else {
|
||||||
|
store.dispatch({
|
||||||
|
type: 'REGISTER_DEVICE',
|
||||||
|
payload: new IOSDevice(udid, type, name),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return execFile('xcrun', ['simctl', 'list', 'devices', '--json'], {
|
if (currentDeviceIDs.size > 0) {
|
||||||
|
store.dispatch({
|
||||||
|
type: 'UNREGISTER_DEVICES',
|
||||||
|
payload: currentDeviceIDs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getActiveSimulators(): Promise<Array<IOSDeviceParams>> {
|
||||||
|
return promisify(execFile)('xcrun', ['simctl', 'list', 'devices', '--json'], {
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
})
|
})
|
||||||
.then(({stdout}) => JSON.parse(stdout).devices)
|
.then(({stdout}) => JSON.parse(stdout).devices)
|
||||||
.then((simulatorDevices: IOSDeviceMap) => {
|
.then(simulatorDevices => {
|
||||||
const simulators: Array<iOSSimulatorDevice> = Object.values(
|
const simulators: Array<iOSSimulatorDevice> = Object.values(
|
||||||
simulatorDevices,
|
simulatorDevices,
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
).reduce((acc, cv) => acc.concat(cv), []);
|
).reduce((acc, cv) => acc.concat(cv), []);
|
||||||
|
|
||||||
const currentDeviceIDs: Set<string> = new Set(
|
return simulators
|
||||||
connections.devices
|
.filter(
|
||||||
.filter(device => device instanceof IOSDevice)
|
simulator =>
|
||||||
.map(device => device.serial),
|
simulator.state === 'Booted' &&
|
||||||
);
|
// For some users "availability" is set, for others it's "isAvailable"
|
||||||
|
// It's not clear which key is set, so we are checking both.
|
||||||
const deviceIDsToRemove = new Set();
|
(simulator.availability === '(available)' ||
|
||||||
simulators.forEach((simulator: iOSSimulatorDevice) => {
|
simulator.isAvailable === 'YES'),
|
||||||
const isRunning =
|
)
|
||||||
simulator.state === 'Booted' &&
|
.map(simulator => {
|
||||||
// For some users "availability" is set, for others it's "isAvailable"
|
return {
|
||||||
// It's not clear which key is set, so we are checking both.
|
udid: simulator.udid,
|
||||||
(simulator.availability === '(available)' ||
|
type: 'emulator',
|
||||||
simulator.isAvailable === 'YES');
|
name: simulator.name,
|
||||||
|
};
|
||||||
if (isRunning && !currentDeviceIDs.has(simulator.udid)) {
|
|
||||||
// create device
|
|
||||||
store.dispatch({
|
|
||||||
type: 'REGISTER_DEVICE',
|
|
||||||
payload: new IOSDevice(simulator.udid, 'emulator', simulator.name),
|
|
||||||
});
|
|
||||||
} else if (!isRunning && currentDeviceIDs.has(simulator.udid)) {
|
|
||||||
deviceIDsToRemove.add(simulator.udid);
|
|
||||||
// delete device
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (deviceIDsToRemove.size > 0) {
|
|
||||||
store.dispatch({
|
|
||||||
type: 'UNREGISTER_DEVICES',
|
|
||||||
payload: deviceIDsToRemove,
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getActiveDevices(): Promise<Array<IOSDeviceParams>> {
|
||||||
|
return iosUtil.targets().catch(e => {
|
||||||
|
console.warn(e);
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export default (store: Store, logger: Logger) => {
|
export default (store: Store, logger: Logger) => {
|
||||||
// monitoring iOS devices only available on MacOS.
|
// monitoring iOS devices only available on MacOS.
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
querySimulatorDevices(store)
|
queryDevices(store)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const simulatorUpdateInterval = setInterval(() => {
|
const simulatorUpdateInterval = setInterval(() => {
|
||||||
querySimulatorDevices(store).catch(err => {
|
queryDevices(store).catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
clearInterval(simulatorUpdateInterval);
|
clearInterval(simulatorUpdateInterval);
|
||||||
});
|
});
|
||||||
|
|||||||
47
src/fb-stubs/iOSContainerUtility.js
Normal file
47
src/fb-stubs/iOSContainerUtility.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018-present Facebook.
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
const errorMessage = 'Physical iOS devices not yet supported';
|
||||||
|
|
||||||
|
export type DeviceTarget = {
|
||||||
|
udid: string,
|
||||||
|
type: 'physical' | 'emulator',
|
||||||
|
name: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
function isAvailable(): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function targets(): Promise<Array<DeviceTarget>> {
|
||||||
|
return Promise.reject(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
function push(
|
||||||
|
udid: string,
|
||||||
|
src: string,
|
||||||
|
bundleId: string,
|
||||||
|
dst: string,
|
||||||
|
): Promise<void> {
|
||||||
|
return Promise.reject(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pull(
|
||||||
|
udid: string,
|
||||||
|
src: string,
|
||||||
|
bundleId: string,
|
||||||
|
dst: string,
|
||||||
|
): Promise<void> {
|
||||||
|
return Promise.reject(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
isAvailable: isAvailable,
|
||||||
|
targets: targets,
|
||||||
|
push: push,
|
||||||
|
pull: pull,
|
||||||
|
};
|
||||||
@@ -301,8 +301,10 @@ export default function reducer(
|
|||||||
case 'CLIENT_SETUP_ERROR': {
|
case 'CLIENT_SETUP_ERROR': {
|
||||||
const {payload} = action;
|
const {payload} = action;
|
||||||
|
|
||||||
|
const errorMessage =
|
||||||
|
payload.error instanceof Error ? payload.error.message : payload.error;
|
||||||
console.error(
|
console.error(
|
||||||
new RecurringError(`Client setup error: ${payload.error.message}`),
|
new RecurringError(`Client setup error: ${errorMessage}`),
|
||||||
`${payload.client.os}:${payload.client.deviceName}:${
|
`${payload.client.os}:${payload.client.deviceName}:${
|
||||||
payload.client.appName
|
payload.client.appName
|
||||||
}`,
|
}`,
|
||||||
@@ -313,10 +315,11 @@ export default function reducer(
|
|||||||
.map(
|
.map(
|
||||||
c =>
|
c =>
|
||||||
isEqual(c.client, payload.client)
|
isEqual(c.client, payload.client)
|
||||||
? {...c, error: payload.error.message}
|
? {...c, error: errorMessage}
|
||||||
: c,
|
: c,
|
||||||
)
|
)
|
||||||
.sort((a, b) => a.client.appName.localeCompare(b.client.appName)),
|
.sort((a, b) => a.client.appName.localeCompare(b.client.appName)),
|
||||||
|
error: `Client setup error: ${errorMessage}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -148,22 +148,6 @@ export default class Server extends EventEmitter {
|
|||||||
};
|
};
|
||||||
this.emit('start-client-setup', client);
|
this.emit('start-client-setup', client);
|
||||||
|
|
||||||
if (
|
|
||||||
clientData.os === 'iOS' &&
|
|
||||||
!clientData.device.toLowerCase().includes('simulator')
|
|
||||||
) {
|
|
||||||
this.emit(
|
|
||||||
'error',
|
|
||||||
new Error(
|
|
||||||
"Flipper doesn't currently support physical iOS devices. You can still use it to view logs, but for now to use the majority of the Flipper plugins you'll have to use the Simulator.",
|
|
||||||
),
|
|
||||||
);
|
|
||||||
console.warn(
|
|
||||||
'Physical iOS device detected. This is not currently supported by Flipper.',
|
|
||||||
'server',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
requestResponse: (payload: {data: string}) => {
|
requestResponse: (payload: {data: string}) => {
|
||||||
if (typeof payload.data !== 'string') {
|
if (typeof payload.data !== 'string') {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
import LogManager from '../fb-stubs/Logger';
|
import LogManager from '../fb-stubs/Logger';
|
||||||
import {RecurringError} from './errors';
|
import {RecurringError} from './errors';
|
||||||
import {promisify} from 'util';
|
import {promisify} from 'util';
|
||||||
|
import child_process from 'child_process';
|
||||||
|
const exec = promisify(child_process.exec);
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const adb = require('adbkit-fb');
|
const adb = require('adbkit-fb');
|
||||||
import {
|
import {
|
||||||
@@ -15,7 +17,10 @@ import {
|
|||||||
isInstalled as opensslInstalled,
|
isInstalled as opensslInstalled,
|
||||||
} from './openssl-wrapper-with-promises';
|
} from './openssl-wrapper-with-promises';
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const tmpFile = promisify(require('tmp').file);
|
const tmp = require('tmp');
|
||||||
|
const tmpFile = promisify(tmp.file);
|
||||||
|
const tmpDir = promisify(tmp.dir);
|
||||||
|
import iosUtil from '../fb-stubs/iOSContainerUtility';
|
||||||
|
|
||||||
// Desktop file paths
|
// Desktop file paths
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
@@ -121,15 +126,7 @@ export default class CertificateProvider {
|
|||||||
if (os === 'Android') {
|
if (os === 'Android') {
|
||||||
return this.getTargetAndroidDeviceId(appName, appDirectory, csr);
|
return this.getTargetAndroidDeviceId(appName, appDirectory, csr);
|
||||||
} else if (os === 'iOS') {
|
} else if (os === 'iOS') {
|
||||||
const matches = /\/Devices\/([^/]+)\//.exec(appDirectory);
|
return this.getTargetiOSDeviceId(appName, appDirectory, csr);
|
||||||
if (matches === null || matches.length < 2) {
|
|
||||||
return Promise.reject(
|
|
||||||
new Error(
|
|
||||||
`iOS simulator directory doesn't match expected format: ${appDirectory}`,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return Promise.resolve(matches[1]);
|
|
||||||
}
|
}
|
||||||
return Promise.resolve('unknown');
|
return Promise.resolve('unknown');
|
||||||
}
|
}
|
||||||
@@ -169,6 +166,14 @@ export default class CertificateProvider {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRelativePathInAppContainer(absolutePath: string) {
|
||||||
|
const matches = /Application\/[^/]+\/(.*)/.exec(absolutePath);
|
||||||
|
if (matches && matches.length === 2) {
|
||||||
|
return matches[1];
|
||||||
|
}
|
||||||
|
throw new Error("Path didn't match expected pattern: " + absolutePath);
|
||||||
|
}
|
||||||
|
|
||||||
deployFileToMobileApp(
|
deployFileToMobileApp(
|
||||||
destination: string,
|
destination: string,
|
||||||
filename: string,
|
filename: string,
|
||||||
@@ -176,8 +181,9 @@ export default class CertificateProvider {
|
|||||||
csr: string,
|
csr: string,
|
||||||
os: string,
|
os: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const appNamePromise = this.extractAppNameFromCSR(csr);
|
||||||
|
|
||||||
if (os === 'Android') {
|
if (os === 'Android') {
|
||||||
const appNamePromise = this.extractAppNameFromCSR(csr);
|
|
||||||
const deviceIdPromise = appNamePromise.then(app =>
|
const deviceIdPromise = appNamePromise.then(app =>
|
||||||
this.getTargetAndroidDeviceId(app, destination, csr),
|
this.getTargetAndroidDeviceId(app, destination, csr),
|
||||||
);
|
);
|
||||||
@@ -192,22 +198,54 @@ export default class CertificateProvider {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (os === 'iOS' || os === 'windows') {
|
if (os === 'iOS' || os === 'windows') {
|
||||||
return new Promise((resolve, reject) => {
|
return promisify(fs.writeFile)(destination + filename, contents).catch(
|
||||||
fs.writeFile(destination + filename, contents, err => {
|
err => {
|
||||||
if (err) {
|
if (os === 'iOS') {
|
||||||
reject(
|
// Writing directly to FS failed. It's probably a physical device.
|
||||||
`Invalid appDirectory recieved from ${os} device: ${destination}: ` +
|
const relativePathInsideApp = this.getRelativePathInAppContainer(
|
||||||
err.toString(),
|
destination,
|
||||||
);
|
);
|
||||||
} else {
|
return appNamePromise
|
||||||
resolve();
|
.then(appName =>
|
||||||
|
this.getTargetiOSDeviceId(appName, destination, csr),
|
||||||
|
)
|
||||||
|
.then(udid => {
|
||||||
|
return appNamePromise.then(appName =>
|
||||||
|
this.pushFileToiOSDevice(
|
||||||
|
udid,
|
||||||
|
appName,
|
||||||
|
relativePathInsideApp,
|
||||||
|
filename,
|
||||||
|
contents,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
throw new Error(
|
||||||
});
|
`Invalid appDirectory recieved from ${os} device: ${destination}: ` +
|
||||||
|
err.toString(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return Promise.reject(new RecurringError(`Unsupported device os: ${os}`));
|
return Promise.reject(new RecurringError(`Unsupported device os: ${os}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pushFileToiOSDevice(
|
||||||
|
udid: string,
|
||||||
|
bundleId: string,
|
||||||
|
destination: string,
|
||||||
|
filename: string,
|
||||||
|
contents: string,
|
||||||
|
): Promise<void> {
|
||||||
|
return tmpDir({unsafeCleanup: true}).then(dir => {
|
||||||
|
const filePath = path.resolve(dir, filename);
|
||||||
|
promisify(fs.writeFile)(filePath, contents).then(() =>
|
||||||
|
iosUtil.push(udid, filePath, bundleId, destination),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
getTargetAndroidDeviceId(
|
getTargetAndroidDeviceId(
|
||||||
appName: string,
|
appName: string,
|
||||||
deviceCsrFilePath: string,
|
deviceCsrFilePath: string,
|
||||||
@@ -215,10 +253,6 @@ export default class CertificateProvider {
|
|||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
return this.adb.listDevices().then((devices: Array<{id: string}>) => {
|
return this.adb.listDevices().then((devices: Array<{id: string}>) => {
|
||||||
const deviceMatchList = devices.map(device =>
|
const deviceMatchList = devices.map(device =>
|
||||||
// To find out which device requested the cert, search them
|
|
||||||
// all for a matching csr file.
|
|
||||||
// It's not important to keep these secret from other apps.
|
|
||||||
// Just need to make sure each app can find its own one.
|
|
||||||
this.androidDeviceHasMatchingCSR(
|
this.androidDeviceHasMatchingCSR(
|
||||||
deviceCsrFilePath,
|
deviceCsrFilePath,
|
||||||
device.id,
|
device.id,
|
||||||
@@ -248,6 +282,39 @@ export default class CertificateProvider {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTargetiOSDeviceId(
|
||||||
|
appName: string,
|
||||||
|
deviceCsrFilePath: string,
|
||||||
|
csr: string,
|
||||||
|
): Promise<string> {
|
||||||
|
const matches = /\/Devices\/([^/]+)\//.exec(deviceCsrFilePath);
|
||||||
|
if (matches && matches.length == 2) {
|
||||||
|
// It's a simulator, the deviceId is in the filepath.
|
||||||
|
return Promise.resolve(matches[1]);
|
||||||
|
}
|
||||||
|
return iosUtil.targets().then(targets => {
|
||||||
|
const deviceMatchList = targets.map(target =>
|
||||||
|
this.iOSDeviceHasMatchingCSR(
|
||||||
|
deviceCsrFilePath,
|
||||||
|
target.udid,
|
||||||
|
appName,
|
||||||
|
csr,
|
||||||
|
).then(isMatch => {
|
||||||
|
return {id: target.udid, isMatch};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return Promise.all(deviceMatchList).then(devices => {
|
||||||
|
const matchingIds = devices.filter(m => m.isMatch).map(m => m.id);
|
||||||
|
if (matchingIds.length == 0) {
|
||||||
|
throw new RecurringError(
|
||||||
|
`No matching device found for app: ${appName}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return matchingIds[0];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
androidDeviceHasMatchingCSR(
|
androidDeviceHasMatchingCSR(
|
||||||
directory: string,
|
directory: string,
|
||||||
deviceId: string,
|
deviceId: string,
|
||||||
@@ -273,6 +340,42 @@ export default class CertificateProvider {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iOSDeviceHasMatchingCSR(
|
||||||
|
directory: string,
|
||||||
|
deviceId: string,
|
||||||
|
bundleId: string,
|
||||||
|
csr: string,
|
||||||
|
): Promise<boolean> {
|
||||||
|
const originalFile = this.getRelativePathInAppContainer(
|
||||||
|
path.resolve(directory, csrFileName),
|
||||||
|
);
|
||||||
|
return tmpDir({unsafeCleanup: true})
|
||||||
|
.then(dir => {
|
||||||
|
return iosUtil
|
||||||
|
.pull(deviceId, originalFile, bundleId, dir)
|
||||||
|
.then(() => dir);
|
||||||
|
})
|
||||||
|
.then(dir => {
|
||||||
|
return promisify(fs.readdir)(dir)
|
||||||
|
.then(items => {
|
||||||
|
if (items.length !== 1) {
|
||||||
|
throw new Error('Conflict in temp dir');
|
||||||
|
}
|
||||||
|
return items[0];
|
||||||
|
})
|
||||||
|
.then(fileName => {
|
||||||
|
const copiedFile = path.resolve(dir, fileName);
|
||||||
|
return promisify(fs.readFile)(copiedFile).then(data =>
|
||||||
|
data
|
||||||
|
.toString()
|
||||||
|
.replace(/\r/g, '')
|
||||||
|
.trim(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(csrFromDevice => csrFromDevice === csr.replace(/\r/g, '').trim());
|
||||||
|
}
|
||||||
|
|
||||||
pushFileToAndroidDevice(
|
pushFileToAndroidDevice(
|
||||||
deviceId: string,
|
deviceId: string,
|
||||||
app: string,
|
app: string,
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>BuildMachineOSBuild</key>
|
||||||
|
<string>16G29</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>CocoaAsyncSocketMac</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.robbiehanson.CocoaAsyncSocketMac</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>CocoaAsyncSocketMac</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
|
<array>
|
||||||
|
<string>MacOSX</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>DTCompiler</key>
|
||||||
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||||
|
<key>DTPlatformBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
<key>DTPlatformVersion</key>
|
||||||
|
<string>GM</string>
|
||||||
|
<key>DTSDKBuild</key>
|
||||||
|
<string>17A360</string>
|
||||||
|
<key>DTSDKName</key>
|
||||||
|
<string>macosx10.13</string>
|
||||||
|
<key>DTXcode</key>
|
||||||
|
<string>0900</string>
|
||||||
|
<key>DTXcodeBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
Binary file not shown.
@@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>BuildMachineOSBuild</key>
|
||||||
|
<string>16G29</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>CocoaAsyncSocketMac</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.robbiehanson.CocoaAsyncSocketMac</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>CocoaAsyncSocketMac</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
|
<array>
|
||||||
|
<string>MacOSX</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>DTCompiler</key>
|
||||||
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||||
|
<key>DTPlatformBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
<key>DTPlatformVersion</key>
|
||||||
|
<string>GM</string>
|
||||||
|
<key>DTSDKBuild</key>
|
||||||
|
<string>17A360</string>
|
||||||
|
<key>DTSDKName</key>
|
||||||
|
<string>macosx10.13</string>
|
||||||
|
<key>DTXcode</key>
|
||||||
|
<string>0900</string>
|
||||||
|
<key>DTXcodeBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
Binary file not shown.
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>BuildMachineOSBuild</key>
|
||||||
|
<string>16G29</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>FBPortForwarding-Mac</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.facebook.FBPortForwarding-Mac</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>FBPortForwarding-Mac</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
|
<array>
|
||||||
|
<string>MacOSX</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string></string>
|
||||||
|
<key>DTCompiler</key>
|
||||||
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||||
|
<key>DTPlatformBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
<key>DTPlatformVersion</key>
|
||||||
|
<string>GM</string>
|
||||||
|
<key>DTSDKBuild</key>
|
||||||
|
<string>17A360</string>
|
||||||
|
<key>DTSDKName</key>
|
||||||
|
<string>macosx10.13</string>
|
||||||
|
<key>DTXcode</key>
|
||||||
|
<string>0900</string>
|
||||||
|
<key>DTXcodeBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>Copyright © 2014 Facebook. All rights reserved.</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
Binary file not shown.
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>BuildMachineOSBuild</key>
|
||||||
|
<string>16G29</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>FBPortForwarding-Mac</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.facebook.FBPortForwarding-Mac</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>FBPortForwarding-Mac</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
|
<array>
|
||||||
|
<string>MacOSX</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string></string>
|
||||||
|
<key>DTCompiler</key>
|
||||||
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||||
|
<key>DTPlatformBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
<key>DTPlatformVersion</key>
|
||||||
|
<string>GM</string>
|
||||||
|
<key>DTSDKBuild</key>
|
||||||
|
<string>17A360</string>
|
||||||
|
<key>DTSDKName</key>
|
||||||
|
<string>macosx10.13</string>
|
||||||
|
<key>DTXcode</key>
|
||||||
|
<string>0900</string>
|
||||||
|
<key>DTXcodeBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>Copyright © 2014 Facebook. All rights reserved.</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>BuildMachineOSBuild</key>
|
||||||
|
<string>16G29</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>peertalkMac</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.facebook.peertalkMac</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>peertalkMac</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
|
<array>
|
||||||
|
<string>MacOSX</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string></string>
|
||||||
|
<key>DTCompiler</key>
|
||||||
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||||
|
<key>DTPlatformBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
<key>DTPlatformVersion</key>
|
||||||
|
<string>GM</string>
|
||||||
|
<key>DTSDKBuild</key>
|
||||||
|
<string>17A360</string>
|
||||||
|
<key>DTSDKName</key>
|
||||||
|
<string>macosx10.13</string>
|
||||||
|
<key>DTXcode</key>
|
||||||
|
<string>0900</string>
|
||||||
|
<key>DTXcodeBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>Copyright © 2014 Facebook. All rights reserved.</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>BuildMachineOSBuild</key>
|
||||||
|
<string>16G29</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>peertalkMac</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.facebook.peertalkMac</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>peertalkMac</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
|
<array>
|
||||||
|
<string>MacOSX</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string></string>
|
||||||
|
<key>DTCompiler</key>
|
||||||
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||||
|
<key>DTPlatformBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
<key>DTPlatformVersion</key>
|
||||||
|
<string>GM</string>
|
||||||
|
<key>DTSDKBuild</key>
|
||||||
|
<string>17A360</string>
|
||||||
|
<key>DTSDKName</key>
|
||||||
|
<string>macosx10.13</string>
|
||||||
|
<key>DTXcode</key>
|
||||||
|
<string>0900</string>
|
||||||
|
<key>DTXcodeBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>Copyright © 2014 Facebook. All rights reserved.</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
Binary file not shown.
Binary file not shown.
50
static/PortForwardingMacApp.app/Contents/Info.plist
Normal file
50
static/PortForwardingMacApp.app/Contents/Info.plist
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>BuildMachineOSBuild</key>
|
||||||
|
<string>16G29</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>PortForwardingMacApp</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.facebook.PortForwardingMacApp</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>PortForwardingMacApp</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
|
<array>
|
||||||
|
<string>MacOSX</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string></string>
|
||||||
|
<key>DTCompiler</key>
|
||||||
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||||
|
<key>DTPlatformBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
<key>DTPlatformVersion</key>
|
||||||
|
<string>GM</string>
|
||||||
|
<key>DTSDKBuild</key>
|
||||||
|
<string>17A360</string>
|
||||||
|
<key>DTSDKName</key>
|
||||||
|
<string>macosx10.13</string>
|
||||||
|
<key>DTXcode</key>
|
||||||
|
<string>0900</string>
|
||||||
|
<key>DTXcodeBuild</key>
|
||||||
|
<string>9A235</string>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>10.10</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>Copyright © 2013-present Facebook. All rights reserved.</string>
|
||||||
|
<key>NSMainNibFile</key>
|
||||||
|
<string>MainMenu</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string>NSApplication</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
BIN
static/PortForwardingMacApp.app/Contents/MacOS/PortForwardingMacApp
Executable file
BIN
static/PortForwardingMacApp.app/Contents/MacOS/PortForwardingMacApp
Executable file
Binary file not shown.
1
static/PortForwardingMacApp.app/Contents/PkgInfo
Normal file
1
static/PortForwardingMacApp.app/Contents/PkgInfo
Normal file
@@ -0,0 +1 @@
|
|||||||
|
APPL????
|
||||||
Reference in New Issue
Block a user