Skip to content

Commit

Permalink
Merge branch 'develop' into refactor-inject-inpage
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmurdoch authored Feb 6, 2024
2 parents fe07fc6 + 82e0029 commit e5f2b68
Show file tree
Hide file tree
Showing 23 changed files with 546 additions and 44 deletions.
14 changes: 13 additions & 1 deletion app/scripts/controllers/app-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export default class AppStateController extends EventEmitter {
'0x539': true,
},
surveyLinkLastClickedOrClosed: null,
signatureSecurityAlertResponses: {},
});
this.timer = null;

Expand Down Expand Up @@ -441,8 +442,19 @@ export default class AppStateController extends EventEmitter {
},
});
}

///: END:ONLY_INCLUDE_IF

addSignatureSecurityAlertResponse(securityAlertResponse) {
const currentState = this.store.getState();
const { signatureSecurityAlertResponses } = currentState;
this.store.updateState({
signatureSecurityAlertResponses: {
...signatureSecurityAlertResponses,
[securityAlertResponse.securityAlertId]: securityAlertResponse,
},
});
}

/**
* A setter for the currentPopupId which indicates the id of popup window that's currently active
*
Expand Down
10 changes: 10 additions & 0 deletions app/scripts/controllers/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export default class PreferencesController {
},
// ENS decentralized website resolution
ipfsGateway: IPFS_DEFAULT_GATEWAY_URL,
isIpfsGatewayEnabled: true,
useAddressBarEnsResolution: true,
// Ledger transport type is deprecated. We currently only support webhid
// on chrome, and u2f on firefox.
Expand Down Expand Up @@ -577,6 +578,15 @@ export default class PreferencesController {
return domain;
}

/**
* A setter for the `isIpfsGatewayEnabled` property
*
* @param {boolean} enabled - Whether or not IPFS is enabled
*/
async setIsIpfsGatewayEnabled(enabled) {
this.store.updateState({ isIpfsGatewayEnabled: enabled });
}

