Skip to content

Commit

Permalink
feat: do not rely on sdk being valid in sign process
Browse files Browse the repository at this point in the history
  • Loading branch information
CedrikNikita committed Nov 11, 2024
1 parent df51f99 commit 66ad91d
Show file tree
Hide file tree
Showing 20 changed files with 337 additions and 113 deletions.
26 changes: 18 additions & 8 deletions src/background/bgPopupHandler.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { v4 as uuid } from 'uuid';
import type {
Dictionary,
IAppData,
IPopupProps,
PopupType,
} from '@/types';
import { UNKNOWN_SOURCE, UNKNOWN_APP_DETAILS } from '@/constants/common';

interface IPopupConfigNoActions {
id: string;
Expand Down Expand Up @@ -38,23 +40,31 @@ export const openPopup = async (
popupProps: Partial<IPopupProps> = {},
) => {
const id = uuid();
const { href, protocol, host } = (typeof aepp === 'object') ? getAeppUrl(aepp) : new URL(aepp);
const { name = host } = (typeof aepp === 'object') ? aepp : {} as any;

let app: IAppData;

if (typeof aepp === 'object') {
app = getAeppUrl(aepp);
} else if (aepp === UNKNOWN_SOURCE) {
app = UNKNOWN_APP_DETAILS;
} else {
app = new URL(aepp);
}

const tabs = await browser.tabs.query({ active: true });

tabs.forEach(({ url: tabURL, id: tabId }) => {
const tabUrl = new URL(tabURL as string);
if (
tabUrl.searchParams.get('type') === POPUP_TYPE_CONNECT
&& decodeURIComponent(tabUrl.searchParams.get('url') || '') === href
&& decodeURIComponent(tabUrl.searchParams.get('url') || '') === app.href
) {
browser.tabs.remove(tabId as number);
}
});

const extUrl = browser.runtime.getURL('./index.html');
const popupUrl = `${extUrl}?id=${id}&type=${popupType}&url=${encodeURIComponent(href)}`;
const popupUrl = `${extUrl}?id=${id}&type=${popupType}&url=${encodeURIComponent(app.href!)}`;
const isMacOsExtension = IS_EXTENSION && browser.runtime.getPlatformInfo().then(({ os }) => os === 'mac');

const popupWindow = await browser.windows.create({
Expand All @@ -73,10 +83,10 @@ export const openPopup = async (
props: {
...popupProps,
app: {
url: href,
name,
protocol,
host,
url: app.href,
name: app.name || app.host,
protocol: app.protocol,
host: app.host,
},
},
};
Expand Down
19 changes: 14 additions & 5 deletions src/composables/deepLinkApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import { checkIfSuperheroCallbackUrl } from '@/utils';
import { IS_IOS, IS_MOBILE_APP, MODAL_TRANSFER_SEND } from '@/constants';
import { useModals } from '@/composables/modals';

export function useDeepLinkApi() {
const router = useIonRouter();
let isDeepLinkUsed = false;

export function useDeepLinkApi(doNotInitializeRouter?: boolean) {
// `useIonRouter` breaks if it is not run in `IonPage` context
const router = doNotInitializeRouter ? null : useIonRouter();
const route = useRoute();

const callbackOrigin = ref<URL | null>(
route.query['x-success']
route?.query['x-success']
? (new URL(decodeURIComponent(route.query['x-success'] as string)))
: null,
);
Expand All @@ -37,24 +40,30 @@ export function useDeepLinkApi() {
) {
const callbackUrlTemplate = route.query[isSuccess ? 'x-success' : 'x-cancel'];
if (!callbackUrlTemplate) {
router.replace({ name: ROUTE_ACCOUNT });
router?.replace({ name: ROUTE_ACCOUNT });
return;
}
const callbackUrl = Object.entries(templateParams).reduce(
(url, [key, value]) => url.replace(new RegExp(`{${key}}`, 'g'), encodeURIComponent(value)),
decodeURIComponent(String(route.query[isSuccess ? 'x-success' : 'x-cancel'])),
) as string;
router.replace({ name: ROUTE_ACCOUNT });
router?.replace({ name: ROUTE_ACCOUNT });
if (IS_MOBILE_APP && !IS_IOS) {
window.open(callbackUrl, '_system');
} else {
window.open(callbackUrl, '_self');
}
}

function setIsDeepLinkUsed(value: boolean) {
isDeepLinkUsed = value;
}

return {
checkIfOpenTransferSendModal,
callbackOrigin,
openCallbackOrGoHome,
setIsDeepLinkUsed,
isDeepLinkUsed,
};
}
5 changes: 3 additions & 2 deletions src/composables/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
POPUP_TYPE_SIGN,
STORAGE_KEYS,
PROTOCOLS,
UNKNOWN_SOURCE,
} from '@/constants';
import { getCleanModalOptions } from '@/utils';
import { aettosToAe, isTxOfASupportedType } from '@/protocols/aeternity/helpers';
Expand Down Expand Up @@ -197,8 +198,8 @@ export function usePermissions() {
popup = POPUP_TYPE_RAW_SIGN;
}
await (
(IS_OFFSCREEN_TAB && app?.url)
? openPopup(popup, app.url, props)
(IS_OFFSCREEN_TAB)
? openPopup(popup, app?.url || UNKNOWN_SOURCE, props)
: openModal(modal, props)
);
return true;
Expand Down
12 changes: 11 additions & 1 deletion src/constants/common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ICurrency, IPermission } from '@/types';
import type { ICurrency, IAppData, IPermission } from '@/types';
import { IS_MOBILE_APP } from './environment';

export const APP_NAME = 'Superhero Wallet';
Expand Down Expand Up @@ -375,6 +375,16 @@ export const POPUP_TYPES = [
export const POPUP_CONNECT_ADDRESS_PERMISSION = 'address';
export const POPUP_CONNECT_TRANSACTIONS_PERMISSION = 'transactions';

export const UNKNOWN_SOURCE = 'Unknown source';
export const UNKNOWN_URL = 'Unknown url';
export const UNKNOWN_APP_DETAILS: IAppData = {
url: UNKNOWN_URL,
href: UNKNOWN_URL,
protocol: '',
host: '',
name: UNKNOWN_SOURCE,
};

export const POPUP_ACTIONS = {
getProps: 'getProps',
resolve: 'resolve',
Expand Down
4 changes: 4 additions & 0 deletions src/icons/warning-outline.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions src/popup/components/DetailsItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
:class="{
expandable,
expanded,
warning,
}"
>
<Component
Expand Down Expand Up @@ -63,6 +64,7 @@ export default defineComponent({
expandable: Boolean,
small: Boolean,
highlight: Boolean,
warning: Boolean,
},
setup(props) {
const expanded = ref(!props.expandable);
Expand Down Expand Up @@ -156,5 +158,15 @@ export default defineComponent({
}
}
}
&.warning {
.label {
color: $color-warning;
}
.value {
color: rgba($color-warning, 0.85);
}
}
}
</style>
17 changes: 16 additions & 1 deletion src/popup/components/Modals/ConfirmRawSign.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,19 @@
data-cy="popup-aex2"
>
<TransactionInfo
:custom-labels="[$t('modals.confirm-raw-sign.title')]"
:custom-labels="[
...(isUnknownDapp ? [$t('common.unknown')] : []),
$t('modals.confirm-raw-sign.title'),
]"
:sender="sender"
:recipient="activeAccount!"
:first-label-warning="isUnknownDapp"
/>

<NoOriginWarning
v-if="isUnknownDapp"
:action="$t('unknownDapp.signDataAction')"
:warning="$t('unknownDapp.signDataWarning')"
/>

<div
Expand Down Expand Up @@ -62,6 +72,7 @@ import {
MODAL_SIGN_AIR_GAP_TRANSACTION,
PROTOCOLS,
RUNNING_IN_POPUP,
UNKNOWN_SOURCE,
} from '@/constants';
import { RejectedByUserError } from '@/lib/errors';
import { useAccounts, useModals, usePopupProps } from '@/composables';
Expand Down Expand Up @@ -93,6 +104,9 @@ export default defineComponent({
const activeAccount = getLastActiveProtocolAccount(PROTOCOLS.aeternity);
const dataAsString = computed((): string => popupProps.value?.txBase64?.toString() || '');
const isUnknownDapp = computed(() => (
!popupProps.value?.app || popupProps.value.app.name === UNKNOWN_SOURCE
));
async function confirm() {
if (RUNNING_IN_POPUP && activeAccount?.type === 'airgap') {
Expand Down Expand Up @@ -124,6 +138,7 @@ export default defineComponent({
cancel,
activeAccount,
dataAsString,
isUnknownDapp,
sender,
};
},
Expand Down
16 changes: 15 additions & 1 deletion src/popup/components/Modals/ConfirmTransactionSign.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@
<template v-else>
<TransactionOverview
:transaction="transaction"
:additional-tag="appName"
:additional-tag="isUnknownDapp ? $t('common.unknown') : appName"
:first-label-warning="isUnknownDapp"
/>
<NoOriginWarning
v-if="isUnknownDapp"
:action="$t('unknownDapp.confirmTransactionAction')"
:warning="$t('unknownDapp.confirmTransactionWarning')"
/>
<div
v-if="appName || error"
Expand Down Expand Up @@ -231,6 +237,7 @@ import {
RUNNING_IN_POPUP,
SUPERHERO_CHAT_URLS,
TX_DIRECTION,
UNKNOWN_SOURCE,
} from '@/constants';
import {
fetchJson,
Expand Down Expand Up @@ -268,6 +275,7 @@ import DetailsItem from '../DetailsItem.vue';
import TokenAmount from '../TokenAmount.vue';
import TransactionDetailsPoolTokenRow from '../TransactionDetailsPoolTokenRow.vue';
import TransactionCallDataDetails from '../TransactionCallDataDetails.vue';
import NoOriginWarning from '../NoOriginWarning.vue';
import AnimatedSpinner from '../../../icons/animated-spinner.svg?vue-component';
Expand Down Expand Up @@ -299,6 +307,7 @@ export default defineComponent({
TokenAmount,
TransactionDetailsPoolTokenRow,
TransactionCallDataDetails,
NoOriginWarning,
AnimatedSpinner,
},
setup() {
Expand Down Expand Up @@ -363,6 +372,10 @@ export default defineComponent({
const app = computed(() => popupProps.value?.app);
const isUnknownDapp = computed(() => (
!popupProps.value?.app || popupProps.value.app.name === UNKNOWN_SOURCE
));
const fee = computed(() => (protocol === PROTOCOLS.aeternity)
? getAeFee(popupProps.value?.tx?.fee!)
: popupProps.value?.tx?.fee!);
Expand Down Expand Up @@ -658,6 +671,7 @@ export default defineComponent({
isDexSwap,
isTokenSale,
isHash,
isUnknownDapp,
loading,
nameAeFee,
popupProps,
Expand Down
23 changes: 22 additions & 1 deletion src/popup/components/Modals/ConfirmUnsafeSign.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,25 @@
>
<TransactionInfo
:custom-labels="[
...(isUnknownDapp ? [$t('common.unknown')] : []),
...(isAeppChatSuperhero)
? [$t('modals.confirmTransactionSign.superheroChat')]
: [],
$t('modals.confirmUnsafeSign.title'),
]"
:sender="sender"
:recipient="activeAccount"
:first-label-warning="isUnknownDapp"
/>

<NoOriginWarning
v-if="isUnknownDapp"
:action="$t('unknownDapp.signDataAction')"
:warning="$t('unknownDapp.signDataWarning')"
/>

<DetailsItem
v-else
:label="isAeppChatSuperhero ? $t('modals.confirmTransactionSign.superheroChat') : sender.name"
class="sender"
data-cy="aepp"
Expand Down Expand Up @@ -78,7 +87,12 @@ import {
onUnmounted,
} from 'vue';
import { JWT_HEADER, PROTOCOLS, SUPERHERO_CHAT_URLS } from '@/constants';
import {
JWT_HEADER,
PROTOCOLS,
SUPERHERO_CHAT_URLS,
UNKNOWN_SOURCE,
} from '@/constants';
import { fromBase64Url, handleUnknownError } from '@/utils';
import { RejectedByUserError } from '@/lib/errors';
import { useAccounts, usePopupProps } from '@/composables';
Expand All @@ -88,6 +102,7 @@ import TransactionInfo from '../TransactionInfo.vue';
import BtnMain from '../buttons/BtnMain.vue';
import DetailsItem from '../DetailsItem.vue';
import CopyText from '../CopyText.vue';
import NoOriginWarning from '../NoOriginWarning.vue';
export default defineComponent({
components: {
Expand All @@ -96,6 +111,7 @@ export default defineComponent({
BtnMain,
DetailsItem,
CopyText,
NoOriginWarning,
},
setup() {
const { popupProps, sender, setPopupProps } = usePopupProps();
Expand All @@ -104,6 +120,10 @@ export default defineComponent({
const isJwt = ref(false);
const messageToDisplay = ref('');
const isUnknownDapp = computed(() => (
!popupProps.value?.app || popupProps.value.app.name === UNKNOWN_SOURCE
));
if (popupProps.value?.data) {
messageToDisplay.value = Buffer.from(popupProps.value?.data).toString();
Expand Down Expand Up @@ -144,6 +164,7 @@ export default defineComponent({
activeAccount,
isAeppChatSuperhero,
isJwt,
isUnknownDapp,
messageToDisplay,
sender,
popupProps,
Expand Down
Loading

0 comments on commit 66ad91d

Please sign in to comment.