mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Adopt security provider request from core (#18520)
This commit is contained in:
parent
09d00e1e45
commit
ae0af1b283
@ -52,6 +52,7 @@ const messageMock = {
|
|||||||
const coreMessageMock = {
|
const coreMessageMock = {
|
||||||
...messageMock,
|
...messageMock,
|
||||||
messageParams: messageParamsMock,
|
messageParams: messageParamsMock,
|
||||||
|
securityProviderResponse: securityProviderResponseMock,
|
||||||
};
|
};
|
||||||
|
|
||||||
const stateMessageMock = {
|
const stateMessageMock = {
|
||||||
|
@ -21,6 +21,7 @@ import {
|
|||||||
AbstractMessageParams,
|
AbstractMessageParams,
|
||||||
AbstractMessageParamsMetamask,
|
AbstractMessageParamsMetamask,
|
||||||
OriginalRequest,
|
OriginalRequest,
|
||||||
|
SecurityProviderRequest,
|
||||||
} from '@metamask/message-manager/dist/AbstractMessageManager';
|
} from '@metamask/message-manager/dist/AbstractMessageManager';
|
||||||
import {
|
import {
|
||||||
BaseControllerV2,
|
BaseControllerV2,
|
||||||
@ -63,9 +64,10 @@ export type CoreMessage = AbstractMessage & {
|
|||||||
messageParams: AbstractMessageParams;
|
messageParams: AbstractMessageParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type StateMessage = Required<AbstractMessage> & {
|
export type StateMessage = Required<
|
||||||
|
Omit<AbstractMessage, 'securityProviderResponse'>
|
||||||
|
> & {
|
||||||
msgParams: Required<AbstractMessageParams>;
|
msgParams: Required<AbstractMessageParams>;
|
||||||
securityProviderResponse: any;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SignControllerState = {
|
export type SignControllerState = {
|
||||||
@ -107,10 +109,7 @@ export type SignControllerOptions = {
|
|||||||
preferencesController: PreferencesController;
|
preferencesController: PreferencesController;
|
||||||
getState: () => any;
|
getState: () => any;
|
||||||
metricsEvent: (payload: any, options?: any) => void;
|
metricsEvent: (payload: any, options?: any) => void;
|
||||||
securityProviderRequest: (
|
securityProviderRequest: SecurityProviderRequest;
|
||||||
requestData: any,
|
|
||||||
methodName: string,
|
|
||||||
) => Promise<any>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -143,11 +142,6 @@ export default class SignController extends BaseControllerV2<
|
|||||||
|
|
||||||
private _metricsEvent: (payload: any, options?: any) => void;
|
private _metricsEvent: (payload: any, options?: any) => void;
|
||||||
|
|
||||||
private _securityProviderRequest: (
|
|
||||||
requestData: any,
|
|
||||||
methodName: string,
|
|
||||||
) => Promise<any>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a Sign controller.
|
* Construct a Sign controller.
|
||||||
*
|
*
|
||||||
@ -178,12 +172,23 @@ export default class SignController extends BaseControllerV2<
|
|||||||
this._preferencesController = preferencesController;
|
this._preferencesController = preferencesController;
|
||||||
this._getState = getState;
|
this._getState = getState;
|
||||||
this._metricsEvent = metricsEvent;
|
this._metricsEvent = metricsEvent;
|
||||||
this._securityProviderRequest = securityProviderRequest;
|
|
||||||
|
|
||||||
this.hub = new EventEmitter();
|
this.hub = new EventEmitter();
|
||||||
this._messageManager = new MessageManager();
|
this._messageManager = new MessageManager(
|
||||||
this._personalMessageManager = new PersonalMessageManager();
|
undefined,
|
||||||
this._typedMessageManager = new TypedMessageManager();
|
undefined,
|
||||||
|
securityProviderRequest,
|
||||||
|
);
|
||||||
|
this._personalMessageManager = new PersonalMessageManager(
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
securityProviderRequest,
|
||||||
|
);
|
||||||
|
this._typedMessageManager = new TypedMessageManager(
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
securityProviderRequest,
|
||||||
|
);
|
||||||
|
|
||||||
this._messageManagers = [
|
this._messageManagers = [
|
||||||
this._messageManager,
|
this._messageManager,
|
||||||
@ -589,15 +594,7 @@ export default class SignController extends BaseControllerV2<
|
|||||||
origin: messageParams.origin as string,
|
origin: messageParams.origin as string,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
return stateMessage;
|
||||||
const messageId = coreMessage.id;
|
|
||||||
const existingMessage = this._getMessage(messageId);
|
|
||||||
|
|
||||||
const securityProviderResponse = existingMessage
|
|
||||||
? existingMessage.securityProviderResponse
|
|
||||||
: await this._securityProviderRequest(stateMessage, stateMessage.type);
|
|
||||||
|
|
||||||
return { ...stateMessage, securityProviderResponse };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _normalizeMsgData(data: string) {
|
private _normalizeMsgData(data: string) {
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
|
|
||||||
import { MESSAGE_TYPE } from '../../../shared/constants/app';
|
|
||||||
|
|
||||||
const fetchWithTimeout = getFetchWithTimeout();
|
|
||||||
|
|
||||||
export async function securityProviderCheck(
|
|
||||||
requestData,
|
|
||||||
methodName,
|
|
||||||
chainId,
|
|
||||||
currentLocale,
|
|
||||||
) {
|
|
||||||
let dataToValidate;
|
|
||||||
|
|
||||||
if (methodName === MESSAGE_TYPE.ETH_SIGN_TYPED_DATA) {
|
|
||||||
dataToValidate = {
|
|
||||||
host_name: requestData.msgParams.origin,
|
|
||||||
rpc_method_name: methodName,
|
|
||||||
chain_id: chainId,
|
|
||||||
data: requestData.msgParams.data,
|
|
||||||
currentLocale,
|
|
||||||
};
|
|
||||||
} else if (
|
|
||||||
methodName === MESSAGE_TYPE.ETH_SIGN ||
|
|
||||||
methodName === MESSAGE_TYPE.PERSONAL_SIGN
|
|
||||||
) {
|
|
||||||
dataToValidate = {
|
|
||||||
host_name: requestData.msgParams.origin,
|
|
||||||
rpc_method_name: methodName,
|
|
||||||
chain_id: chainId,
|
|
||||||
data: {
|
|
||||||
signer_address: requestData.msgParams.from,
|
|
||||||
msg_to_sign: requestData.msgParams.data,
|
|
||||||
},
|
|
||||||
currentLocale,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
dataToValidate = {
|
|
||||||
host_name: requestData.origin,
|
|
||||||
rpc_method_name: methodName,
|
|
||||||
chain_id: chainId,
|
|
||||||
data: {
|
|
||||||
from_address: requestData?.txParams?.from,
|
|
||||||
to_address: requestData?.txParams?.to,
|
|
||||||
gas: requestData?.txParams?.gas,
|
|
||||||
gasPrice: requestData?.txParams?.gasPrice,
|
|
||||||
value: requestData?.txParams?.value,
|
|
||||||
data: requestData?.txParams?.data,
|
|
||||||
},
|
|
||||||
currentLocale,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetchWithTimeout(
|
|
||||||
'https://proxy.metafi.codefi.network/opensea/security/v1/validate',
|
|
||||||
{
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
Accept: 'application/json',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(dataToValidate),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return await response.json();
|
|
||||||
}
|
|
117
app/scripts/lib/security-provider-helpers.test.ts
Normal file
117
app/scripts/lib/security-provider-helpers.test.ts
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import { MESSAGE_TYPE } from '../../../shared/constants/app';
|
||||||
|
import {
|
||||||
|
RequestData,
|
||||||
|
securityProviderCheck,
|
||||||
|
} from './security-provider-helpers';
|
||||||
|
|
||||||
|
describe('securityProviderCheck', () => {
|
||||||
|
let fetchSpy: jest.SpyInstance;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// Spy on the global fetch function
|
||||||
|
fetchSpy = jest.spyOn(global, 'fetch');
|
||||||
|
fetchSpy.mockImplementation(async () => {
|
||||||
|
return new Response(JSON.stringify('result_mocked'), { status: 200 });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const paramsMock = {
|
||||||
|
origin: 'https://example.com',
|
||||||
|
data: 'some_data',
|
||||||
|
from: '0x',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Utility function to handle different data properties based on methodName
|
||||||
|
const getExpectedData = (methodName: string, requestData: RequestData) => {
|
||||||
|
switch (methodName) {
|
||||||
|
case MESSAGE_TYPE.ETH_SIGN:
|
||||||
|
case MESSAGE_TYPE.PERSONAL_SIGN:
|
||||||
|
return {
|
||||||
|
signer_address: requestData.msgParams?.from,
|
||||||
|
msg_to_sign: requestData.msgParams?.data,
|
||||||
|
};
|
||||||
|
case MESSAGE_TYPE.ETH_SIGN_TYPED_DATA:
|
||||||
|
return requestData.messageParams?.data;
|
||||||
|
default:
|
||||||
|
return {
|
||||||
|
from_address: requestData.txParams?.from,
|
||||||
|
to_address: requestData.txParams?.to,
|
||||||
|
gas: requestData.txParams?.gas,
|
||||||
|
gasPrice: requestData.txParams?.gasPrice,
|
||||||
|
value: requestData.txParams?.value,
|
||||||
|
data: requestData.txParams?.data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test.each([
|
||||||
|
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA],
|
||||||
|
[MESSAGE_TYPE.ETH_SIGN],
|
||||||
|
[MESSAGE_TYPE.PERSONAL_SIGN],
|
||||||
|
['some_other_method'],
|
||||||
|
])(
|
||||||
|
'should call fetch with the correct parameters for %s',
|
||||||
|
async (methodName: string) => {
|
||||||
|
let requestData: RequestData;
|
||||||
|
|
||||||
|
switch (methodName) {
|
||||||
|
case MESSAGE_TYPE.ETH_SIGN_TYPED_DATA:
|
||||||
|
requestData = {
|
||||||
|
origin: 'https://example.com',
|
||||||
|
messageParams: paramsMock,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case MESSAGE_TYPE.ETH_SIGN:
|
||||||
|
case MESSAGE_TYPE.PERSONAL_SIGN:
|
||||||
|
requestData = {
|
||||||
|
origin: 'https://example.com',
|
||||||
|
msgParams: paramsMock,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
requestData = {
|
||||||
|
origin: 'https://example.com',
|
||||||
|
txParams: {
|
||||||
|
from: '0x',
|
||||||
|
to: '0x',
|
||||||
|
gas: 'some_gas',
|
||||||
|
gasPrice: 'some_gasPrice',
|
||||||
|
value: 'some_value',
|
||||||
|
data: 'some_data',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await securityProviderCheck(
|
||||||
|
requestData,
|
||||||
|
methodName,
|
||||||
|
'1',
|
||||||
|
'en',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(fetchSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(fetchSpy).toHaveBeenCalledWith(
|
||||||
|
'https://proxy.metafi.codefi.network/opensea/security/v1/validate',
|
||||||
|
expect.objectContaining({
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
host_name:
|
||||||
|
methodName === 'some_other_method'
|
||||||
|
? requestData.origin
|
||||||
|
: requestData.msgParams?.origin ||
|
||||||
|
requestData.messageParams?.origin,
|
||||||
|
rpc_method_name: methodName,
|
||||||
|
chain_id: '1',
|
||||||
|
data: getExpectedData(methodName, requestData),
|
||||||
|
currentLocale: 'en',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(result).toEqual('result_mocked');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
92
app/scripts/lib/security-provider-helpers.ts
Normal file
92
app/scripts/lib/security-provider-helpers.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import { Json } from '@metamask/utils';
|
||||||
|
import { MessageParams } from '@metamask/message-manager';
|
||||||
|
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
|
||||||
|
import { MESSAGE_TYPE } from '../../../shared/constants/app';
|
||||||
|
|
||||||
|
const fetchWithTimeout = getFetchWithTimeout();
|
||||||
|
|
||||||
|
export type TransactionRequestData = {
|
||||||
|
txParams: Record<string, unknown>;
|
||||||
|
messageParams?: never;
|
||||||
|
msgParams?: never;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MessageRequestData =
|
||||||
|
| {
|
||||||
|
msgParams: MessageParams;
|
||||||
|
txParams?: never;
|
||||||
|
messageParams?: never;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
messageParams: MessageParams;
|
||||||
|
msgParams?: never;
|
||||||
|
txParams?: never;
|
||||||
|
}
|
||||||
|
| TransactionRequestData;
|
||||||
|
|
||||||
|
export type RequestData = {
|
||||||
|
origin: string;
|
||||||
|
} & MessageRequestData;
|
||||||
|
|
||||||
|
export async function securityProviderCheck(
|
||||||
|
requestData: RequestData,
|
||||||
|
methodName: string,
|
||||||
|
chainId: string,
|
||||||
|
currentLocale: string,
|
||||||
|
): Promise<Record<string, Json>> {
|
||||||
|
let dataToValidate;
|
||||||
|
// Core message managers use messageParams but frontend uses msgParams with lots of references
|
||||||
|
const params = requestData.msgParams || requestData.messageParams;
|
||||||
|
|
||||||
|
if (methodName === MESSAGE_TYPE.ETH_SIGN_TYPED_DATA) {
|
||||||
|
dataToValidate = {
|
||||||
|
host_name: params?.origin,
|
||||||
|
rpc_method_name: methodName,
|
||||||
|
chain_id: chainId,
|
||||||
|
data: params?.data,
|
||||||
|
currentLocale,
|
||||||
|
};
|
||||||
|
} else if (
|
||||||
|
methodName === MESSAGE_TYPE.ETH_SIGN ||
|
||||||
|
methodName === MESSAGE_TYPE.PERSONAL_SIGN
|
||||||
|
) {
|
||||||
|
dataToValidate = {
|
||||||
|
host_name: params?.origin,
|
||||||
|
rpc_method_name: methodName,
|
||||||
|
chain_id: chainId,
|
||||||
|
data: {
|
||||||
|
signer_address: params?.from,
|
||||||
|
msg_to_sign: params?.data,
|
||||||
|
},
|
||||||
|
currentLocale,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
dataToValidate = {
|
||||||
|
host_name: requestData.origin,
|
||||||
|
rpc_method_name: methodName,
|
||||||
|
chain_id: chainId,
|
||||||
|
data: {
|
||||||
|
from_address: requestData.txParams?.from,
|
||||||
|
to_address: requestData.txParams?.to,
|
||||||
|
gas: requestData.txParams?.gas,
|
||||||
|
gasPrice: requestData.txParams?.gasPrice,
|
||||||
|
value: requestData.txParams?.value,
|
||||||
|
data: requestData.txParams?.data,
|
||||||
|
},
|
||||||
|
currentLocale,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const response: Response = await fetchWithTimeout(
|
||||||
|
'https://proxy.metafi.codefi.network/opensea/security/v1/validate',
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(dataToValidate),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return await response.json();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user