Fix Android Connection Swap Issue (Server Side)
Summary: - Take device id retrieved by matching CSR to the given CSR destination - Otherwise, use the previous way Note: - Backward compatibility will be fixed next diff Reviewed By: jknoxville Differential Revision: D17346422 fbshipit-source-id: 59b2fb9849373db1ba930dde702194c5fb201678
This commit is contained in:
committed by
Facebook Github Bot
parent
88197a7076
commit
2239ca65a5
@@ -112,7 +112,6 @@ export default class Client extends EventEmitter {
|
||||
lessPlugins: Plugins | undefined;
|
||||
showAllPlugins: boolean;
|
||||
connection: RSocketClientSocket<any, any> | null | undefined;
|
||||
responder: Partial<Responder<string, any>>;
|
||||
store: Store;
|
||||
activePlugins: Set<string>;
|
||||
device: Promise<BaseDevice>;
|
||||
@@ -121,6 +120,7 @@ export default class Client extends EventEmitter {
|
||||
logger: Logger;
|
||||
lastSeenDeviceList: Array<BaseDevice>;
|
||||
broadcastCallbacks: Map<string, Map<string, Set<Function>>>;
|
||||
rIC: any;
|
||||
|
||||
requestCallbacks: Map<
|
||||
number,
|
||||
@@ -162,19 +162,12 @@ export default class Client extends EventEmitter {
|
||||
|
||||
const client = this;
|
||||
// node.js doesn't support requestIdleCallback
|
||||
const rIC =
|
||||
this.rIC =
|
||||
typeof window === 'undefined'
|
||||
? (cb: Function, _: any) => {
|
||||
cb();
|
||||
}
|
||||
: window.requestIdleCallback;
|
||||
|
||||
this.responder = {
|
||||
fireAndForget: (payload: {data: string}) =>
|
||||
rIC(() => client.onMessage(payload.data), {
|
||||
timeout: 500,
|
||||
}),
|
||||
};
|
||||
: window.requestIdleCallback.bind(window);
|
||||
|
||||
if (conn) {
|
||||
conn.connectionStatus().subscribe({
|
||||
|
||||
113
src/server.tsx
113
src/server.tsx
@@ -28,6 +28,11 @@ type ClientInfo = {
|
||||
client: Client;
|
||||
};
|
||||
|
||||
type ClientCsrQuery = {
|
||||
csr?: string | undefined;
|
||||
csr_path?: string | undefined;
|
||||
};
|
||||
|
||||
declare interface Server {
|
||||
on(event: 'new-client', callback: (client: Client) => void): this;
|
||||
on(event: 'error', callback: (err: Error) => void): this;
|
||||
@@ -124,16 +129,24 @@ class Server extends EventEmitter {
|
||||
if (!payload.data) {
|
||||
return {};
|
||||
}
|
||||
const clientData: ClientQuery = JSON.parse(payload.data);
|
||||
const clientData: ClientQuery & ClientCsrQuery = JSON.parse(payload.data);
|
||||
this.connectionTracker.logConnectionAttempt(clientData);
|
||||
|
||||
const client = this.addConnection(socket, clientData);
|
||||
const {app, os, device, device_id, sdk_version, csr, csr_path} = clientData;
|
||||
|
||||
const client: Promise<Client> = this.addConnection(
|
||||
socket,
|
||||
{app, os, device, device_id, sdk_version},
|
||||
{csr, csr_path},
|
||||
);
|
||||
|
||||
socket.connectionStatus().subscribe({
|
||||
onNext(payload) {
|
||||
if (payload.kind == 'ERROR' || payload.kind == 'CLOSED') {
|
||||
console.debug(`Device disconnected ${client.id}`, 'server');
|
||||
server.removeConnection(client.id);
|
||||
client.then(client => {
|
||||
console.debug(`Device disconnected ${client.id}`, 'server');
|
||||
server.removeConnection(client.id);
|
||||
});
|
||||
}
|
||||
},
|
||||
onSubscribe(subscription) {
|
||||
@@ -141,7 +154,14 @@ class Server extends EventEmitter {
|
||||
},
|
||||
});
|
||||
|
||||
return client.responder;
|
||||
return {
|
||||
fireAndForget: (payload: {data: string}) =>
|
||||
client.then(client => {
|
||||
client.rIC(() => client.onMessage(payload.data), {
|
||||
timeout: 500,
|
||||
});
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
_untrustedRequestHandler = (
|
||||
@@ -272,49 +292,66 @@ class Server extends EventEmitter {
|
||||
return null;
|
||||
}
|
||||
|
||||
addConnection(
|
||||
async addConnection(
|
||||
conn: RSocketClientSocket<any, any>,
|
||||
query: ClientQuery,
|
||||
): Client {
|
||||
csrQuery: ClientCsrQuery,
|
||||
): Promise<Client> {
|
||||
invariant(query, 'expected query');
|
||||
|
||||
const id = `${query.app}#${query.os}#${query.device}#${query.device_id}`;
|
||||
console.debug(`Device connected: ${id}`, 'server');
|
||||
// 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
|
||||
? this.certificateProvider.extractAppNameFromCSR(csr).then(appName => {
|
||||
return this.certificateProvider.getTargetDeviceId(
|
||||
query.os,
|
||||
appName,
|
||||
csr_path,
|
||||
csr,
|
||||
);
|
||||
})
|
||||
: Promise.resolve(query.device_id)
|
||||
).then(csrId => {
|
||||
query.device_id = csrId;
|
||||
const id = `${query.app}#${query.os}#${query.device}#${csrId}`;
|
||||
console.debug(`Device connected: ${id}`, 'server');
|
||||
|
||||
const client = new Client(id, query, conn, this.logger, this.store);
|
||||
const client = new Client(id, query, conn, this.logger, this.store);
|
||||
|
||||
const info = {
|
||||
client,
|
||||
connection: conn,
|
||||
};
|
||||
const info = {
|
||||
client,
|
||||
connection: conn,
|
||||
};
|
||||
|
||||
client.init().then(() => {
|
||||
console.debug(
|
||||
`Device client initialised: ${id}. Supported plugins: ${client.plugins.join(
|
||||
', ',
|
||||
)}`,
|
||||
'server',
|
||||
);
|
||||
client.init().then(() => {
|
||||
console.debug(
|
||||
`Device client initialised: ${id}. Supported plugins: ${client.plugins.join(
|
||||
', ',
|
||||
)}`,
|
||||
'server',
|
||||
);
|
||||
|
||||
/* If a device gets disconnected without being cleaned up properly,
|
||||
* Flipper won't be aware until it attempts to reconnect.
|
||||
* When it does we need to terminate the zombie connection.
|
||||
*/
|
||||
if (this.connections.has(id)) {
|
||||
const connectionInfo = this.connections.get(id);
|
||||
connectionInfo &&
|
||||
connectionInfo.connection &&
|
||||
connectionInfo.connection.close();
|
||||
this.removeConnection(id);
|
||||
}
|
||||
/* If a device gets disconnected without being cleaned up properly,
|
||||
* Flipper won't be aware until it attempts to reconnect.
|
||||
* When it does we need to terminate the zombie connection.
|
||||
*/
|
||||
if (this.connections.has(id)) {
|
||||
const connectionInfo = this.connections.get(id);
|
||||
connectionInfo &&
|
||||
connectionInfo.connection &&
|
||||
connectionInfo.connection.close();
|
||||
this.removeConnection(id);
|
||||
}
|
||||
|
||||
this.connections.set(id, info);
|
||||
this.emit('new-client', client);
|
||||
this.emit('clients-change');
|
||||
client.emit('plugins-change');
|
||||
this.connections.set(id, info);
|
||||
this.emit('new-client', client);
|
||||
this.emit('clients-change');
|
||||
client.emit('plugins-change');
|
||||
});
|
||||
|
||||
return client;
|
||||
});
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
attachFakeClient(client: Client) {
|
||||
|
||||
@@ -346,7 +346,12 @@ export default class CertificateProvider {
|
||||
return androidUtil
|
||||
.pull(deviceId, processName, directory + csrFileName)
|
||||
.then(deviceCsr => {
|
||||
return this.santitizeString(deviceCsr.toString()) === csr;
|
||||
// Santitize both of the string before comparation
|
||||
// The csr string extraction on client side return string in both way
|
||||
return (
|
||||
this.santitizeString(deviceCsr.toString()) ===
|
||||
this.santitizeString(csr)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user