Prepare desktop app for requestResponse CSR change

Summary:
[Step 1 of a protocol change between desktop app and flipper agent]

The flipper agent periodically tries to connect.
When it doesn't have the required certs, instead of trying to connect, it requests them from the desktop.
After requesting, it just continues the loop, trying to request.

The problem with that is
a) the desktop can take longer than one cycle to generate and provide the certs, meaning the agent will make overlapping requests, causing confusion and it to take longer than necessary.
b) the desktop can take less time than a retry cycle, but the agent will still wait before trying to connect.

Fixing a) by making the agent wait for a response from the desktop before continuing attempting to reconnect.
This means on the next connection attempt, it's guaranteed that the desktop is finished processing the CSR.

b) remains unfixed for now, but can be dealt with separately.

This is step 1 which adds an extra responder to the desktop app. It won't change anything until the agent starts
sending requestResponse messages instead of fireAndForgets. The plan is to leave this in place for a while to give users time to update, after that, we'll roll out the change to the agent.

Reviewed By: passy

Differential Revision: D9179392

fbshipit-source-id: 9a8021253dcd28c15cceeec23630a67aec219fd5
This commit is contained in:
John Knox
2018-08-07 06:29:25 -07:00
committed by Facebook Github Bot
parent a92b6eaf80
commit f73c28ba6b
3 changed files with 130 additions and 7 deletions

View File

@@ -0,0 +1,81 @@
// flow-typed signature: 06cae6786a7bab166b894590a59b8780
// flow-typed version: <<STUB>>/rsocket-flowable_v0.0.6/flow_v0.76.0
/**
* This is an autogenerated libdef stub for:
*
* 'rsocket-flowable'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/
declare module 'rsocket-flowable' {
declare module.exports: any;
}
/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module 'rsocket-flowable/build/Flowable' {
declare module.exports: any;
}
declare module 'rsocket-flowable/build/FlowableMapOperator' {
declare module.exports: any;
}
declare module 'rsocket-flowable/build/FlowableRequestOperator' {
declare module.exports: any;
}
declare module 'rsocket-flowable/build/FlowableTakeOperator' {
declare module.exports: any;
}
declare module 'rsocket-flowable/build/FlowableTimer' {
declare module.exports: any;
}
declare module 'rsocket-flowable/build/haste/rsocket-flowable' {
declare module.exports: any;
}
declare module 'rsocket-flowable/build/index' {
declare module.exports: any;
}
declare module 'rsocket-flowable/build/Single' {
declare module.exports: any;
}
// Filename aliases
declare module 'rsocket-flowable/build/Flowable.js' {
declare module.exports: $Exports<'rsocket-flowable/build/Flowable'>;
}
declare module 'rsocket-flowable/build/FlowableMapOperator.js' {
declare module.exports: $Exports<'rsocket-flowable/build/FlowableMapOperator'>;
}
declare module 'rsocket-flowable/build/FlowableRequestOperator.js' {
declare module.exports: $Exports<'rsocket-flowable/build/FlowableRequestOperator'>;
}
declare module 'rsocket-flowable/build/FlowableTakeOperator.js' {
declare module.exports: $Exports<'rsocket-flowable/build/FlowableTakeOperator'>;
}
declare module 'rsocket-flowable/build/FlowableTimer.js' {
declare module.exports: $Exports<'rsocket-flowable/build/FlowableTimer'>;
}
declare module 'rsocket-flowable/build/haste/rsocket-flowable.js' {
declare module.exports: $Exports<'rsocket-flowable/build/haste/rsocket-flowable'>;
}
declare module 'rsocket-flowable/build/index.js' {
declare module.exports: $Exports<'rsocket-flowable/build/index'>;
}
declare module 'rsocket-flowable/build/Single.js' {
declare module.exports: $Exports<'rsocket-flowable/build/Single'>;
}

View File

@@ -12,6 +12,7 @@ import type {ClientQuery} from './Client.js';
import CertificateProvider from './utils/CertificateProvider';
import {RSocketServer, ReactiveSocket} from 'rsocket-core';
import RSocketTCPServer from 'rsocket-tcp-server';
import {Single} from 'rsocket-flowable';
import Client from './Client.js';
import {RecurringError} from './utils/errors';
@@ -155,6 +156,48 @@ export default class Server extends EventEmitter {
}
return {
requestResponse: (payload: {data: string}) => {
if (typeof payload.data !== 'string') {
return;
}
let rawData;
try {
rawData = JSON.parse(payload.data);
} catch (err) {
console.error(`Invalid JSON: ${payload.data}`, 'clientMessage');
return;
}
const json: {|
method: 'signCertificate',
csr: string,
destination: string,
|} = rawData;
if (json.method === 'signCertificate') {
console.warn('CSR received from device', 'server');
const {csr, destination} = json;
return new Single(subscriber => {
subscriber.onSubscribe();
this.certificateProvider
.processCertificateSigningRequest(csr, clientData.os, destination)
.then(_ => {
subscriber.onComplete({
data: JSON.stringify({}),
metadata: '',
});
})
.catch(e => {
console.error(e);
subscriber.onError(e);
});
});
}
},
// Leaving this here for a while for backwards compatibility,
// but for up to date SDKs it will no longer used.
// We can delete it after the SDK change has been using requestResponse for a few weeks.
fireAndForget: (payload: {data: string}) => {
if (typeof payload.data !== 'string') {
return;
@@ -176,11 +219,11 @@ export default class Server extends EventEmitter {
if (json.method === 'signCertificate') {
console.warn('CSR received from device', 'server');
const {csr, destination} = json;
this.certificateProvider.processCertificateSigningRequest(
csr,
clientData.os,
destination,
);
this.certificateProvider
.processCertificateSigningRequest(csr, clientData.os, destination)
.catch(e => {
console.error(e);
});
}
},
};

View File

@@ -100,8 +100,7 @@ export default class CertificateProvider {
csr,
os,
),
)
.catch(e => console.error(e));
);
}
ensureOpenSSLIsAvailable(): void {