Upload/Download certs zip from Flipper
Summary: This diff adds upload and download logic for certs. It makes changes on both Flipper Client and Desktop side. With this we enable cert exchange through WWW. Next Diffs: 1) Add Flipper state in cert provider for more debug data 2) Tests Reviewed By: jknoxville Differential Revision: D23092706 fbshipit-source-id: e576253606b64b62848b70203db7e09a3bd77fd9
This commit is contained in:
committed by
Facebook GitHub Bot
parent
6e0b407063
commit
f626925443
@@ -14,10 +14,13 @@
|
||||
"@emotion/core": "^10.0.22",
|
||||
"@emotion/styled": "^10.0.23",
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"@types/archiver": "^3.1.0",
|
||||
"@types/uuid": "^8.0.1",
|
||||
"JSONStream": "^1.3.1",
|
||||
"adbkit": "^2.11.1",
|
||||
"adbkit-logcat": "^2.0.1",
|
||||
"algoliasearch": "^4.0.0",
|
||||
"archiver": "^5.0.0",
|
||||
"async-mutex": "^0.1.3",
|
||||
"axios": "^0.19.2",
|
||||
"deep-equal": "^2.0.1",
|
||||
@@ -61,7 +64,7 @@
|
||||
"semver": "^7.3.2",
|
||||
"string-natural-compare": "^3.0.0",
|
||||
"tmp": "^0.2.1",
|
||||
"uuid": "^8.1.0",
|
||||
"uuid": "^8.3.0",
|
||||
"which": "^2.0.1",
|
||||
"ws": "^7.3.0",
|
||||
"xdg-basedir": "^4.0.0"
|
||||
|
||||
@@ -72,7 +72,12 @@ function getStore(selectedPlugins: Array<string>) {
|
||||
|
||||
const client = new Client(
|
||||
clientId,
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial'},
|
||||
{
|
||||
app: 'app',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
// @ts-ignore
|
||||
|
||||
17
desktop/app/src/devices/ClientDevice.tsx
Normal file
17
desktop/app/src/devices/ClientDevice.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import BaseDevice, {OS} from './BaseDevice';
|
||||
|
||||
export default class ClientDevice extends BaseDevice {
|
||||
constructor(serial: string, title: string, os: OS) {
|
||||
super(serial, 'emulator', title, os);
|
||||
this.devicePlugins = [];
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import querystring from 'querystring';
|
||||
import {IncomingMessage} from 'http';
|
||||
import ws from 'ws';
|
||||
import {initSelfInpector} from './utils/self-inspection/selfInspectionUtils';
|
||||
import ClientDevice from './devices/ClientDevice';
|
||||
|
||||
type ClientInfo = {
|
||||
connection: FlipperClientConnection<any, any> | null | undefined;
|
||||
@@ -51,9 +52,9 @@ type ClientCsrQuery = {
|
||||
function transformCertificateExchangeMediumToType(
|
||||
medium: number | undefined,
|
||||
): CertificateExchangeMedium {
|
||||
if (medium === 1) {
|
||||
if (medium == 1) {
|
||||
return 'FS_ACCESS';
|
||||
} else if (medium === 2) {
|
||||
} else if (medium == 2) {
|
||||
return 'WWW';
|
||||
} else {
|
||||
return 'FS_ACCESS';
|
||||
@@ -226,6 +227,7 @@ class Server extends EventEmitter {
|
||||
device: 'device',
|
||||
device_id: deviceId,
|
||||
sdk_version: 1,
|
||||
medium: 'FS_ACCESS',
|
||||
},
|
||||
{},
|
||||
).then((c) => (resolvedClient = c));
|
||||
@@ -277,14 +279,43 @@ class Server extends EventEmitter {
|
||||
if (!payload.data) {
|
||||
return {};
|
||||
}
|
||||
const clientData: ClientQuery & ClientCsrQuery = JSON.parse(payload.data);
|
||||
const clientData: ClientQuery &
|
||||
ClientCsrQuery & {medium: number | undefined} = JSON.parse(payload.data);
|
||||
this.connectionTracker.logConnectionAttempt(clientData);
|
||||
|
||||
const {app, os, device, device_id, sdk_version, csr, csr_path} = clientData;
|
||||
const {
|
||||
app,
|
||||
os,
|
||||
device,
|
||||
device_id,
|
||||
sdk_version,
|
||||
csr,
|
||||
csr_path,
|
||||
medium,
|
||||
} = clientData;
|
||||
const transformedMedium = transformCertificateExchangeMediumToType(medium);
|
||||
const duplicateDevices = this.store
|
||||
.getState()
|
||||
.connections.devices.filter((device) => device.serial === device_id);
|
||||
// When user switches from WWW to FS_ACCESS, we reset the certs folder, but we don't do it other way around. Thus when user switches to WWW from FS_ACCESS and if certs arepresent then the device id sent by Flipper SDK is the original one and in that case we need not create a device.
|
||||
if (transformedMedium === 'WWW' && duplicateDevices.length == 0) {
|
||||
// TODO unregister previous ClientDevice's for a particular device
|
||||
this.store.dispatch({
|
||||
type: 'REGISTER_DEVICE',
|
||||
payload: new ClientDevice(device_id, app, os),
|
||||
});
|
||||
}
|
||||
|
||||
const client: Promise<Client> = this.addConnection(
|
||||
socket,
|
||||
{app, os, device, device_id, sdk_version},
|
||||
{
|
||||
app,
|
||||
os,
|
||||
device,
|
||||
device_id,
|
||||
sdk_version,
|
||||
medium: transformedMedium,
|
||||
},
|
||||
{csr, csr_path},
|
||||
).then((client) => {
|
||||
return (resolvedClient = client);
|
||||
@@ -364,6 +395,7 @@ class Server extends EventEmitter {
|
||||
destination: string;
|
||||
medium: number | undefined; // OSS's older Client SDK might not send medium information. This is not an issue for internal FB users, as Flipper release is insync with client SDK through launcher.
|
||||
} = rawData;
|
||||
|
||||
if (json.method === 'signCertificate') {
|
||||
console.debug('CSR received from device', 'server');
|
||||
|
||||
@@ -461,7 +493,7 @@ class Server extends EventEmitter {
|
||||
|
||||
async addConnection(
|
||||
conn: FlipperClientConnection<any, any>,
|
||||
query: ClientQuery,
|
||||
query: ClientQuery & {medium: CertificateExchangeMedium},
|
||||
csrQuery: ClientCsrQuery,
|
||||
): Promise<Client> {
|
||||
invariant(query, 'expected query');
|
||||
@@ -469,7 +501,7 @@ class Server extends EventEmitter {
|
||||
// try to get id by comparing giving `csr` to file from `csr_path`
|
||||
// otherwise, use given device_id
|
||||
const {csr_path, csr} = csrQuery;
|
||||
return (csr_path && csr
|
||||
return (csr_path && csr && query.medium === 'FS_ACCESS'
|
||||
? this.certificateProvider.extractAppNameFromCSR(csr).then((appName) => {
|
||||
return this.certificateProvider.getTargetDeviceId(
|
||||
query.os,
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
*/
|
||||
|
||||
import {Logger} from '../fb-interfaces/Logger';
|
||||
import {internGraphPOSTAPIRequest} from '../fb-stubs/user';
|
||||
import Server from '../server';
|
||||
import {promisify} from 'util';
|
||||
import fs from 'fs';
|
||||
import fsExtra from 'fs-extra';
|
||||
|
||||
import {
|
||||
openssl,
|
||||
isInstalled as opensslInstalled,
|
||||
@@ -24,6 +27,9 @@ import * as androidUtil from './androidContainerUtility';
|
||||
import os from 'os';
|
||||
import {Client as ADBClient} from 'adbkit';
|
||||
import {Store} from '../reducers/index';
|
||||
import archiver from 'archiver';
|
||||
import promiseTimeout from '../utils/promiseTimeout';
|
||||
import {v4 as uuid} from 'uuid';
|
||||
|
||||
export type CertificateExchangeMedium = 'FS_ACCESS' | 'WWW';
|
||||
|
||||
@@ -94,47 +100,90 @@ export default class CertificateProvider {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
processCertificateSigningRequest(
|
||||
uploadFiles = async (zipPath: string, deviceID: string): Promise<void> => {
|
||||
const buff = await fsExtra.readFile(zipPath);
|
||||
const file = new File([buff], 'certs.zip');
|
||||
return reportPlatformFailures(
|
||||
promiseTimeout(
|
||||
5 * 60 * 1000,
|
||||
internGraphPOSTAPIRequest('flipper/certificates', {
|
||||
certificate_zip: file,
|
||||
device_id: deviceID,
|
||||
}),
|
||||
'Timed out uploading Flipper export.',
|
||||
),
|
||||
'uploadCertificates',
|
||||
).catch((e) => console.error(`Failed to upload certificates due to ${e}`));
|
||||
};
|
||||
|
||||
async processCertificateSigningRequest(
|
||||
unsanitizedCsr: string,
|
||||
os: string,
|
||||
appDirectory: string,
|
||||
medium: CertificateExchangeMedium,
|
||||
): Promise<{deviceId: string}> {
|
||||
// TODO: Add implementations for each of these conditions
|
||||
if (medium === 'FS_ACCESS') {
|
||||
// Use IDB for cert exchange
|
||||
} else if (medium === 'WWW') {
|
||||
// Use WWWW
|
||||
}
|
||||
const csr = this.santitizeString(unsanitizedCsr);
|
||||
if (csr === '') {
|
||||
return Promise.reject(new Error(`Received empty CSR from ${os} device`));
|
||||
}
|
||||
this.ensureOpenSSLIsAvailable();
|
||||
const rootFolder = await promisify(tmp.dir)();
|
||||
const certFolder = rootFolder + '/FlipperCerts/';
|
||||
const certsZipPath = rootFolder + '/certs.zip';
|
||||
return this.certificateSetup
|
||||
.then((_) => this.getCACertificate())
|
||||
.then((caCert) =>
|
||||
this.deployFileToMobileApp(
|
||||
this.deployOrStageFileForMobileApp(
|
||||
appDirectory,
|
||||
deviceCAcertFile,
|
||||
caCert,
|
||||
csr,
|
||||
os,
|
||||
medium,
|
||||
certFolder,
|
||||
),
|
||||
)
|
||||
.then((_) => this.generateClientCertificate(csr))
|
||||
.then((clientCert) =>
|
||||
this.deployFileToMobileApp(
|
||||
this.deployOrStageFileForMobileApp(
|
||||
appDirectory,
|
||||
deviceClientCertFile,
|
||||
clientCert,
|
||||
csr,
|
||||
os,
|
||||
medium,
|
||||
certFolder,
|
||||
),
|
||||
)
|
||||
.then((_) => this.extractAppNameFromCSR(csr))
|
||||
.then((appName) => this.getTargetDeviceId(os, appName, appDirectory, csr))
|
||||
.then((deviceId) => {
|
||||
.then((_) => {
|
||||
return this.extractAppNameFromCSR(csr);
|
||||
})
|
||||
.then((appName) => {
|
||||
if (medium === 'FS_ACCESS') {
|
||||
return this.getTargetDeviceId(os, appName, appDirectory, csr);
|
||||
} else {
|
||||
return uuid();
|
||||
}
|
||||
})
|
||||
.then(async (deviceId) => {
|
||||
if (medium === 'WWW') {
|
||||
const zipPromise = new Promise((resolve, reject) => {
|
||||
const output = fs.createWriteStream(certsZipPath);
|
||||
const archive = archiver('zip', {
|
||||
zlib: {level: 9}, // Sets the compression level.
|
||||
});
|
||||
archive.directory(certFolder, false);
|
||||
output.on('close', function () {
|
||||
resolve(certsZipPath);
|
||||
});
|
||||
archive.on('warning', reject);
|
||||
archive.on('error', reject);
|
||||
archive.pipe(output);
|
||||
archive.finalize();
|
||||
});
|
||||
await zipPromise;
|
||||
await this.uploadFiles(certsZipPath, deviceId);
|
||||
}
|
||||
return {
|
||||
deviceId,
|
||||
};
|
||||
@@ -201,15 +250,31 @@ export default class CertificateProvider {
|
||||
throw new Error("Path didn't match expected pattern: " + absolutePath);
|
||||
}
|
||||
|
||||
deployFileToMobileApp(
|
||||
async deployOrStageFileForMobileApp(
|
||||
destination: string,
|
||||
filename: string,
|
||||
contents: string,
|
||||
csr: string,
|
||||
os: string,
|
||||
medium: CertificateExchangeMedium,
|
||||
certFolder: string,
|
||||
): Promise<void> {
|
||||
const appNamePromise = this.extractAppNameFromCSR(csr);
|
||||
|
||||
if (medium === 'WWW') {
|
||||
const certPathExists = await fsExtra.pathExists(certFolder);
|
||||
if (!certPathExists) {
|
||||
await fsExtra.mkdir(certFolder);
|
||||
}
|
||||
return promisify(fs.writeFile)(certFolder + filename, contents).catch(
|
||||
(e) => {
|
||||
throw new Error(
|
||||
`Failed to write ${filename} to temporary folder. Error: ${e}`,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (os === 'Android') {
|
||||
const deviceIdPromise = appNamePromise.then((app) =>
|
||||
this.getTargetAndroidDeviceId(app, destination, csr),
|
||||
@@ -237,9 +302,9 @@ export default class CertificateProvider {
|
||||
destination,
|
||||
);
|
||||
return appNamePromise
|
||||
.then((appName) =>
|
||||
this.getTargetiOSDeviceId(appName, destination, csr),
|
||||
)
|
||||
.then((appName) => {
|
||||
return this.getTargetiOSDeviceId(appName, destination, csr);
|
||||
})
|
||||
.then((udid) => {
|
||||
return appNamePromise.then((appName) =>
|
||||
this.pushFileToiOSDevice(
|
||||
|
||||
@@ -716,7 +716,12 @@ test('test determinePluginsToProcess for mutilple clients having plugins present
|
||||
const device1 = new BaseDevice('serial1', 'emulator', 'TestiPhone', 'iOS');
|
||||
const client1 = new Client(
|
||||
generateClientIdentifier(device1, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
{
|
||||
app: 'app',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial1',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
@@ -724,7 +729,12 @@ test('test determinePluginsToProcess for mutilple clients having plugins present
|
||||
);
|
||||
const client2 = new Client(
|
||||
generateClientIdentifier(device1, 'app2'),
|
||||
{app: 'app2', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
{
|
||||
app: 'app2',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial1',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
@@ -732,7 +742,12 @@ test('test determinePluginsToProcess for mutilple clients having plugins present
|
||||
);
|
||||
const client3 = new Client(
|
||||
generateClientIdentifier(device1, 'app3'),
|
||||
{app: 'app3', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
{
|
||||
app: 'app3',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial1',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
@@ -777,7 +792,12 @@ test('test determinePluginsToProcess for no selected plugin present in any clien
|
||||
const device1 = new BaseDevice('serial1', 'emulator', 'TestiPhone', 'iOS');
|
||||
const client1 = new Client(
|
||||
generateClientIdentifier(device1, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
{
|
||||
app: 'app',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial1',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
@@ -785,7 +805,12 @@ test('test determinePluginsToProcess for no selected plugin present in any clien
|
||||
);
|
||||
const client2 = new Client(
|
||||
generateClientIdentifier(device1, 'app2'),
|
||||
{app: 'app2', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
{
|
||||
app: 'app2',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial1',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
@@ -811,7 +836,12 @@ test('test determinePluginsToProcess for multiple clients on same device', async
|
||||
const device1 = new BaseDevice('serial1', 'emulator', 'TestiPhone', 'iOS');
|
||||
const client1 = new Client(
|
||||
generateClientIdentifier(device1, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
{
|
||||
app: 'app',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial1',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
@@ -819,7 +849,12 @@ test('test determinePluginsToProcess for multiple clients on same device', async
|
||||
);
|
||||
const client2 = new Client(
|
||||
generateClientIdentifier(device1, 'app2'),
|
||||
{app: 'app2', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
{
|
||||
app: 'app2',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial1',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
@@ -852,7 +887,12 @@ test('test determinePluginsToProcess for multiple clients on different device',
|
||||
const device2 = new BaseDevice('serial2', 'emulator', 'TestiPhone', 'iOS');
|
||||
const client1Device1 = new Client(
|
||||
generateClientIdentifier(device1, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
{
|
||||
app: 'app',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial1',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
@@ -860,7 +900,12 @@ test('test determinePluginsToProcess for multiple clients on different device',
|
||||
);
|
||||
const client2Device1 = new Client(
|
||||
generateClientIdentifier(device1, 'app2'),
|
||||
{app: 'app1', os: 'iOS', device: 'TestiPhone', device_id: 'serial1'},
|
||||
{
|
||||
app: 'app1',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial1',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
@@ -868,7 +913,12 @@ test('test determinePluginsToProcess for multiple clients on different device',
|
||||
);
|
||||
const client1Device2 = new Client(
|
||||
generateClientIdentifier(device2, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial2'},
|
||||
{
|
||||
app: 'app',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial2',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
@@ -876,7 +926,12 @@ test('test determinePluginsToProcess for multiple clients on different device',
|
||||
);
|
||||
const client2Device2 = new Client(
|
||||
generateClientIdentifier(device2, 'app2'),
|
||||
{app: 'app1', os: 'iOS', device: 'TestiPhone', device_id: 'serial2'},
|
||||
{
|
||||
app: 'app1',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial2',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
@@ -934,7 +989,12 @@ test('test determinePluginsToProcess to ignore archived clients', async () => {
|
||||
const mockStore = configureStore<State, {}>([])();
|
||||
const client = new Client(
|
||||
generateClientIdentifier(selectedDevice, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial'},
|
||||
{
|
||||
app: 'app',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
@@ -942,7 +1002,12 @@ test('test determinePluginsToProcess to ignore archived clients', async () => {
|
||||
);
|
||||
const archivedClient = new Client(
|
||||
generateClientIdentifier(archivedDevice, 'app'),
|
||||
{app: 'app', os: 'iOS', device: 'TestiPhone', device_id: 'serial-archived'},
|
||||
{
|
||||
app: 'app',
|
||||
os: 'iOS',
|
||||
device: 'TestiPhone',
|
||||
device_id: 'serial-archived',
|
||||
},
|
||||
null,
|
||||
logger,
|
||||
mockStore,
|
||||
|
||||
@@ -1882,6 +1882,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/algoliasearch/-/algoliasearch-3.34.5.tgz#c40e346a6c5526f9b27af7863117d1200456e7d2"
|
||||
integrity sha512-JS+5KT9SfwzGIkoCsj7EyYHzhrsagj321BEPH3oroHYnuKUfPVoei58qLsBPo9RRa27Vb79WJssSSPBicnaAng==
|
||||
|
||||
"@types/archiver@^3.1.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-3.1.0.tgz#0d5bd922ba5cf06e137cd6793db7942439b1805e"
|
||||
integrity sha512-nTvHwgWONL+iXG+9CX+gnQ/tTOV+qucAjwpXqeUn4OCRMxP42T29FFP/7XaOo0EqqO3TlENhObeZEe7RUJAriw==
|
||||
dependencies:
|
||||
"@types/glob" "*"
|
||||
|
||||
"@types/aria-query@^4.2.0":
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0"
|
||||
@@ -2049,6 +2056,14 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/glob@*":
|
||||
version "7.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
|
||||
integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==
|
||||
dependencies:
|
||||
"@types/minimatch" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/glob@^7.1.1":
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
|
||||
@@ -2467,6 +2482,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.0.0.tgz#165aae4819ad2174a17476dbe66feebd549556c0"
|
||||
integrity sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw==
|
||||
|
||||
"@types/uuid@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.0.1.tgz#42958a1a880640b139eea97a1640e1a3f61016d2"
|
||||
integrity sha512-2kE8rEFgJpbBAPw5JghccEevQb0XVU0tewF/8h7wPQTeCtoJ6h8qmBIwuzUVm2MutmzC/cpCkwxudixoNYDp1A==
|
||||
|
||||
"@types/webdriverio@^4.8.0":
|
||||
version "4.13.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/webdriverio/-/webdriverio-4.13.3.tgz#c1571c4e62724135c0b11e7d7e36b07af5168856"
|
||||
@@ -2919,6 +2939,35 @@ archiver-utils@^1.3.0:
|
||||
normalize-path "^2.0.0"
|
||||
readable-stream "^2.0.0"
|
||||
|
||||
archiver-utils@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2"
|
||||
integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==
|
||||
dependencies:
|
||||
glob "^7.1.4"
|
||||
graceful-fs "^4.2.0"
|
||||
lazystream "^1.0.0"
|
||||
lodash.defaults "^4.2.0"
|
||||
lodash.difference "^4.5.0"
|
||||
lodash.flatten "^4.4.0"
|
||||
lodash.isplainobject "^4.0.6"
|
||||
lodash.union "^4.6.0"
|
||||
normalize-path "^3.0.0"
|
||||
readable-stream "^2.0.0"
|
||||
|
||||
archiver@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.0.0.tgz#b1e7dc075a4e18e0aa59afdd7c3e5f3d3321cbeb"
|
||||
integrity sha512-AEWhJz6Yi6hWtN1Sqy/H4sZo/lLMJ/NftXxGaDy/TnOMmmjsRaZc/Ts+U4BsPoBQkuunTN6t8hk7iU9A+HBxLw==
|
||||
dependencies:
|
||||
archiver-utils "^2.1.0"
|
||||
async "^3.2.0"
|
||||
buffer-crc32 "^0.2.1"
|
||||
readable-stream "^3.6.0"
|
||||
readdir-glob "^1.0.0"
|
||||
tar-stream "^2.1.2"
|
||||
zip-stream "^4.0.0"
|
||||
|
||||
archiver@~2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/archiver/-/archiver-2.1.1.tgz#ff662b4a78201494a3ee544d3a33fe7496509ebc"
|
||||
@@ -3074,6 +3123,11 @@ async@^2.0.0, async@^2.4.0:
|
||||
dependencies:
|
||||
lodash "^4.17.14"
|
||||
|
||||
async@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
|
||||
integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==
|
||||
|
||||
async@~0.2.9:
|
||||
version "0.2.10"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
|
||||
@@ -3540,7 +3594,7 @@ buffer-alloc@^1.2.0:
|
||||
buffer-alloc-unsafe "^1.1.0"
|
||||
buffer-fill "^1.0.0"
|
||||
|
||||
buffer-crc32@^0.2.1, buffer-crc32@~0.2.3:
|
||||
buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3:
|
||||
version "0.2.13"
|
||||
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
|
||||
@@ -4025,6 +4079,16 @@ compress-commons@^1.2.0:
|
||||
normalize-path "^2.0.0"
|
||||
readable-stream "^2.0.0"
|
||||
|
||||
compress-commons@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.0.1.tgz#c5fa908a791a0c71329fba211d73cd2a32005ea8"
|
||||
integrity sha512-xZm9o6iikekkI0GnXCmAl3LQGZj5TBDj0zLowsqi7tJtEa3FMGSEcHcqrSJIrOAk1UG/NBbDn/F1q+MG/p/EsA==
|
||||
dependencies:
|
||||
buffer-crc32 "^0.2.13"
|
||||
crc32-stream "^4.0.0"
|
||||
normalize-path "^3.0.0"
|
||||
readable-stream "^3.6.0"
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
@@ -4171,6 +4235,14 @@ crc32-stream@^2.0.0:
|
||||
crc "^3.4.4"
|
||||
readable-stream "^2.0.0"
|
||||
|
||||
crc32-stream@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.0.tgz#05b7ca047d831e98c215538666f372b756d91893"
|
||||
integrity sha512-tyMw2IeUX6t9jhgXI6um0eKfWq4EIDpfv5m7GX4Jzp7eVelQ360xd8EPXJhp2mHwLQIkqlnMLjzqSZI3a+0wRw==
|
||||
dependencies:
|
||||
crc "^3.4.4"
|
||||
readable-stream "^3.4.0"
|
||||
|
||||
crc@^3.4.4:
|
||||
version "3.8.0"
|
||||
resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6"
|
||||
@@ -8212,6 +8284,21 @@ lodash.debounce@4.0.8, lodash.debounce@^4.0.8:
|
||||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
|
||||
|
||||
lodash.defaults@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
|
||||
integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
|
||||
|
||||
lodash.difference@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c"
|
||||
integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=
|
||||
|
||||
lodash.flatten@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
|
||||
integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
|
||||
|
||||
lodash.isplainobject@^4.0.6:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
|
||||
@@ -8247,6 +8334,11 @@ lodash.throttle@^4.1.1:
|
||||
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
|
||||
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
|
||||
|
||||
lodash.union@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
|
||||
integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
|
||||
|
||||
lodash@^4.0.1, lodash@^4.16.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.8.0, lodash@~4.17.12, lodash@~4.17.4:
|
||||
version "4.17.19"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
|
||||
@@ -10107,7 +10199,7 @@ readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.1.4, readable
|
||||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readable-stream@^3.1.1, readable-stream@^3.4.0:
|
||||
readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
|
||||
@@ -10116,6 +10208,13 @@ readable-stream@^3.1.1, readable-stream@^3.4.0:
|
||||
string_decoder "^1.1.1"
|
||||
util-deprecate "^1.0.1"
|
||||
|
||||
readdir-glob@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.0.0.tgz#a495436934bbe57be6a68039d16e8946621eb8c5"
|
||||
integrity sha512-km0DIcwQVZ1ZUhXhMWpF74/Wm5aFEd5/jDiVWF1Hkw2myPQovG8vCQ8+FQO2KXE9npQQvCnAMZhhWuUee4WcCQ==
|
||||
dependencies:
|
||||
minimatch "^3.0.4"
|
||||
|
||||
realpath-native@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-2.0.0.tgz#7377ac429b6e1fd599dc38d08ed942d0d7beb866"
|
||||
@@ -11485,6 +11584,17 @@ tar-stream@^2.0.0:
|
||||
inherits "^2.0.3"
|
||||
readable-stream "^3.1.1"
|
||||
|
||||
tar-stream@^2.1.2:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.3.tgz#1e2022559221b7866161660f118255e20fa79e41"
|
||||
integrity sha512-Z9yri56Dih8IaK8gncVPx4Wqt86NDmQTSh49XLZgjWpGZL9GK9HKParS2scqHCC4w6X9Gh2jwaU45V47XTKwVA==
|
||||
dependencies:
|
||||
bl "^4.0.1"
|
||||
end-of-stream "^1.4.1"
|
||||
fs-constants "^1.0.0"
|
||||
inherits "^2.0.3"
|
||||
readable-stream "^3.1.1"
|
||||
|
||||
tar@^6.0.1:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.2.tgz#5df17813468a6264ff14f766886c622b84ae2f39"
|
||||
@@ -12141,6 +12251,11 @@ uuid@^8.1.0:
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d"
|
||||
integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg==
|
||||
|
||||
uuid@^8.3.0:
|
||||
version "8.3.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea"
|
||||
integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==
|
||||
|
||||
v8-compile-cache@^2.0.3:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
|
||||
@@ -12613,3 +12728,12 @@ zip-stream@^1.2.0:
|
||||
compress-commons "^1.2.0"
|
||||
lodash "^4.8.0"
|
||||
readable-stream "^2.0.0"
|
||||
|
||||
zip-stream@^4.0.0:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.0.2.tgz#3a20f1bd7729c2b59fd4efa04df5eb7a5a217d2e"
|
||||
integrity sha512-TGxB2g+1ur6MHkvM644DuZr8Uzyz0k0OYWtS3YlpfWBEmK4woaC2t3+pozEL3dBfIPmpgmClR5B2QRcMgGt22g==
|
||||
dependencies:
|
||||
archiver-utils "^2.1.0"
|
||||
compress-commons "^4.0.0"
|
||||
readable-stream "^3.6.0"
|
||||
|
||||
@@ -28,10 +28,22 @@ class FlipperCertificateProvider {
|
||||
const std::string& path,
|
||||
const std::string& deviceID) = 0;
|
||||
|
||||
/**
|
||||
* Sets certificate exchange medium
|
||||
*/
|
||||
virtual void setCertificateExchangeMedium(
|
||||
const FlipperCertificateExchangeMedium medium) = 0;
|
||||
|
||||
/**
|
||||
* Gets certificate exchange medium
|
||||
*/
|
||||
virtual FlipperCertificateExchangeMedium getCertificateExchangeMedium() = 0;
|
||||
|
||||
/**
|
||||
* This lets the Client know if it should reset the connection folder when
|
||||
* `stop` is called.
|
||||
*/
|
||||
virtual bool shouldResetCertificateFolder() = 0;
|
||||
};
|
||||
|
||||
} // namespace flipper
|
||||
|
||||
@@ -235,12 +235,15 @@ bool FlipperConnectionManagerImpl::connectSecurely() {
|
||||
if (deviceId.compare("unknown")) {
|
||||
loadingDeviceId->complete();
|
||||
}
|
||||
int medium = certProvider_ != nullptr
|
||||
? certProvider_->getCertificateExchangeMedium()
|
||||
: FlipperCertificateExchangeMedium::FS_ACCESS;
|
||||
|
||||
parameters.payload = rsocket::Payload(folly::toJson(folly::dynamic::object(
|
||||
"csr", contextStore_->getCertificateSigningRequest().c_str())(
|
||||
"csr_path", contextStore_->getCertificateDirectoryPath().c_str())(
|
||||
"os", deviceData_.os)("device", deviceData_.device)(
|
||||
"device_id", deviceId)("app", deviceData_.app)(
|
||||
"device_id", deviceId)("app", deviceData_.app)("medium", medium)(
|
||||
"sdk_version", sdkVersion)));
|
||||
address.setFromHostPort(deviceData_.host, securePort);
|
||||
|
||||
@@ -293,6 +296,9 @@ void FlipperConnectionManagerImpl::reconnect() {
|
||||
}
|
||||
|
||||
void FlipperConnectionManagerImpl::stop() {
|
||||
if (certProvider_ && certProvider_->shouldResetCertificateFolder()) {
|
||||
contextStore_->resetState();
|
||||
}
|
||||
if (!isStarted_) {
|
||||
log("Not started");
|
||||
return;
|
||||
@@ -353,10 +359,13 @@ void FlipperConnectionManagerImpl::requestSignedCertFromFlipper() {
|
||||
auto generatingCSR = flipperState_->start("Generate CSR");
|
||||
std::string csr = contextStore_->getCertificateSigningRequest();
|
||||
generatingCSR->complete();
|
||||
|
||||
int medium = certProvider_ != nullptr
|
||||
? certProvider_->getCertificateExchangeMedium()
|
||||
: FlipperCertificateExchangeMedium::FS_ACCESS;
|
||||
folly::dynamic message =
|
||||
folly::dynamic::object("method", "signCertificate")("csr", csr.c_str())(
|
||||
"destination", contextStore_->getCertificateDirectoryPath().c_str());
|
||||
"destination", contextStore_->getCertificateDirectoryPath().c_str())(
|
||||
"medium", medium);
|
||||
auto gettingCert = flipperState_->start("Getting cert from desktop");
|
||||
|
||||
flipperEventBase_->add([this, message, gettingCert]() {
|
||||
@@ -369,10 +378,32 @@ void FlipperConnectionManagerImpl::requestSignedCertFromFlipper() {
|
||||
folly::dynamic config = folly::parseJson(response);
|
||||
contextStore_->storeConnectionConfig(config);
|
||||
}
|
||||
gettingCert->complete();
|
||||
if (certProvider_) {
|
||||
auto gettingCertFromProvider =
|
||||
flipperState_->start("Getting cert from Cert Provider");
|
||||
|
||||
try {
|
||||
// Certificates should be present in app's sandbox after it is
|
||||
// returned. The reason we can't have a completion block here
|
||||
// is because if the certs are not present after it returns
|
||||
// then the flipper tries to reconnect on insecured channel
|
||||
// and recreates the app.csr. By the time completion block is
|
||||
// called the DeviceCA cert doesn't match app's csr and it
|
||||
// throws an SSL error.
|
||||
certProvider_->getCertificates(
|
||||
contextStore_->getCertificateDirectoryPath(),
|
||||
contextStore_->getDeviceId());
|
||||
gettingCertFromProvider->complete();
|
||||
} catch (std::exception& e) {
|
||||
gettingCertFromProvider->fail(e.what());
|
||||
gettingCert->fail(e.what());
|
||||
} catch (...) {
|
||||
gettingCertFromProvider->fail("Exception from certProvider");
|
||||
gettingCert->fail("Exception from certProvider");
|
||||
}
|
||||
}
|
||||
log("Certificate exchange complete.");
|
||||
// TODO: Use Certificate provider get Certificates
|
||||
// `certProvider_->getCertificates("path", "device");`
|
||||
gettingCert->complete();
|
||||
|
||||
// Disconnect after message sending is complete.
|
||||
// This will trigger a reconnect which should use the secure
|
||||
|
||||
Reference in New Issue
Block a user