Skip to content

Commit

Permalink
feat: update to properly handle request permissions on all platform
Browse files Browse the repository at this point in the history
  • Loading branch information
abretonc7s committed Apr 19, 2024
1 parent 473978f commit 7d4115f
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 114 deletions.
29 changes: 17 additions & 12 deletions app/components/Views/AccountConnect/AccountConnect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ const AccountConnect = (props: AccountConnectProps) => {
: AvatarAccountType.JazzIcon,
);

const { id: channelId, origin: metadataOrigin } = hostInfo.metadata as {
// on inappBrowser: hostname
// on sdk or walletconnect: channelId
const { origin: channelIdOrHostname } = hostInfo.metadata as {
id: string;
origin: string;
};
Expand All @@ -121,7 +123,9 @@ const AccountConnect = (props: AccountConnectProps) => {
const [hostname, setHostname] = useState<string>(origin);

const urlWithProtocol = prefixUrlWithProtocol(hostname);
const sdkConnection = SDKConnect.getInstance().getConnection({ channelId });
const sdkConnection = SDKConnect.getInstance().getConnection({
channelId: channelIdOrHostname,
});
// Last wallet connect session metadata
const wc2Metadata = useSelector((state: RootState) => state.sdk.wc2Metadata);

Expand Down Expand Up @@ -177,22 +181,23 @@ const AccountConnect = (props: AccountConnectProps) => {
// sdk channelId format: uuid
// inappbrowser channelId format: app.uniswap.io
DevLogger.log(
`AccountConnect::loadHostname channelId=${channelId} hostname=${hostname} origin=${origin}`,
`AccountConnect::loadHostname hostname=${hostname} origin=${origin} metadataOrigin=${channelIdOrHostname}`,
sdkConnection,
);
// check if channelId contains dot, it comes from in-app browser and we can use it.
if (channelId.indexOf('.') !== -1) {
if (channelIdOrHostname.indexOf('.') !== -1) {
return origin;
}

if (sdkConnection) {
const _hostname = (
sdkConnection?.originatorInfo?.url ?? metadataOrigin
sdkConnection?.originatorInfo?.url ?? channelIdOrHostname
).replace(AppConstants.MM_SDK.SDK_REMOTE_ORIGIN, '');
return _hostname;
}

return wc2Metadata?.url ?? channelId;
}, [channelId, hostname, metadataOrigin, sdkConnection, origin, wc2Metadata]);
return wc2Metadata?.url ?? channelIdOrHostname;
}, [hostname, channelIdOrHostname, sdkConnection, origin, wc2Metadata]);

