Skip to content

Commit

Permalink
Merge pull request #3707 from Emurgo/fix/ff-message-passing
Browse files Browse the repository at this point in the history
updated message passing
  • Loading branch information
vsubhuman authored Nov 14, 2024
2 parents 3ff9767 + f6be653 commit 80e1037
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 20 deletions.
54 changes: 44 additions & 10 deletions packages/yoroi-extension/app/api/thunk.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,12 @@ declare var chrome;

// UI -> background queries:

export function callBackground<T, R>(message: T): Promise<R> {
export function callBackground<R>(message: {| type: string, request?: Object |}): Promise<R> {
return new Promise((resolve, reject) => {
window.chrome.runtime.sendMessage(message, response => {
const serializedMessage = { type: message.type, request: JSON.stringify(message.request ?? null) };
window.chrome.runtime.sendMessage(serializedMessage, response => {
// $FlowIgnore
console.debug(`CLIENT [${message.type}] received result: `, JSON.stringify(sanitizeForLog(response)));
if (window.chrome.runtime.lastError) {
// eslint-disable-next-line prefer-promise-reject-errors
reject(`Error ${window.chrome.runtime.lastError} when calling the background with: ${JSON.stringify(sanitizeForLog(message)) ?? 'undefined'}`);
Expand Down Expand Up @@ -290,7 +293,8 @@ export async function removeAllTransactions(
}
}

export const popAddress: GetEntryFuncType<typeof PopAddress> = async ({ publicDeriverId }) => {
type PopAddressType = ({ publicDeriverId: number, ...}) => ReturnType<GetEntryFuncType<typeof PopAddress>>;
export const popAddress: PopAddressType = async ({ publicDeriverId }) => {
await callBackground({ type: PopAddress.typeTag, request: { publicDeriverId } });
}

Expand All @@ -306,11 +310,12 @@ function deserializeTx(tx: any): ?WalletTransaction {
}

export const refreshTransactions: GetEntryFuncType<typeof RefreshTransactions> = async (request) => {
const txs = await callBackground({ type: 'refresh-transactions', request });
if (txs.error) {
console.error('Failed to refresh transactions!', txs.error);
const resp = await callBackground({ type: RefreshTransactions.typeTag, request });
if (resp.error) {
console.error('Failed to refresh transactions!', resp.error);
return [];
}
const txs = JSON.parse(resp);
return txs.map(tx => {
try {
return deserializeTx(tx);
Expand Down Expand Up @@ -398,8 +403,11 @@ export const getConnectedSites: GetEntryFuncType<typeof GetConnectedSites> = asy
return await callBackground({ type: GetConnectedSites.typeTag });
}

export const getProtocolParameters: GetEntryFuncType<typeof GetProtocolParameters> = async (request) => {
return await callBackground({ type: GetProtocolParameters.typeTag, request });
type GetProtocolParametersType = ({ networkId: number, ... }) => ReturnType<GetEntryFuncType<typeof GetProtocolParameters>>;
export const getProtocolParameters: GetProtocolParametersType = async (
{ networkId }
) => {
return await callBackground({ type: GetProtocolParameters.typeTag, request: { networkId } });
}

// Background -> UI notifications:
Expand All @@ -408,8 +416,34 @@ const callbacks = Object.freeze({
serverStatusUpdate: [],
coinPriceUpdate: [],
});
chrome.runtime.onMessage.addListener(async (message, _sender, _sendResponse) => {
//fixme: verify sender.id/origin
const APP_ORIGIN = window.location.origin || null;
const EXPECTED_MESSAGE_TYPE = 'yoroi-emit-update';
chrome.runtime.onMessage.addListener((rawMessage, { origin }, _sendResponse) => {
if (APP_ORIGIN != null && origin !== APP_ORIGIN) {
Logger.debug('[client] ignoring non-origin message (' + origin + '/' + APP_ORIGIN + ')');
return;
}
if (rawMessage.type !== EXPECTED_MESSAGE_TYPE) {
Logger.debug('[client] ignoring unknown type message (' + rawMessage.type + '/' + EXPECTED_MESSAGE_TYPE + ')');
return;
}
const serializedMessage = rawMessage.data;
const messageType = typeof serializedMessage;
if (messageType !== 'string') {
Logger.error('[client] unexpected message type (' + messageType + ') a JSON string is expected, but received: ' + JSON.stringify(sanitizeForLog(serializedMessage)));
return;
}
let message;
try {
message = JSON.parse(serializedMessage);
} catch (error) {
Logger.error('unparsable message: ' + serializedMessage + ' | Error: ' + stringifyError(error));
return;
}
if (typeof message !== 'object') {
Logger.error('unrecognizable message type: ' + (typeof message) + ' (expected object); Original message: ' + serializedMessage);
return;
}
Logger.debug('get message from background:', JSON.stringify(sanitizeForLog(message)));

if (message.type === 'wallet-state-update') {
Expand Down
8 changes: 5 additions & 3 deletions packages/yoroi-extension/app/coreUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,13 @@ export function timeCached<R>(fun: () => R, ttl: number): () => R {
* @return same value or a copy in case the value is an object
*/
export function sanitizeForLog(v: any): any {
const fields: Array<any> = ['password'];
if (v != null && typeof v === 'object') {
let r = Object.keys(v).reduce((o, k) => ({ ...o, [k]: sanitizeForLog(v[k]) }) , {})
// $FlowIgnore[incompatible-use]
if (r.password != null) {
r = { ...r, password: '[sanitized]' };
for (const f of fields) {
if (r[f] != null) {
r = { ...r, [f]: '[sanitized]' };
}
}
return r;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,11 @@ export function deserializeTransactionCtorData(
state: serializedData.state,
errorMsg: serializedData.errorMsg,
certificates: serializedData.certificates,
ttl: serializedData.ttl && new BigNumber(serializedData.ttl),
ttl: serializedData.ttl && new BigNumber(
typeof serializedData.ttl === 'object'
? { ...serializedData.ttl, _isBigNumber: true }
: serializedData.ttl
),
metadata: serializedData.metadata,
withdrawals: serializedData.withdrawals.map(({ address, value }) => ({
address,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
} from './connector';
import { GetProtocolParameters } from './protocolParameters';
import { subscribe } from '../../subscriptionManager';
import { sanitizeForLog } from '../../../../../app/coreUtils';

const handlerMap = Object.freeze({
[GetHistoricalCoinPrices.typeTag]: GetHistoricalCoinPrices.handle,
Expand Down Expand Up @@ -107,6 +108,7 @@ export function getHandler(typeTag: string): ?Handler {
return async (request, send, sendResponse) => {
try {
const result = await handler(request.request);
console.debug(`BACKGROUND [${typeTag}] sending result: `, JSON.stringify(sanitizeForLog(result)));
sendResponse(result);
} catch (error) {
sendResponse({ error: error.message });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ class ProcolParameterApi {
}

export const GetProtocolParameters: HandlerType<
{ networkId: number, ... },
{| networkId: number |},
ProtocolParameters
> = Object.freeze({
typeTag: 'get-protocol-parameters',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ export const GetPrivateStakingKey: HandlerType<
});

export const RemoveAllTransactions: HandlerType<
{ publicDeriverId: number, ... },
{| publicDeriverId: number |},
void
> = Object.freeze({
typeTag: 'remove-all-transactions',
Expand All @@ -275,7 +275,7 @@ export const RemoveAllTransactions: HandlerType<
});

export const PopAddress: HandlerType<
{ publicDeriverId: number, ... },
{| publicDeriverId: number |},
void
> = Object.freeze({
typeTag: 'pop-address',
Expand Down Expand Up @@ -354,6 +354,7 @@ export const RefreshTransactions: HandlerType<
// initial transaction list loading
txs = await adaApi.refreshTransactions(refreshTxRequest);
}
return txs;
// $FlowIgnore
return JSON.stringify(txs);
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
}
const handler = getHandler(message.type);
if (handler) {
handler(message, sender, sendResponse);
const deserializedMessage = {
type: message.type,
request: JSON.parse(message.request),
};
handler(deserializedMessage, sender, sendResponse);
// Returning `true` is required by Firefox, see:
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,6 @@ declare var chrome;
*/
export function emitUpdateToSubscriptions(data: Object): void {
for (const { tabId } of getSubscriptions()) {
chrome.tabs.sendMessage(tabId, data);
chrome.tabs.sendMessage(tabId, { type: 'yoroi-emit-update', data: JSON.stringify(data) });
}
}

0 comments on commit 80e1037

Please sign in to comment.