Skip to content

Commit 9a1b49c

Browse files
committed
fix: prevent transfer send opening on unsupported deeplinks
1 parent 49c1f68 commit 9a1b49c

File tree

10 files changed

+79
-40
lines changed

10 files changed

+79
-40
lines changed

src/composables/deepLinkApi.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
import { ref } from 'vue';
2-
import { Router, RouteLocationNormalized as Route } from 'vue-router';
2+
import {
3+
Router,
4+
RouteLocationNormalized as Route,
5+
} from 'vue-router';
6+
import { checkIfSuperheroCallbackUrl } from '@/utils';
7+
import { MODAL_TRANSFER_SEND } from '@/constants';
8+
import { useModals } from '@/composables/modals';
39

410
export interface UseDeepLinkApiOptions {
511
router: Router
612
}
13+
714
/**
815
* TODO: refactor once upgrade to vue-router: 4.x.x
916
* @param { router: Router }
@@ -16,6 +23,17 @@ export function useDeepLinkApi({ router }: UseDeepLinkApiOptions) {
1623
: null,
1724
);
1825

26+
/**
27+
* Function needed to support legacy tipping from superhero.com
28+
*/
29+
function checkIfOpenTransferSendModal() {
30+
if (checkIfSuperheroCallbackUrl(route.query)) {
31+
const { openModal } = useModals();
32+
33+
openModal(MODAL_TRANSFER_SEND);
34+
}
35+
}
36+
1937
function openCallbackOrGoHome(
2038
isSuccess: boolean,
2139
templateParams: Record<string, string> = {},
@@ -34,6 +52,7 @@ export function useDeepLinkApi({ router }: UseDeepLinkApiOptions) {
3452
}
3553

3654
return {
55+
checkIfOpenTransferSendModal,
3756
callbackOrigin,
3857
openCallbackOrGoHome,
3958
};

src/composables/transferSendForm.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
computed,
3+
nextTick,
34
ref,
45
} from 'vue';
56
import { useI18n } from 'vue-i18n';
@@ -44,7 +45,7 @@ export function useTransferSendForm({
4445

4546
const { t } = useI18n();
4647
const { openModal, openDefaultModal } = useModals();
47-
const { errors, validate } = useForm();
48+
const { errors, validate, validateField } = useForm();
4849

4950
const hasError = computed((): boolean => ['address', 'amount'].some((errorKey) => getMessageByFieldName(errors.value[errorKey]).status === 'error'));
5051

@@ -68,10 +69,10 @@ export function useTransferSendForm({
6869
const result: Partial<TransferFormModel> = {};
6970

7071
const selectedToken = tokenHandler ? tokenHandler(token, formModel.value.selectedAsset) : null;
72+
7173
if (selectedToken) {
7274
result.selectedAsset = selectedToken;
7375
}
74-
7576
if (account) {
7677
result.address = account;
7778
}
@@ -85,11 +86,14 @@ export function useTransferSendForm({
8586
return result;
8687
}
8788

88-
function updateFormModelValues(params: Dictionary) {
89+
async function updateFormModelValues(params: Dictionary) {
90+
const updatedValues = returnFormModelValues(params, getSelectedAssetValue);
8991
formModel.value = {
9092
...formModel.value,
91-
...returnFormModelValues(params, getSelectedAssetValue),
93+
...updatedValues,
9294
};
95+
await nextTick();
96+
Object.keys(updatedValues).forEach((field) => validateField(field));
9397
}
9498

9599
async function openScanQrModal(tokenBalances: IToken[]) {

src/lib/RouteQueryActionsController.ts

+3-23
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import {
2-
LocationQuery,
3-
Router,
4-
} from 'vue-router';
5-
import { Ref } from 'vue';
1+
import { Router } from 'vue-router';
62
import { Dictionary } from '@/types';
73
import { useModals } from '@/composables';
84
import { APP_LINK_WEB, MODAL_TRANSFER_SEND } from '@/constants';
@@ -56,28 +52,12 @@ export const RouteQueryActionsController = (() => {
5652
},
5753
};
5854

59-
function getDeeplinkAction(
60-
query: LocationQuery,
61-
isLoggedIn: Ref<boolean>,
62-
): RouteQueryActionName | null {
63-
if (!isLoggedIn.value || !query) {
64-
return null;
65-
}
66-
67-
return (query['x-success'] && query['x-cancel'])
68-
? 'transferSend'
69-
: null;
70-
}
71-
7255
/**
7356
* Monitor the action arguments in the query string and perform assigned action method.
7457
*/
75-
function init(router: Router, isLoggedIn: Ref<boolean>) {
58+
function init(router: Router) {
7659
const unbind = router.beforeResolve(({ query }, from, next) => {
77-
const action = (
78-
query?.[ACTION_PROP]
79-
|| getDeeplinkAction(query, isLoggedIn)
80-
) as null | RouteQueryActionName;
60+
const action = query?.[ACTION_PROP] as null | RouteQueryActionName;
8161

8262
if (action && typeof action === 'string' && availableActions[action]) {
8363
const queryWithoutAction = { ...query };

src/popup/components/Modals/TransferSend.vue

Whitespace-only changes.

src/popup/components/ProtocolSpecificView.vue

+13-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919
* or displaying the modals.
2020
*/
2121
22-
import { PropType, defineAsyncComponent, defineComponent } from 'vue';
22+
import {
23+
PropType,
24+
defineAsyncComponent,
25+
defineComponent,
26+
} from 'vue';
2327
import { useStore } from 'vuex';
2428
import type { Protocol, ProtocolView, ProtocolViewsConfig } from '@/types';
2529
import { DISTINCT_PROTOCOL_VIEWS, PROTOCOL_AETERNITY } from '@/constants';
@@ -30,7 +34,9 @@ import aeternityViews from '@/protocols/aeternity/views';
3034
import bitcoinViews from '@/protocols/bitcoin/views';
3135
3236
import { useRoute } from 'vue-router';
33-
import { detectProtocolByOwner } from '@/utils';
37+
import {
38+
detectProtocolByOwner,
39+
} from '@/utils';
3440
import InfoBox from './InfoBox.vue';
3541
3642
/**
@@ -54,13 +60,16 @@ export default defineComponent({
5460
},
5561
setup(props) {
5662
const store = useStore();
57-
const { activeAccount } = useAccounts({ store });
58-
const { activeNetwork } = useNetworks();
5963
const { params, meta } = useRoute();
64+
65+
const { activeNetwork } = useNetworks();
66+
const { activeAccount } = useAccounts({ store });
67+
6068
const ownerProtocol = detectProtocolByOwner(
6169
activeNetwork.value.type,
6270
params.transactionOwner as string,
6371
);
72+
6473
const importViewComponent = views[
6574
meta.isMultisig
6675
? PROTOCOL_AETERNITY

src/popup/components/TransferSend/TransferSendRecipient.vue

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<Field
44
v-slot="{ field }"
55
name="address"
6+
:model-value="modelValue"
67
:rules="{
78
required: true,
89
not_same_as: [activeAccount.address, protocol],

src/popup/pages/Dashboard.vue

+17-3
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,25 @@
4949
</template>
5050

5151
<script lang="ts">
52-
import { defineComponent } from 'vue';
53-
52+
import {
53+
defineComponent,
54+
onMounted,
55+
} from 'vue';
56+
import { useRouter } from 'vue-router';
5457
import { useStore } from 'vuex';
58+
5559
import {
5660
DASHBOARD_CARD_ID,
5761
IS_CORDOVA,
5862
PROTOCOL_AETERNITY,
5963
UNFINISHED_FEATURES,
6064
} from '@/constants';
6165
import { ROUTE_ACCOUNT_DETAILS_NAMES_CLAIM, ROUTE_APPS_BROWSER } from '@/popup/router/routeNames';
62-
import { useAccounts, useAeSdk } from '@/composables';
66+
import {
67+
useAccounts,
68+
useAeSdk,
69+
useDeepLinkApi,
70+
} from '@/composables';
6371
6472
import DashboardCard from '@/popup/components/DashboardCard.vue';
6573
import DashboardWrapper from '@/popup/components/DashboardWrapper.vue';
@@ -89,14 +97,20 @@ export default defineComponent({
8997
},
9098
setup() {
9199
const store = useStore();
100+
const router = useRouter();
92101
93102
const {
94103
activeAccount,
95104
activeAccountSimplexLink,
96105
} = useAccounts({ store });
106+
const { checkIfOpenTransferSendModal } = useDeepLinkApi({ router });
97107
98108
const { isNodeMainnet, isNodeTestnet } = useAeSdk({ store });
99109
110+
onMounted(() => {
111+
checkIfOpenTransferSendModal();
112+
});
113+
100114
return {
101115
PROTOCOL_AETERNITY,
102116
DASHBOARD_CARD_ID,

src/popup/router/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const {
5050
} = useAccounts({ store });
5151
const { setPopupProps } = usePopupProps();
5252

53-
RouteQueryActionsController.init(router, isLoggedIn);
53+
RouteQueryActionsController.init(router);
5454

5555
const unbind = router.beforeEach(async (to, from, next) => {
5656
await watchUntilTruthy(() => store.state.isRestored);

src/protocols/aeternity/components/TransferSendForm.vue

+6-4
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,13 @@ import { useStore } from 'vuex';
166166
import { Encoded } from '@aeternity/aepp-sdk';
167167
168168
import {
169-
AGGREGATOR_URL,
170169
MODAL_PAYLOAD_FORM,
171170
PROTOCOL_AETERNITY,
172171
} from '@/constants';
173-
import { isUrlValid } from '@/utils';
172+
import {
173+
checkIfSuperheroCallbackUrl,
174+
isUrlValid,
175+
} from '@/utils';
174176
import {
175177
useAccounts,
176178
useBalances,
@@ -406,8 +408,8 @@ export default defineComponent({
406408
}
407409
408410
const { query } = route;
409-
const slicedAggregatorUrl = AGGREGATOR_URL.endsWith('/') ? AGGREGATOR_URL.slice(0, -1) : AGGREGATOR_URL;
410-
if ([query['x-success'], query['x-cancel']].every((value) => value && (value as string).startsWith(slicedAggregatorUrl))) {
411+
412+
if (checkIfSuperheroCallbackUrl(query)) {
411413
isUrlTippingEnabled.value = true;
412414
}
413415
updateFormModelValues({

src/utils/common.ts

+10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { WatchSource, watch } from 'vue';
88
import { defer, uniqWith } from 'lodash-es';
99
import BigNumber from 'bignumber.js';
1010
import { useI18n } from 'vue-i18n';
11+
import { LocationQuery } from 'vue-router';
1112
import type {
1213
BigNumberPublic,
1314
IAccount,
@@ -22,6 +23,7 @@ import type {
2223
} from '@/types';
2324
import {
2425
ADDRESS_GAP_LIMIT,
26+
AGGREGATOR_URL,
2527
DECIMAL_PLACES_HIGH_PRECISION,
2628
DECIMAL_PLACES_LOW_PRECISION,
2729
IS_CORDOVA,
@@ -398,3 +400,11 @@ export async function defaultAccountDiscovery(
398400
));
399401
return lastNotEmptyIdx;
400402
}
403+
404+
export function checkIfSuperheroCallbackUrl(query: LocationQuery) {
405+
const slicedAggregatorUrl = AGGREGATOR_URL.endsWith('/') ? AGGREGATOR_URL.slice(0, -1) : AGGREGATOR_URL;
406+
407+
return [query['x-success'], query['x-cancel']].every(
408+
(value) => value && (value as string).startsWith(slicedAggregatorUrl),
409+
);
410+
}

0 commit comments

Comments
 (0)