// Retrieve hostname info based on channelId
useEffect(() => {
Expand All @@ -215,10 +220,10 @@ const AccountConnect = (props: AccountConnectProps) => {
const cancelPermissionRequest = useCallback(
(requestId) => {
Engine.context.PermissionController.rejectPermissionsRequest(requestId);
if (channelId && accountsLength === 0) {
if (channelIdOrHostname && accountsLength === 0) {
// Remove Potential SDK connection
SDKConnect.getInstance().removeChannel({
channelId,
channelId: channelIdOrHostname,
sendTerminate: true,
});
}
Expand All @@ -231,7 +236,7 @@ const AccountConnect = (props: AccountConnectProps) => {
[
Engine.context.PermissionController,
accountsLength,
channelId,
channelIdOrHostname,
trackEvent,
],
);
Expand Down Expand Up @@ -291,7 +296,7 @@ const AccountConnect = (props: AccountConnectProps) => {
...hostInfo,
metadata: {
...hostInfo.metadata,
origin: metadataOrigin,
origin: channelIdOrHostname,
},
approvedAccounts: selectedAccounts,
};
Expand Down Expand Up @@ -354,7 +359,7 @@ const AccountConnect = (props: AccountConnectProps) => {
Engine.context.PermissionController,
toastRef,
accountsLength,
metadataOrigin,
channelIdOrHostname,
triggerDappViewedEvent,
trackEvent,
]);
Expand Down
79 changes: 18 additions & 61 deletions app/core/RPCMethods/RPCMethodMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,25 +120,16 @@ export const checkActiveAccountAndChainId = async ({
hostname,
formattedAddress,
});
const validHostname = hostname?.replace(
AppConstants.MM_SDK.SDK_REMOTE_ORIGIN,
'',
);

const permissionsController = (
Engine.context as { PermissionController: PermissionController<any, any> }
).PermissionController;
DevLogger.log(
`checkActiveAccountAndChainId channelId=${channelId} isWalletConnect=${isWalletConnect} validHostname=${validHostname}`,
`checkActiveAccountAndChainId channelId=${channelId} isWalletConnect=${isWalletConnect} hostname=${hostname}`,
permissionsController.state,
);

let accounts: string[] = [];
if (isWalletConnect) {
accounts = await getPermittedAccounts(validHostname);
} else {
accounts = (await getPermittedAccounts(channelId ?? validHostname)) ?? [];
}
const accounts = (await getPermittedAccounts(channelId ?? hostname)) ?? [];

const normalizedAccounts = accounts.map(safeToChecksumAddress);

Expand Down Expand Up @@ -294,22 +285,18 @@ export const getRpcMethodMiddleware = ({
injectHomePageScripts,
// For analytics
analytics,
}: RPCMethodsMiddleParameters) =>
}: RPCMethodsMiddleParameters) => {
// Make sure to always have the correct origin
hostname = hostname.replace(AppConstants.MM_SDK.SDK_REMOTE_ORIGIN, '');
DevLogger.log(
`getRpcMethodMiddleware hostname=${hostname} channelId=${channelId}`,
);
// all user facing RPC calls not implemented by the provider
createAsyncMiddleware(async (req: any, res: any, next: any) => {
return createAsyncMiddleware(async (req: any, res: any, next: any) => {
// Used by eth_accounts and eth_coinbase RPCs.
const getEthAccounts = async () => {
let accounts: string[] = [];
const validHostname = hostname.replace(
AppConstants.MM_SDK.SDK_REMOTE_ORIGIN,
'',
);
if (isMMSDK) {
accounts =
(await getPermittedAccounts(channelId ?? validHostname)) ?? [];
} else {
accounts = await getPermittedAccounts(validHostname);
}
const accounts: string[] =
(await getPermittedAccounts(channelId ?? hostname)) ?? [];
res.result = accounts;
};

Expand Down Expand Up @@ -388,7 +375,7 @@ export const getRpcMethodMiddleware = ({
getPermissionsForOrigin:
Engine.context.PermissionController.getPermissions.bind(
Engine.context.PermissionController,
hostname,
channelId ?? hostname,
),
},
);
Expand All @@ -398,14 +385,6 @@ export const getRpcMethodMiddleware = ({
}),
wallet_requestPermissions: async () =>
new Promise<any>((resolve, reject) => {
let requestId: string | undefined;
if (isMMSDK) {
// Extract id from hostname
requestId = hostname.replace(
AppConstants.MM_SDK.SDK_REMOTE_ORIGIN,
'',
);
}
requestPermissionsHandler
.implementation(
req,
Expand All @@ -421,9 +400,8 @@ export const getRpcMethodMiddleware = ({
requestPermissionsForOrigin:
Engine.context.PermissionController.requestPermissions.bind(
Engine.context.PermissionController,
{ origin: requestId ?? hostname },
{ origin: channelId ?? hostname },
req.params[0],
{ id: requestId },
),
},
)
Expand Down Expand Up @@ -486,12 +464,8 @@ export const getRpcMethodMiddleware = ({
},
eth_requestAccounts: async () => {
const { params } = req;
const validHostname = hostname.replace(
AppConstants.MM_SDK.SDK_REMOTE_ORIGIN,
'',
);
const permittedAccounts = await getPermittedAccounts(
channelId ?? validHostname,
channelId ?? hostname,
);

if (!params?.force && permittedAccounts.length) {
Expand All @@ -500,7 +474,7 @@ export const getRpcMethodMiddleware = ({
try {
checkTabActive();
await Engine.context.PermissionController.requestPermissions(
{ origin: channelId ?? validHostname },
{ origin: channelId ?? hostname },
{ eth_accounts: {} },
{
preserveExistingPermissions: true,
Expand All @@ -526,16 +500,6 @@ export const getRpcMethodMiddleware = ({
eth_sendTransaction: async () => {
checkTabActive();

if (isMMSDK) {
// Append origin to the request so it can be parsed in UI TransactionHeader
DevLogger.log(
`SDK Transaction detected --- custom hostname -- ${hostname} --> ${
AppConstants.MM_SDK.SDK_REMOTE_ORIGIN + url.current
}`,
);
hostname = AppConstants.MM_SDK.SDK_REMOTE_ORIGIN + url.current;
}

return RPCMethods.eth_sendTransaction({
hostname,
req,
Expand Down Expand Up @@ -643,6 +607,7 @@ export const getRpcMethodMiddleware = ({
isWalletConnect,
});

DevLogger.log(`personal_sign`, params, pageMeta, hostname);
PPOMUtil.validateRequest(req);

const rawSig = await SignatureController.newUnsignedPersonalMessage({
Expand Down Expand Up @@ -875,16 +840,7 @@ export const getRpcMethodMiddleware = ({
*/
metamask_getProviderState: async () => {
let accounts: string[] = [];
const validHostname = hostname.replace(
AppConstants.MM_SDK.SDK_REMOTE_ORIGIN,
'',
);
if (isMMSDK) {
accounts =
(await getPermittedAccounts(channelId ?? validHostname)) ?? [];
} else {
accounts = await getPermittedAccounts(validHostname);
}
accounts = (await getPermittedAccounts(channelId ?? hostname)) ?? [];
res.result = {
...getProviderState(),
accounts,
Expand Down Expand Up @@ -956,4 +912,5 @@ export const getRpcMethodMiddleware = ({
throw e;
}
});
};
export default getRpcMethodMiddleware;
1 change: 0 additions & 1 deletion app/core/SDKConnect/AndroidSDK/AndroidService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,6 @@ export default class AndroidService extends EventEmitter2 {
return permissionsController.requestPermissions(
{ origin: channelId },
{ eth_accounts: {} },
{ id: channelId },
);
}

Expand Down
3 changes: 2 additions & 1 deletion app/core/SDKConnect/ConnectionManagement/reconnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ async function reconnect({

// issue can happen during dev because bundle takes too long to load via metro.
// should not happen but keeping it for reference / debug purpose.
console.warn(`Already connecting --- Priotity to deeplink`);
console.warn(`BUNDLE WARNING: Already connecting --- Priotity to deeplink`);
// instance.removeChannel({ channelId, sendTerminate: true });
}
if (!instance.state.connections[channelId]) {
interruptReason = 'no connection';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,6 @@ export default class DeeplinkProtocolService {
return permissionsController.requestPermissions(
{ origin: channelId },
{ eth_accounts: {} },
{ id: channelId },
);
}

Expand Down
40 changes: 29 additions & 11 deletions app/core/SDKConnect/handlers/checkPermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,14 @@ export const checkPermissions = async ({
);

if (approved) {
connection.approvalPromise = undefined;
return true;
}

DevLogger.log(
`checkPermissions channelWasActiveRecently=${channelWasActiveRecently} OTPExpirationDuration=${OTPExpirationDuration}`,
);

if (channelWasActiveRecently) {
return true;
}

Expand All @@ -75,7 +82,6 @@ export const checkPermissions = async ({
`checkPermissions approvalPromise exists completed -- allowed`,
allowed,
);
connection.approvalPromise = undefined;
// Add delay for backgroundBridge to complete setup
await wait(300);
return allowed;
Expand All @@ -87,14 +93,27 @@ export const checkPermissions = async ({
connection.revalidate({ channelId: connection.channelId });
}

DevLogger.log(
`checkPermissions channelWasActiveRecently=${channelWasActiveRecently} OTPExpirationDuration=${OTPExpirationDuration}`,
);
if (channelWasActiveRecently) {
return true;
}

try {
const accountPermission = permissionsController.getPermission(
connection.channelId,
'eth_accounts',
);
if (accountPermission) {
DevLogger.log(
`checkPermissions accountPermission exists but not active recently -- REVOKE + ASK AGAIN`,
);
try {
// Revoke and ask again
permissionsController.revokePermission(
connection.channelId,
'eth_accounts',
);
} catch (err) {
// Ignore error if permission is not found
console.warn(`checkPermissions revokePermission error`, err);
}
}

connection.approvalPromise = permissionsController.requestPermissions(
{ origin: connection.channelId },
{ eth_accounts: {} },
Expand All @@ -106,10 +125,9 @@ export const checkPermissions = async ({
await connection.approvalPromise;
// Clear previous permissions if already approved.
connection.revalidate({ channelId: connection.channelId });
connection.approvalPromise = undefined;
return true;
} catch (err) {
DevLogger.log(`checkPermissions error`, err);
console.warn(`checkPermissions error`, err);
connection.approvalPromise = undefined;
throw err;
}
Expand Down
Loading

0 comments on commit 7d4115f

Please sign in to comment.