/**
* A setter for the `useAddressBarEnsResolution` property
*
Expand Down
2 changes: 1 addition & 1 deletion app/scripts/lib/ppom/ppom-middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ describe('PPOMMiddleware', () => {
const usePPOM = async () => {
throw new Error('some error');
};
const middlewareFunction = createMiddleWare(usePPOM);
const middlewareFunction = createMiddleWare({ usePPOM });
const req = {
method: 'eth_sendTransaction',
securityAlertResponse: undefined,
Expand Down
62 changes: 49 additions & 13 deletions app/scripts/lib/ppom/ppom-middleware.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import { PPOM } from '@blockaid/ppom_release';
import { PPOMController } from '@metamask/ppom-validator';
import { NetworkController } from '@metamask/network-controller';
import { v4 as uuid } from 'uuid';

import {
BlockaidReason,
BlockaidResultType,
} from '../../../../shared/constants/security-provider';
import { CHAIN_IDS } from '../../../../shared/constants/network';
import { SIGNING_METHODS } from '../../../../shared/constants/transaction';
import { PreferencesController } from '../../controllers/preferences';
import { SecurityAlertResponse } from '../transaction/util';

const { sentry } = global as any;

const ConfirmationMethods = Object.freeze([
const CONFIRMATION_METHODS = Object.freeze([
'eth_sendRawTransaction',
'eth_sendTransaction',
'eth_sign',
'eth_signTypedData',
'eth_signTypedData_v1',
'eth_signTypedData_v3',
'eth_signTypedData_v4',
'personal_sign',
...SIGNING_METHODS,
]);

export const SUPPORTED_CHAIN_IDS: string[] = [
Expand All @@ -44,12 +42,19 @@ export const SUPPORTED_CHAIN_IDS: string[] = [
* @param ppomController - Instance of PPOMController.
* @param preferencesController - Instance of PreferenceController.
* @param networkController - Instance of NetworkController.
* @param appStateController
* @param updateSecurityAlertResponseByTxId
* @returns PPOMMiddleware function.
*/
export function createPPOMMiddleware(
ppomController: PPOMController,
preferencesController: PreferencesController,
networkController: NetworkController,
appStateController: any,
updateSecurityAlertResponseByTxId: (
req: any,
securityAlertResponse: SecurityAlertResponse,
) => void,
) {
return async (req: any, _res: any, next: () => void) => {
try {
Expand All @@ -58,15 +63,46 @@ export function createPPOMMiddleware(
const { chainId } = networkController.state.providerConfig;
if (
securityAlertsEnabled &&
ConfirmationMethods.includes(req.method) &&
CONFIRMATION_METHODS.includes(req.method) &&
SUPPORTED_CHAIN_IDS.includes(chainId)
) {
// eslint-disable-next-line require-atomic-updates
req.securityAlertResponse = await ppomController.usePPOM(
async (ppom: PPOM) => {
return ppom.validateJsonRpc(req);
},
);
const securityAlertId = uuid();

ppomController.usePPOM(async (ppom: PPOM) => {
try {
const securityAlertResponse = await ppom.validateJsonRpc(req);
securityAlertResponse.securityAlertId = securityAlertId;
updateSecurityAlertResponseByTxId(req, securityAlertResponse);
} catch (error: any) {
sentry?.captureException(error);
console.error('Error validating JSON RPC using PPOM: ', error);
const securityAlertResponse = {
result_type: BlockaidResultType.Failed,
reason: BlockaidReason.failed,
description:
'Validating the confirmation failed by throwing error.',
};
updateSecurityAlertResponseByTxId(req, securityAlertResponse);
}
});

if (SIGNING_METHODS.includes(req.method)) {
req.securityAlertResponse = {
securityAlertId,
};
appStateController.addSignatureSecurityAlertResponse({
reason: BlockaidResultType.Loading,
result_type: BlockaidReason.inProgress,
securityAlertId,
});
} else {
req.securityAlertResponse = {
reason: BlockaidResultType.Loading,
result_type: BlockaidReason.inProgress,
securityAlertId,
};
}
}
} catch (error: any) {
sentry?.captureException(error);
Expand Down
2 changes: 2 additions & 0 deletions app/scripts/lib/setupSentry.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ export const SENTRY_BACKGROUND_STATE = {
forgottenPassword: true,
identities: false,
incomingTransactionsPreferences: true,
isIpfsGatewayEnabled: false,
ipfsGateway: false,
isLineaMainnetReleased: true,
knownMethodData: false,
Expand All @@ -211,6 +212,7 @@ export const SENTRY_BACKGROUND_STATE = {
selectedAddress: false,
snapRegistryList: false,
theme: true,
signatureSecurityAlertResponses: false,
transactionSecurityCheckEnabled: true,
use4ByteResolution: true,
useAddressBarEnsResolution: true,
Expand Down
13 changes: 11 additions & 2 deletions app/scripts/lib/transaction/util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ import {
addTransaction,
} from './util';

jest.mock('uuid', () => {
const actual = jest.requireActual('uuid');

return {
...actual,
v4: jest.fn(),
};
});

const TRANSACTION_PARAMS_MOCK: TransactionParams = {
from: '0x1',
};
Expand Down Expand Up @@ -380,8 +389,8 @@ describe('Transaction Utils', () => {
).toHaveBeenCalledWith(TRANSACTION_PARAMS_MOCK, {
...TRANSACTION_OPTIONS_MOCK,
securityAlertResponse: {
reason: 'testReason',
result_type: 'testResultType',
reason: 'loading',
result_type: 'validation_in_progress',
},
});

Expand Down
93 changes: 75 additions & 18 deletions app/scripts/lib/transaction/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import {
TransactionController,
TransactionMeta,
TransactionParams,
WalletDevice,
TransactionType,
SendFlowHistoryEntry,
Result,
} from '@metamask/transaction-controller';
import {
AddUserOperationOptions,
Expand All @@ -12,11 +16,45 @@ import {
import { PPOMController } from '@metamask/ppom-validator';
import { captureException } from '@sentry/browser';
import { addHexPrefix } from 'ethereumjs-util';
import { v4 as uuid } from 'uuid';
import { SUPPORTED_CHAIN_IDS } from '../ppom/ppom-middleware';
import {
BlockaidReason,
BlockaidResultType,
} from '../../../../shared/constants/security-provider';
///: END:ONLY_INCLUDE_IF

/**
* Type for security alert response from transaction validator.
*/
export type SecurityAlertResponse = {
reason: string;
features?: string[];
result_type: string;
providerRequestsCount?: Record<string, number>;
securityAlertId?: string;
};

export type AddTransactionOptions = NonNullable<
Parameters<TransactionController['addTransaction']>[1]
Parameters<
(
txParams: TransactionParams,
options?: {
actionId?: string;
deviceConfirmedOn?: WalletDevice;
method?: string;
origin?: string;
requireApproval?: boolean | undefined;
securityAlertResponse?: SecurityAlertResponse;
sendFlowHistory?: SendFlowHistoryEntry[];
swaps?: {
hasApproveTx?: boolean;
meta?: Partial<TransactionMeta>;
};
type?: TransactionType;
},
) => Promise<Result>
>[1]
>;

type BaseAddTransactionRequest = {
Expand All @@ -30,16 +68,6 @@ type BaseAddTransactionRequest = {
userOperationController: UserOperationController;
};

/**
* Type for security alert response from transaction validator.
*/
export type SecurityAlertResponse = {
reason: string;
features?: string[];
result_type: string;
providerRequestsCount?: Record<string, number>;
};

type FinalAddTransactionRequest = BaseAddTransactionRequest & {
transactionOptions: AddTransactionOptions;
};
Expand Down Expand Up @@ -83,6 +111,12 @@ export async function addDappTransaction(

export async function addTransaction(
request: AddTransactionRequest,
///: BEGIN:ONLY_INCLUDE_IF(blockaid)
updateSecurityAlertResponseByTxId: (
req: AddTransactionOptions | undefined,
securityAlertResponse: SecurityAlertResponse,
) => void,
///: END:ONLY_INCLUDE_IF
): Promise<TransactionMeta> {
///: BEGIN:ONLY_INCLUDE_IF(blockaid)
const {
Expand All @@ -109,13 +143,36 @@ export async function addTransaction(
],
};

const securityAlertResponse = await ppomController.usePPOM(
async (ppom) => {
return ppom.validateJsonRpc(ppomRequest);
},
);

request.transactionOptions.securityAlertResponse = securityAlertResponse;
const securityAlertId = uuid();

ppomController.usePPOM(async (ppom) => {
try {
const securityAlertResponse = await ppom.validateJsonRpc(ppomRequest);
updateSecurityAlertResponseByTxId(
request.transactionOptions,
securityAlertResponse,
);
} catch (e) {
captureException(e);
console.error('Error validating JSON RPC using PPOM: ', e);
const securityAlertResponse = {
result_type: BlockaidResultType.Failed,
reason: BlockaidReason.failed,
description:
'Validating the confirmation failed by throwing error.',
};
updateSecurityAlertResponseByTxId(
request.transactionOptions,
securityAlertResponse,
);
}
});

request.transactionOptions.securityAlertResponse = {
reason: BlockaidResultType.Loading,
result_type: BlockaidReason.inProgress,
securityAlertId,
};
} catch (e) {
captureException(e);
}
Expand Down
Loading

0 comments on commit e5f2b68

Please sign in to comment.