format import ServerWebSocket , { ConnectionCtx } from './ServerWebSocket' ; import { SecureClientQuery } from './ServerAdapter' ; import { ParsedUrlQuery } from 'querystring' ; import { ClientDescription } from 'flipper-common' ; import { isWsResponseMessage , parseSecureClientQuery , assertNotNull , } from './Utilities' ; import WebSocketClientConnection from './WebSocketClientConnection' ; import { serializeError } from 'serialize-error' ; import { WSCloseCode } from '../utils/WSCloseCode' ; export interface SecureConnectionCtx extends ConnectionCtx { clientQuery ? : SecureClientQuery ; clientConnection ? : WebSocketClientConnection ; clientPromise ? : Promise < ClientDescription > ; client ? : ClientDescription ; } /**
 * WebSocket-based server.
 * A secure connection has been established between the server and a client. Once a client
 * has a valid certificate, it can use a secure connection with Flipper and start exchanging
 * messages.
 * https://fbflipper.com/docs/extending/new-clients
 * https://fbflipper.com/docs/extending/establishing-a-connection
 */ class SecureServerWebSocket extends ServerWebSocket { protected handleConnectionAttempt ( ctx ) { const { clientQuery , ws } = ctx ; assertNotNull ( clientQuery ) ; console . info ( `[conn] Secure websocket connection attempt: ${ clientQuery . app } on ${ clientQuery . device_id }. Medium ${ clientQuery . medium }. CSR: ${ clientQuery . csr_path }` ) ; this . listener . onSecureConnectionAttempt ( clientQuery ) ; const clientConnection = new WebSocketClientConnection ( ws ) ; const clientPromise = this . listener . onConnectionCreated ( clientQuery , clientConnection ) . then ( ( client ) => { ctx . client = client ; return client ; } ) . catch ( ( e ) => { throw new Error ( `Failed to resolve client ${ clientQuery . app } on ${ clientQuery . device_id } medium ${ clientQuery . medium }. Reason: ${ JSON . stringify ( serializeError ( e ) ) }` ) ; } ) ; ctx . clientConnection = clientConnection ; ctx . clientPromise = clientPromise ; } protected async handleMessage ( ctx , parsedMessage , rawMessage ) { const { clientQuery , clientConnection , clientPromise , client , ws } = ctx ; assertNotNull ( clientQuery ) ; assertNotNull ( clientConnection ) ; assertNotNull ( clientPromise ) ; if ( isWsResponseMessage ( parsedMessage ) ) { const callbacks = clientConnection . matchPendingRequest ( parsedMessage . id ) ; if ( ! callbacks ) { return ; } callbacks . resolve ( { ... parsedMessage , length : rawMessage . length , } ) ; return ; } if ( client ) { this . listener . onClientMessage ( client . id , rawMessage ) ; } else { clientPromise . then ( ( client ) => { this . listener . onClientMessage ( client . id , rawMessage ) ; } ) . catch ( ( error ) => { if ( ws . readyState === ws . OPEN ) { ws . emit ( 'error' , error ) ; ws . close ( WSCloseCode . InternalError ) ; } } ) ; } } param message protected parseClientQuery ( query ) { return parseSecureClientQuery ( query ) ; } } export default SecureServerWebSocket ;