import { E164Number } from '@celo/utils/lib/io' ; import crypto from 'crypto' ; import debugFactory from 'debug' ; import { AuthenticationMethod , AuthSigner , EncryptionKeySigner , MatchmakingRequest , MatchmakingResponse , queryOdis , ServiceContext , signWithDEK , } from './query' ; const debug = debugFactory ( 'kit:odis:matchmaking' ) ; const MATCHMAKING_ENDPOINT = '/getContactMatches' ; const SALT = '__celo__' ; export async function getContactMatches ( e164NumberCaller , e164NumberContacts , account , phoneNumberIdentifier , signer , context , dekSigner ? , clientVersion ? , sessionID ? ) { const selfPhoneNumObfuscated = obfuscateNumberForMatchmaking ( e164NumberCaller ) ; const obfucsatedNumToE164Number = getContactNumsObfuscated ( e164NumberContacts ) ; const body = { account , userPhoneNumber : selfPhoneNumObfuscated , contactPhoneNumbers : Object . keys ( obfucsatedNumToE164Number ) , hashedPhoneNumber : phoneNumberIdentifier , version : clientVersion ? clientVersion : 'unknown' , authenticationMethod : signer . authenticationMethod } ; if ( sessionID ) { body . sessionID = sessionID ; } if ( signer . authenticationMethod === AuthenticationMethod . ENCRYPTION_KEY ) { dekSigner = signer ; } if ( dekSigner ) { body . signedUserPhoneNumber = signWithDEK ( selfPhoneNumObfuscated , dekSigner ) ; } else { console . warn ( 'Failure to provide DEK will prevent users from requerying their matches' ) ; } const response = await queryOdis < MatchmakingResponse > ( signer , body , context , MATCHMAKING_ENDPOINT ) ; const matchHashes = response . matchedContacts . map ( ( match ) => match . phoneNumber ) ; if ( ! matchHashes || ! matchHashes . length ) { debug ( 'No matches found' ) ; return [ ] ; } return getMatchedContacts ( obfucsatedNumToE164Number , matchHashes ) ; } function getContactNumsObfuscated ( e164NumberMatches ) { const hashes = { } ; for ( const e164Number of e164NumberMatches ) { const hash = obfuscateNumberForMatchmaking ( e164Number ) ; hashes [ hash ] = e164Number ; } return hashes ; } export function obfuscateNumberForMatchmaking ( e164Number ) { return crypto . createHash ( 'sha256' ) . update ( e164Number + SALT ) . digest ( 'base64' ) ; } param obfucsatedNumToE164Number param matchHashes function getMatchedContacts ( obfucsatedNumToE164Number , matchHashes ) { const matches = [ ] ; for ( const match of matchHashes ) { const e164Number = obfucsatedNumToE164Number [ match ] ; if ( ! e164Number ) { throw new Error ( 'Number missing in hash map, should never happen' ) ; } matches . push ( e164Number ) ; } return matches ; }