Move keychain storage to server, some constants cleanup
Summary: This diff moves keychain storage to the server. Figured to leave request logic itself in the UI-core, as basically all use cases happen there, except for streaming download for mobile build plugin, so sending the requests from the backend doesn't really seem to add value, unless we run into some CORS issues later. Reviewed By: passy Differential Revision: D32596715 fbshipit-source-id: f5ab9d794f91a6eb8a8dc07ae723bf2890726771
This commit is contained in:
committed by
Facebook GitHub Bot
parent
bca169df73
commit
e742322eb1
@@ -26,7 +26,7 @@ import type {RenderHost} from 'flipper-ui-core';
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import {setupMenuBar} from './setupMenuBar';
|
import {setupMenuBar} from './setupMenuBar';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import {FlipperServerConfig} from 'flipper-common';
|
import {FlipperServer, FlipperServerConfig} from 'flipper-common';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
@@ -45,7 +45,10 @@ if (process.env.NODE_ENV === 'development' && os.platform() === 'darwin') {
|
|||||||
global.electronRequire('mac-ca');
|
global.electronRequire('mac-ca');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initializeElectron(flipperServerConfig: FlipperServerConfig) {
|
export function initializeElectron(
|
||||||
|
flipperServer: FlipperServer,
|
||||||
|
flipperServerConfig: FlipperServerConfig,
|
||||||
|
) {
|
||||||
const execPath = process.execPath || remote.process.execPath;
|
const execPath = process.execPath || remote.process.execPath;
|
||||||
const isProduction = !/node_modules[\\/]electron[\\/]/.test(execPath);
|
const isProduction = !/node_modules[\\/]electron[\\/]/.test(execPath);
|
||||||
|
|
||||||
@@ -191,6 +194,7 @@ export function initializeElectron(flipperServerConfig: FlipperServerConfig) {
|
|||||||
GK(gatekeeper) {
|
GK(gatekeeper) {
|
||||||
return flipperServerConfig.gatekeepers[gatekeeper] ?? false;
|
return flipperServerConfig.gatekeepers[gatekeeper] ?? false;
|
||||||
},
|
},
|
||||||
|
flipperServer,
|
||||||
};
|
};
|
||||||
|
|
||||||
setupMenuBar();
|
setupMenuBar();
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
loadSettings,
|
loadSettings,
|
||||||
setupPrefetcher,
|
setupPrefetcher,
|
||||||
} from 'flipper-server-core';
|
} from 'flipper-server-core';
|
||||||
import {getLogger, Logger, setLoggerInstance} from 'flipper-common';
|
import {getLogger, isTest, Logger, setLoggerInstance} from 'flipper-common';
|
||||||
import constants from './fb-stubs/constants';
|
import constants from './fb-stubs/constants';
|
||||||
import {initializeElectron} from './electron/initializeElectron';
|
import {initializeElectron} from './electron/initializeElectron';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
@@ -54,19 +54,31 @@ if (process.env.NODE_ENV === 'development' && os.platform() === 'darwin') {
|
|||||||
async function start() {
|
async function start() {
|
||||||
const app = remote.app;
|
const app = remote.app;
|
||||||
const execPath = process.execPath || remote.process.execPath;
|
const execPath = process.execPath || remote.process.execPath;
|
||||||
|
const appPath = app.getAppPath();
|
||||||
const isProduction = !/node_modules[\\/]electron[\\/]/.test(execPath);
|
const isProduction = !/node_modules[\\/]electron[\\/]/.test(execPath);
|
||||||
const env = process.env;
|
const env = process.env;
|
||||||
|
|
||||||
const logger = createDelegatedLogger();
|
const logger = createDelegatedLogger();
|
||||||
setLoggerInstance(logger);
|
setLoggerInstance(logger);
|
||||||
|
|
||||||
|
let keytar: any = undefined;
|
||||||
|
try {
|
||||||
|
if (!isTest()) {
|
||||||
|
keytar = (global.electronRequire || require)(
|
||||||
|
path.join(appPath, 'native-modules', `keytar-${process.platform}.node`),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to load keytar:', e);
|
||||||
|
}
|
||||||
|
|
||||||
const flipperServer = new FlipperServerImpl(
|
const flipperServer = new FlipperServerImpl(
|
||||||
{
|
{
|
||||||
env,
|
env,
|
||||||
gatekeepers: getGatekeepers(),
|
gatekeepers: getGatekeepers(),
|
||||||
isProduction,
|
isProduction,
|
||||||
paths: {
|
paths: {
|
||||||
appPath: app.getAppPath(),
|
appPath,
|
||||||
homePath: app.getPath('home'),
|
homePath: app.getPath('home'),
|
||||||
execPath,
|
execPath,
|
||||||
staticPath: getStaticDir(),
|
staticPath: getStaticDir(),
|
||||||
@@ -79,12 +91,13 @@ async function start() {
|
|||||||
validWebSocketOrigins: constants.VALID_WEB_SOCKET_REQUEST_ORIGIN_PREFIXES,
|
validWebSocketOrigins: constants.VALID_WEB_SOCKET_REQUEST_ORIGIN_PREFIXES,
|
||||||
},
|
},
|
||||||
logger,
|
logger,
|
||||||
|
keytar,
|
||||||
);
|
);
|
||||||
|
|
||||||
await flipperServer.connect();
|
await flipperServer.connect();
|
||||||
const flipperServerConfig = await flipperServer.exec('get-config');
|
const flipperServerConfig = await flipperServer.exec('get-config');
|
||||||
|
|
||||||
initializeElectron(flipperServerConfig);
|
initializeElectron(flipperServer, flipperServerConfig);
|
||||||
|
|
||||||
// By turning this in a require, we force the JS that the body of this module (init) has completed (initializeElectron),
|
// By turning this in a require, we force the JS that the body of this module (init) has completed (initializeElectron),
|
||||||
// before starting the rest of the Flipper process.
|
// before starting the rest of the Flipper process.
|
||||||
|
|||||||
@@ -155,13 +155,19 @@ export type FlipperServerCommands = {
|
|||||||
'ios-launch-simulator': (udid: string) => Promise<void>;
|
'ios-launch-simulator': (udid: string) => Promise<void>;
|
||||||
'persist-settings': (settings: Settings) => Promise<void>;
|
'persist-settings': (settings: Settings) => Promise<void>;
|
||||||
'persist-launcher-settings': (settings: LauncherSettings) => Promise<void>;
|
'persist-launcher-settings': (settings: LauncherSettings) => Promise<void>;
|
||||||
|
'keychain-write': (service: string, token: string) => Promise<void>;
|
||||||
|
'keychain-read': (service: string) => Promise<string>;
|
||||||
|
'keychain-unset': (service: string) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ENVIRONMENT_VARIABLES =
|
type ENVIRONMENT_VARIABLES =
|
||||||
| 'NODE_ENV'
|
| 'NODE_ENV'
|
||||||
| 'DEV_SERVER_URL'
|
| 'DEV_SERVER_URL'
|
||||||
| 'CONFIG'
|
| 'CONFIG'
|
||||||
| 'FLIPPER_ENABLED_PLUGINS';
|
| 'FLIPPER_ENABLED_PLUGINS'
|
||||||
|
| 'FB_ONDEMAND'
|
||||||
|
| 'FLIPPER_INTERNGRAPH_URL';
|
||||||
|
|
||||||
type ENVIRONMENT_PATHS =
|
type ENVIRONMENT_PATHS =
|
||||||
| 'appPath'
|
| 'appPath'
|
||||||
| 'homePath'
|
| 'homePath'
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import {launchEmulator} from './devices/android/AndroidDevice';
|
|||||||
import {setFlipperServerConfig} from './FlipperServerConfig';
|
import {setFlipperServerConfig} from './FlipperServerConfig';
|
||||||
import {saveSettings} from './utils/settings';
|
import {saveSettings} from './utils/settings';
|
||||||
import {saveLauncherSettings} from './utils/launcherSettings';
|
import {saveLauncherSettings} from './utils/launcherSettings';
|
||||||
|
import {KeytarManager} from './utils/keytar';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FlipperServer takes care of all incoming device & client connections.
|
* FlipperServer takes care of all incoming device & client connections.
|
||||||
@@ -51,12 +52,18 @@ export class FlipperServerImpl implements FlipperServer {
|
|||||||
state: FlipperServerState = 'pending';
|
state: FlipperServerState = 'pending';
|
||||||
android: AndroidDeviceManager;
|
android: AndroidDeviceManager;
|
||||||
ios: IOSDeviceManager;
|
ios: IOSDeviceManager;
|
||||||
|
keytarManager: KeytarManager;
|
||||||
|
|
||||||
constructor(public config: FlipperServerConfig, public logger: Logger) {
|
constructor(
|
||||||
|
public config: FlipperServerConfig,
|
||||||
|
public logger: Logger,
|
||||||
|
keytarModule?: any,
|
||||||
|
) {
|
||||||
setFlipperServerConfig(config);
|
setFlipperServerConfig(config);
|
||||||
const server = (this.server = new ServerController(this));
|
const server = (this.server = new ServerController(this));
|
||||||
this.android = new AndroidDeviceManager(this);
|
this.android = new AndroidDeviceManager(this);
|
||||||
this.ios = new IOSDeviceManager(this);
|
this.ios = new IOSDeviceManager(this);
|
||||||
|
this.keytarManager = new KeytarManager(keytarModule);
|
||||||
|
|
||||||
server.addListener('error', (err) => {
|
server.addListener('error', (err) => {
|
||||||
this.emit('server-error', err);
|
this.emit('server-error', err);
|
||||||
@@ -227,6 +234,10 @@ export class FlipperServerImpl implements FlipperServer {
|
|||||||
'persist-settings': async (settings) => saveSettings(settings),
|
'persist-settings': async (settings) => saveSettings(settings),
|
||||||
'persist-launcher-settings': async (settings) =>
|
'persist-launcher-settings': async (settings) =>
|
||||||
saveLauncherSettings(settings),
|
saveLauncherSettings(settings),
|
||||||
|
'keychain-read': (service) => this.keytarManager.retrieveToken(service),
|
||||||
|
'keychain-write': (service, password) =>
|
||||||
|
this.keytarManager.writeKeychain(service, password),
|
||||||
|
'keychain-unset': (service) => this.keytarManager.unsetKeychain(service),
|
||||||
};
|
};
|
||||||
|
|
||||||
registerDevice(device: ServerDevice) {
|
registerDevice(device: ServerDevice) {
|
||||||
|
|||||||
45
desktop/flipper-server-core/src/utils/keytar.tsx
Normal file
45
desktop/flipper-server-core/src/utils/keytar.tsx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* 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 os from 'os';
|
||||||
|
import {UserNotSignedInError} from 'flipper-common';
|
||||||
|
|
||||||
|
export class KeytarManager {
|
||||||
|
keytar: any;
|
||||||
|
|
||||||
|
constructor(keytarModule: any) {
|
||||||
|
this.keytar = keytarModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async writeKeychain(service: string, password: string): Promise<void> {
|
||||||
|
if (this.keytar == null) {
|
||||||
|
throw new Error('Keytar is not available.');
|
||||||
|
}
|
||||||
|
await this.keytar.deletePassword(service, os.userInfo().username);
|
||||||
|
await this.keytar.setPassword(service, os.userInfo().username, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async unsetKeychain(service: string): Promise<void> {
|
||||||
|
await this.keytar.deletePassword(service, os.userInfo().username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async retrieveToken(service: string): Promise<string> {
|
||||||
|
if (this.keytar == null) {
|
||||||
|
throw new Error('Keytar is not available.');
|
||||||
|
}
|
||||||
|
const token = await this.keytar.getPassword(
|
||||||
|
service,
|
||||||
|
os.userInfo().username,
|
||||||
|
);
|
||||||
|
if (!token) {
|
||||||
|
throw new UserNotSignedInError();
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,12 @@ import type {NotificationEvents} from './dispatcher/notifications';
|
|||||||
import type {PluginNotification} from './reducers/notifications';
|
import type {PluginNotification} from './reducers/notifications';
|
||||||
import type {NotificationConstructorOptions} from 'electron';
|
import type {NotificationConstructorOptions} from 'electron';
|
||||||
import {FlipperLib} from 'flipper-plugin';
|
import {FlipperLib} from 'flipper-plugin';
|
||||||
import {FlipperServerConfig, ReleaseChannel, Tristate} from 'flipper-common';
|
import {
|
||||||
|
FlipperServer,
|
||||||
|
FlipperServerConfig,
|
||||||
|
ReleaseChannel,
|
||||||
|
Tristate,
|
||||||
|
} from 'flipper-common';
|
||||||
// TODO: those imports are only used for testing, require conditionally?
|
// TODO: those imports are only used for testing, require conditionally?
|
||||||
import {tmpdir} from 'os';
|
import {tmpdir} from 'os';
|
||||||
import {resolve} from 'path';
|
import {resolve} from 'path';
|
||||||
@@ -99,6 +104,7 @@ export interface RenderHost {
|
|||||||
openLink(url: string): void;
|
openLink(url: string): void;
|
||||||
loadDefaultPlugins(): Record<string, any>;
|
loadDefaultPlugins(): Record<string, any>;
|
||||||
GK(gatekeeper: string): boolean;
|
GK(gatekeeper: string): boolean;
|
||||||
|
flipperServer?: FlipperServer;
|
||||||
serverConfig: FlipperServerConfig;
|
serverConfig: FlipperServerConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,4 +42,7 @@ export default Object.freeze({
|
|||||||
},
|
},
|
||||||
|
|
||||||
SUPPORT_GROUPS: [],
|
SUPPORT_GROUPS: [],
|
||||||
|
|
||||||
|
INTERN_URL: '',
|
||||||
|
INTERNGRAPH_API: '',
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user