Skip to content

Commit

Permalink
enhancement: update url whitelist (#5356)
Browse files Browse the repository at this point in the history
* enhancement: move open url in browser into own function

* enhancement: add confirmation popup

* chore: add localization to external url popup

* fix: fix condition for blacklist

* fix: fix url validation

* chore: remove blacklist from electron + locale fixase

* fix: update strings

Co-authored-by: Nicole O'Brien <nicole.obrien@iota.org>
  • Loading branch information
MarkNerdi996 and nicole-obrien committed Dec 7, 2022
1 parent d497912 commit be3cff4
Show file tree
Hide file tree
Showing 15 changed files with 83 additions and 57 deletions.
40 changes: 2 additions & 38 deletions packages/desktop/electron/main.js
Expand Up @@ -175,50 +175,14 @@ if (app.isPackaged) {
paths.errorHtml = path.join(__dirname, '../error.html')
}

/**
* Check URL against allowlist
*/
function isUrlAllowed(targetUrl) {
const externalAllowlist = [
// IOTA Foundation
'blog.iota.org',
'chrysalis.iota.org',
'chrysalis.docs.iota.org',
'discord.iota.org',
'firefly.iota.org',
'iota.org',
'privacy@iota.org',
'wiki.iota.org',
'explorer.iota.org',

// Assembly / Shimmer
'assembly.sc',
'shimmer.network',
'explorer.shimmer.network',

// GitHub
'github.com/iotaledger/firefly/issues',
'github.com/iotaledger/firefly/issues/new/choose',

// Other
'support.ledger.com',
]
const url = new URL(targetUrl)
const domain = url.hostname.replace('www.', '').replace('mailto:', '')

return externalAllowlist.includes(domain) || externalAllowlist.includes(domain + url.pathname)
}

/**
* Handles url navigation events
*/
const handleNavigation = (e, url) => {
e.preventDefault()

try {
if (isUrlAllowed(url)) {
shell.openExternal(url)
}
shell.openExternal(url)
} catch (err) {
console.error(err)
}
Expand Down Expand Up @@ -325,7 +289,7 @@ function createWindow() {
* Handle permissions requests
*/
session.defaultSession.setPermissionRequestHandler((_webContents, permission, cb, details) => {
if (permission === 'openExternal' && details && details.externalURL && isUrlAllowed(details.externalURL)) {
if (permission === 'openExternal' && details && details.externalURL) {
return cb(true)
}

Expand Down
Expand Up @@ -21,7 +21,7 @@
import { ActivityType, formatTokenAmountPrecise } from '@core/wallet'
import { BASE_TOKEN } from '@core/network/constants'
import { activeProfile } from '@core/profile/stores'
import { Platform } from '@core/app'
import { openUrlInBrowser } from '@core/app'
import { ExplorerEndpoint, getOfficialExplorerUrl } from '@core/network'
import { openPopup } from '@auxiliary/popup'
Expand Down Expand Up @@ -58,7 +58,7 @@
}
function handleExplorerClick(): void {
Platform.openUrl(`${explorerUrl}/${ExplorerEndpoint.Nft}/${id}`)
openUrlInBrowser(`${explorerUrl}/${ExplorerEndpoint.Nft}/${id}`)
}
function handleSendClick(): void {
Expand Down
@@ -1,15 +1,15 @@
<script lang="typescript">
import { Button, Text, ButtonSize } from 'shared/components'
import { localize } from '@core/i18n'
import { Platform } from '@core/app'
import { openUrlInBrowser } from '@core/app'
import { HelpAndInfoRoute } from '@core/router'
export let route: HelpAndInfoRoute
export let url: string
export let actionLocale: string
function handleClick(): void {
Platform.openUrl(url)
openUrlInBrowser(url)
}
</script>

Expand Down
@@ -1,6 +1,6 @@
<script lang="typescript">
import { Link, Text } from 'shared/components'
import { Platform } from '@core/app'
import { openUrlInBrowser } from '@core/app'
</script>

<div class="mb-8">
Expand Down Expand Up @@ -102,7 +102,7 @@
<Text type="h2" classes="mt-8 mb-5">2. Data Protection</Text>
<Text type="p" secondary classes="mb-4">
IOTA does not collect any of your personal data through the App. Please refer to the Firefly Privacy Policy (
<Link onClick={() => Platform.openUrl('https://firefly.iota.org/privacy')}>
<Link onClick={() => openUrlInBrowser('https://firefly.iota.org/privacy')}>
https://firefly.iota.org/privacy
</Link>) for information on how we and our third-party service providers process data in relation to the App.
</Text>
Expand Down Expand Up @@ -399,7 +399,7 @@
This Privacy Policy is dedicated to the users of the App. If you would like to know more about how the IOTA
Foundation (hereinafter "IOTA", "we", "us", "our") processes Personal Data collected and processed in connection
with other services and activities offered by IOTA, please see IOTA's general Privacy Policy available at
<Link onClick={() => Platform.openUrl('https://www.iota.org/privacy-policy')}>
<Link onClick={() => openUrlInBrowser('https://www.iota.org/privacy-policy')}>
https://www.iota.org/privacy-policy
</Link>
.
Expand Down
Expand Up @@ -5,7 +5,7 @@
import { Activity, formatTokenAmountPrecise } from '@core/wallet'
import { BASE_TOKEN, ExplorerEndpoint } from '@core/network'
import { getOfficialExplorerUrl } from '@core/network/utils'
import { Platform } from '@core/app'
import { openUrlInBrowser } from '@core/app'
import { truncateString } from '@core/utils'
import { setClipboard } from '@core/utils'
Expand Down Expand Up @@ -68,7 +68,7 @@
function handleTransactionIdClick(): void {
explorerUrl
? Platform.openUrl(
? openUrlInBrowser(
`${explorerUrl}/${ExplorerEndpoint.Transaction}/${activity.asyncData?.claimingTransactionId}`
)
: setClipboard(activity.asyncData?.claimingTransactionId)
Expand Down
4 changes: 2 additions & 2 deletions packages/shared/components/popups/ActivityDetailsPopup.svelte
Expand Up @@ -12,7 +12,7 @@
NftActivityDetails,
ActivityInformation,
} from 'shared/components'
import { Platform } from '@core/app'
import { openUrlInBrowser } from '@core/app'
import {
ActivityAsyncStatus,
ActivityDirection,
Expand Down Expand Up @@ -84,7 +84,7 @@
}
function handleExplorerClick(): void {
Platform.openUrl(`${explorerUrl}/${ExplorerEndpoint.Transaction}/${activity.transactionId}`)
openUrlInBrowser(`${explorerUrl}/${ExplorerEndpoint.Transaction}/${activity.transactionId}`)
}
function handleTransactionIdClick(): void {
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/components/popups/ConfirmationPopup.svelte
Expand Up @@ -37,7 +37,7 @@
</Text>
<div class="space-y-4">
{#if description}
<Text fontSize="14" classes="text-left">{description}</Text>
<Text fontSize="14" classes="text-left break-words">{description}</Text>
{/if}
{#if hint}
<TextHint {info} {success} {warning} {danger} text={hint} />
Expand Down
@@ -1,6 +1,6 @@
<script lang="typescript">
import { LedgerAnimation, Button, Link, Text } from 'shared/components'
import { Platform } from '@core/app'
import { openUrlInBrowser } from '@core/app'
import { closePopup } from '@auxiliary/popup'
import { localize } from '@core/i18n'
Expand Down Expand Up @@ -34,7 +34,7 @@
<Link
classes="ml-0.5 inline-block text-13 leading-160"
onClick={() =>
Platform.openUrl(
openUrlInBrowser(
'https://support.ledger.com/hc/en-us/articles/360019868977-Fix-USB-connection-issues-with-Ledger-Live?support=true'
)}
>
Expand Down
6 changes: 3 additions & 3 deletions packages/shared/components/popups/LegalUpdate.svelte
Expand Up @@ -9,7 +9,7 @@
needsToAcceptLatestPrivacyPolicy,
TERMS_OF_SERVICE_VERSION,
PRIVACY_POLICY_VERSION,
Platform,
openUrlInBrowser,
} from '@core/app'
const TOS_LINK = 'https://firefly.iota.org/terms'
Expand All @@ -20,11 +20,11 @@
const privacyPolicy = needsToAcceptLatestPrivacyPolicy()
function handleViewTosClick(): void {
Platform.openUrl(TOS_LINK)
openUrlInBrowser(TOS_LINK)
}
function handleViewPrivPolicyClick(): void {
Platform.openUrl(PRIVACY_POLICY_LINK)
openUrlInBrowser(PRIVACY_POLICY_LINK)
}
function handleConfirmClick(): void {
Expand Down
4 changes: 2 additions & 2 deletions packages/shared/components/popups/Version.svelte
Expand Up @@ -10,9 +10,9 @@
appVersionDetails,
AppStage,
appStage,
Platform,
PlatformOption,
platform,
openUrlInBrowser,
} from '@core/app'
import { formatDate, localize } from '@core/i18n'
import { closePopup } from '@auxiliary/popup'
Expand All @@ -24,7 +24,7 @@
if (hasAutoUpdate) {
downloadAppUpdate()
} else {
Platform.openUrl('https://firefly.iota.org')
openUrlInBrowser('https://firefly.iota.org')
}
closePopup()
}
Expand Down
@@ -0,0 +1,24 @@
export const externalAllowedLinks = [
// IOTA Foundation
'blog.iota.org',
'chrysalis.iota.org',
'chrysalis.docs.iota.org',
'discord.iota.org',
'firefly.iota.org',
'iota.org',
'privacy@iota.org',
'wiki.iota.org',
'explorer.iota.org',

// Assembly / Shimmer
'assembly.sc',
'shimmer.network',
'explorer.shimmer.network',

// GitHub
'github.com/iotaledger/firefly/issues',
'github.com/iotaledger/firefly/issues/new/choose',

// Other
'support.ledger.com',
]
1 change: 1 addition & 0 deletions packages/shared/lib/core/app/constants/index.ts
@@ -1,4 +1,5 @@
export * from './app-updater-poll-interval.constant'
export * from './default-app-settings.constant'
export * from './external-allowed-links.constant'
export * from './privacy-policy-version.constant'
export * from './terms-of-service-version.constant'
1 change: 1 addition & 0 deletions packages/shared/lib/core/app/utils/index.ts
Expand Up @@ -2,5 +2,6 @@ export * from './checkForAppUpdate'
export * from './installAppUpdate'
export * from './needsToAcceptLatestPrivacyPolicy'
export * from './needsToAcceptLatestTermsOfService'
export * from './openUrlInBrowser'
export * from './pollCheckForAppUpdate'
export * from './shouldBeDarkMode'
30 changes: 30 additions & 0 deletions packages/shared/lib/core/app/utils/openUrlInBrowser.ts
@@ -0,0 +1,30 @@
import { closePopup, openPopup } from '@auxiliary/popup'
import { localize } from '@core/i18n'
import { Platform } from '../classes/platform.class'
import { externalAllowedLinks } from '../constants'

export function openUrlInBrowser(targetUrl: string): void {
const url = new URL(targetUrl)
const domain = url.hostname.replace('www.', '').replace('mailto:', '')

const isAllowed = externalAllowedLinks.includes(domain) || externalAllowedLinks.includes(domain + url.pathname)

if (isAllowed) {
Platform.openUrl(targetUrl)
} else {
openPopup({
type: 'confirmation',
props: {
title: localize('popups.externalUrl.title'),
description: localize('popups.externalUrl.body', { values: { url: targetUrl } }),
hint: localize('popups.externalUrl.hint'),
warning: true,
confirmText: localize('popups.externalUrl.action'),
onConfirm: () => {
Platform.openUrl(targetUrl)
closePopup()
},
},
})
}
}
6 changes: 6 additions & 0 deletions packages/shared/locales/en.json
Expand Up @@ -700,6 +700,12 @@
"errorTitle": "Unable to delete {name}",
"errorBody1": "You cannot delete this wallet, you must have at least one."
},
"externalUrl": {
"title": "Open URL in Browser",
"body": "Are you sure you want to open \"{url}\" in the browser?",
"hint": "This URL is unknown to Firefly. Please double check the URL before opening it.",
"action": "Open URL"
},
"hideAccount": {
"title": "Hide {name}?",
"body": "You can find this wallet later by enabling \"Show hidden wallets\" in Advanced Settings.",
Expand Down

0 comments on commit be3cff4

Please sign in to comment.