diff --git a/packages/frontend/src/components/login/v2/ConfirmLogin.js b/packages/frontend/src/components/login/v2/ConfirmLogin.js index e0fcccb435..afce41c1e7 100644 --- a/packages/frontend/src/components/login/v2/ConfirmLogin.js +++ b/packages/frontend/src/components/login/v2/ConfirmLogin.js @@ -21,7 +21,8 @@ export default ({ appReferrer, contractId, publicKey, - contractIdUrl + contractIdUrl, + isValidFailureUrl }) => { const [loggingIn, setLoggingIn] = useState(false); const [showGrantFullAccessModal, setShowGrantFullAccessModal] = useState(false); @@ -81,7 +82,7 @@ export default ({ handleClickConnect(); } }} - disabled={loggingIn} + disabled={loggingIn || !isValidFailureUrl} sending={loggingIn} sendingString='button.connecting' > diff --git a/packages/frontend/src/components/login/v2/ConfirmLoginWrapper.js b/packages/frontend/src/components/login/v2/ConfirmLoginWrapper.js index 778afa4c50..a267323279 100644 --- a/packages/frontend/src/components/login/v2/ConfirmLoginWrapper.js +++ b/packages/frontend/src/components/login/v2/ConfirmLoginWrapper.js @@ -15,7 +15,8 @@ export default ({ contractId, contractIdUrl, onClickCancel, - publicKey + publicKey, + isValidFailureUrl }) => { const dispatch = useDispatch(); @@ -45,6 +46,7 @@ export default ({ ); }} contractIdUrl={contractIdUrl} + isValidFailureUrl={isValidFailureUrl} /> ); }; \ No newline at end of file diff --git a/packages/frontend/src/components/login/v2/SelectAccountLoginWrapper.js b/packages/frontend/src/components/login/v2/SelectAccountLoginWrapper.js index a6d6e6b832..113da2b410 100644 --- a/packages/frontend/src/components/login/v2/SelectAccountLoginWrapper.js +++ b/packages/frontend/src/components/login/v2/SelectAccountLoginWrapper.js @@ -14,7 +14,6 @@ import { selectAccountAccountsBalances } from '../../../redux/slices/account'; import { selectAvailableAccounts } from '../../../redux/slices/availableAccounts'; -import { checkIsValidUrl } from '../../../utils/helper-api'; import SelectAccountLogin from './SelectAccountLogin'; export default ({ @@ -22,7 +21,8 @@ export default ({ contractId, contractIdUrl, onClickNext, - failureUrl + failureUrl, + isValidFailureUrl }) => { const dispatch = useDispatch(); @@ -49,7 +49,7 @@ export default ({ contractIdUrl={contractIdUrl} onClickCancel={() => { Mixpanel.track("LOGIN Click deny button"); - if (failureUrl && checkIsValidUrl(failureUrl)) { + if (failureUrl && isValidFailureUrl) { window.location.href = failureUrl; } else { dispatch(redirectToApp()); diff --git a/packages/frontend/src/components/sign/v2/SignTransactionSummary.js b/packages/frontend/src/components/sign/v2/SignTransactionSummary.js index 5c78fb6ea5..af4360f178 100644 --- a/packages/frontend/src/components/sign/v2/SignTransactionSummary.js +++ b/packages/frontend/src/components/sign/v2/SignTransactionSummary.js @@ -53,7 +53,8 @@ export default ({ onClickApprove, onClickMoreInformation, accountUrlReferrer, - submittingTransaction + submittingTransaction, + isValidCallbackUrl }) => { const insufficientBalance = availableBalance && transferAmount && new BN(availableBalance).lt(new BN(transferAmount)); return ( @@ -82,13 +83,13 @@ export default ({ diff --git a/packages/frontend/src/components/sign/v2/SignTransactionSummaryWrapper.js b/packages/frontend/src/components/sign/v2/SignTransactionSummaryWrapper.js index b2214bfe3c..9a98d3a356 100644 --- a/packages/frontend/src/components/sign/v2/SignTransactionSummaryWrapper.js +++ b/packages/frontend/src/components/sign/v2/SignTransactionSummaryWrapper.js @@ -16,7 +16,8 @@ export default ({ onClickCancel, onClickApprove, submittingTransaction, - signGasFee + signGasFee, + isValidCallbackUrl }) => { const accountLocalStorageAccountId = useSelector(selectAccountLocalStorageAccountId); @@ -35,6 +36,7 @@ export default ({ onClickMoreInformation={onClickMoreInformation} accountUrlReferrer={accountUrlReferrer} submittingTransaction={submittingTransaction} + isValidCallbackUrl={isValidCallbackUrl} /> ); }; \ No newline at end of file diff --git a/packages/frontend/src/routes/LoginWrapper.js b/packages/frontend/src/routes/LoginWrapper.js index 590271e276..a329511d85 100644 --- a/packages/frontend/src/routes/LoginWrapper.js +++ b/packages/frontend/src/routes/LoginWrapper.js @@ -28,6 +28,7 @@ export function LoginWrapper() { const contractId = URLParams.contract_id; const publicKey = URLParams.public_key; const failureUrl = checkIsValidUrl(URLParams.failure_url) ? URLParams.failure_url : null; + const isValidFailureUrl = checkIsValidUrl(failureUrl); const invalidContractId = URLParams.invalidContractId; const contractIdUrl = `${EXPLORER_URL}/accounts/${contractId}`; @@ -47,7 +48,7 @@ export function LoginWrapper() { invalidContractId={contractId} onClickReturnToApp={() => { Mixpanel.track("LOGIN Invalid contract id Click return to app button", { contract_id: contractId }); - if (checkIsValidUrl(failureUrl)) { + if (isValidFailureUrl) { window.location.href = failureUrl; } }} @@ -63,6 +64,7 @@ export function LoginWrapper() { contractIdUrl={contractIdUrl} onClickCancel={() => setConfirmLogin(false)} publicKey={publicKey} + isValidFailureUrl={isValidFailureUrl} /> ); } @@ -73,6 +75,7 @@ export function LoginWrapper() { contractId={contractId} contractIdUrl={contractIdUrl} failureUrl={failureUrl} + isValidFailureUrl={isValidFailureUrl} onClickNext={() => { setConfirmLogin(true); window.scrollTo(0, 0); }} /> ); diff --git a/packages/frontend/src/routes/SignWrapper.js b/packages/frontend/src/routes/SignWrapper.js index 85bc45b334..23628357be 100644 --- a/packages/frontend/src/routes/SignWrapper.js +++ b/packages/frontend/src/routes/SignWrapper.js @@ -7,7 +7,7 @@ import SignTransferRetry from '../components/sign/SignTransferRetry'; import SignTransactionDetailsWrapper from '../components/sign/v2/SignTransactionDetailsWrapper'; import SignTransactionSummaryWrapper from '../components/sign/v2/SignTransactionSummaryWrapper'; import { Mixpanel } from '../mixpanel'; -import { switchAccount } from '../redux/actions/account'; +import { switchAccount, redirectTo } from '../redux/actions/account'; import { selectAccountId } from '../redux/slices/account'; import { selectAvailableAccounts, selectAvailableAccountsIsLoading } from '../redux/slices/availableAccounts'; import { @@ -22,6 +22,7 @@ import { selectSignTransactions, selectSignTransactionsBatchIsValid } from '../redux/slices/sign'; +import { checkIsValidUrl } from '../utils/helper-api'; export function SignWrapper() { const dispatch = useDispatch(); @@ -45,6 +46,7 @@ export function SignWrapper() { const transactions = useSelector(selectSignTransactions); const accountId = useSelector(selectAccountId); const transactionBatchisValid = useSelector(selectSignTransactionsBatchIsValid); + const isValidCallbackUrl = checkIsValidUrl(signCallbackUrl); const signerId = transactions.length && transactions[0].signerId; const signGasFee = new BN(signFeesGasLimitIncludingGasChanges).div(new BN('1000000000000')).toString(); @@ -81,11 +83,13 @@ export function SignWrapper() { } if (signStatus === SIGN_STATUS.SUCCESS) { - if (signCallbackUrl && !!transactionHashes.length) { + if (signCallbackUrl && !!transactionHashes.length && isValidCallbackUrl) { window.location.href = addQueryParams(signCallbackUrl, { signMeta, transactionHashes: transactionHashes.join(',') }); + } else { + dispatch(redirectTo('/')); } } }, [signStatus]); @@ -97,7 +101,7 @@ export function SignWrapper() { const handleCancelTransaction = async () => { Mixpanel.track("SIGN Deny the transaction"); - if (signCallbackUrl) { + if (signCallbackUrl && isValidCallbackUrl) { if (signStatus?.success !== false) { window.location.href = addQueryParams(signCallbackUrl, { signMeta, @@ -112,6 +116,8 @@ export function SignWrapper() { errorMessage: encodeURIComponent(signStatus?.errorMessage?.substring(0, 100)) || encodeURIComponent('Unknown error') }); return; + } else { + dispatch(redirectTo('/')); } }; @@ -155,6 +161,7 @@ export function SignWrapper() { signGasFee={signGasFee} onClickMoreInformation={() => setCurrentDisplay(DISPLAY.TRANSACTION_DETAILS)} onClickEditAccount={() => setCurrentDisplay(DISPLAY.ACCOUNT_SELECTION)} + isValidCallbackUrl={isValidCallbackUrl} /> ); } \ No newline at end of file diff --git a/packages/frontend/src/utils/helper-api.js b/packages/frontend/src/utils/helper-api.js index 7049fd4810..f002099037 100644 --- a/packages/frontend/src/utils/helper-api.js +++ b/packages/frontend/src/utils/helper-api.js @@ -14,8 +14,8 @@ export function checkIsValidUrl(url) { } const urlProtocol = new URL(url).protocol; - if (urlProtocol !== 'http:' && urlProtocol !== 'https:') { - console.log('Invalid URL protocol:', urlProtocol, 'Please use http or https.'); + if (urlProtocol === 'javascript:') { + console.log('Invalid URL protocol:', urlProtocol, 'URL cannot execute JavaScript'); return false; }