Merge pull request #14 from tornadocash/audit

fix: audit
This commit is contained in:
Danil Kovtonyuk 2022-06-15 16:39:41 +10:00 committed by GitHub
commit 8fbbe4c67b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 156 additions and 87 deletions

View File

@ -24,3 +24,7 @@ To start a development build (e.g. with logging and file watching) run `yarn dev
## Architecture ## Architecture
For detailed explanation on how things work, checkout [Nuxt.js docs](https://nuxtjs.org). For detailed explanation on how things work, checkout [Nuxt.js docs](https://nuxtjs.org).
## Audit
[TornadoCash_Сlassic_dApp_audit_Decurity.pdf](https://tornado.cash/audits/TornadoCash_Сlassic_dApp_audit_Decurity.pdf)

View File

@ -35,6 +35,7 @@
class="detail-description" class="detail-description"
:href="txExplorerUrl(tx.txHash)" :href="txExplorerUrl(tx.txHash)"
target="_blank" target="_blank"
rel="noopener noreferrer"
> >
{{ tx.txHash }} {{ tx.txHash }}
</a> </a>

View File

@ -12,7 +12,7 @@
class="footer-address__value" class="footer-address__value"
target="_blank" target="_blank"
:href="addressExplorerUrl(donationsAddress)" :href="addressExplorerUrl(donationsAddress)"
rel="noreferrer" rel="noopener noreferrer"
>{{ donationsAddress }}</a >{{ donationsAddress }}</a
> >
</div> </div>
@ -31,7 +31,7 @@
type="is-icon" type="is-icon"
:href="duneLink" :href="duneLink"
target="_blank" target="_blank"
rel="noreferrer" rel="noopener noreferrer"
icon-right="stats" icon-right="stats"
></b-button> ></b-button>
<b-button <b-button
@ -39,7 +39,7 @@
type="is-icon" type="is-icon"
href="https://torn.community" href="https://torn.community"
target="_blank" target="_blank"
rel="noreferrer" rel="noopener noreferrer"
icon-right="discourse" icon-right="discourse"
></b-button> ></b-button>
<b-button <b-button
@ -47,7 +47,7 @@
type="is-icon" type="is-icon"
href="https://discord.com/invite/TFDrM8K42j" href="https://discord.com/invite/TFDrM8K42j"
target="_blank" target="_blank"
rel="noreferrer" rel="noopener noreferrer"
icon-right="discord" icon-right="discord"
></b-button> ></b-button>
<b-button <b-button
@ -55,7 +55,7 @@
type="is-icon" type="is-icon"
href="https://tornado-cash.medium.com" href="https://tornado-cash.medium.com"
target="_blank" target="_blank"
rel="noreferrer" rel="noopener noreferrer"
icon-right="medium" icon-right="medium"
></b-button> ></b-button>
<b-button <b-button
@ -63,7 +63,7 @@
type="is-icon" type="is-icon"
href="https://twitter.com/TornadoCash" href="https://twitter.com/TornadoCash"
target="_blank" target="_blank"
rel="noreferrer" rel="noopener noreferrer"
icon-right="twitter" icon-right="twitter"
></b-button> ></b-button>
<b-button <b-button
@ -71,7 +71,7 @@
type="is-icon" type="is-icon"
href="https://t.me/TornadoCashOfficial" href="https://t.me/TornadoCashOfficial"
target="_blank" target="_blank"
rel="noreferrer" rel="noopener noreferrer"
icon-right="telegram" icon-right="telegram"
></b-button> ></b-button>
<b-button <b-button
@ -79,7 +79,7 @@
type="is-icon" type="is-icon"
href="https://github.com/tornadocash" href="https://github.com/tornadocash"
target="_blank" target="_blank"
rel="noreferrer" rel="noopener noreferrer"
icon-right="github" icon-right="github"
></b-button> ></b-button>
<div class="break"></div> <div class="break"></div>

View File

@ -19,6 +19,7 @@
class="detail-description" class="detail-description"
:href="txExplorerUrl(job.txHash)" :href="txExplorerUrl(job.txHash)"
target="_blank" target="_blank"
rel="noopener noreferrer"
> >
{{ job.txHash }} {{ job.txHash }}
</a> </a>

View File

@ -3,7 +3,9 @@
<template v-slot:content> <template v-slot:content>
<template v-if="isLoggedIn"> <template v-if="isLoggedIn">
<p>{{ $t('web3connected') }}</p> <p>{{ $t('web3connected') }}</p>
<a :href="addressExplorerUrl(ethAccount)" target="_blank">{{ shortAddress(ethAccount) }}</a> <a :href="addressExplorerUrl(ethAccount)" target="_blank" rel="noopener noreferrer">{{
shortAddress(ethAccount)
}}</a>
<p><NumberFormat :value="balance" /> {{ currency }}</p> <p><NumberFormat :value="balance" /> {{ currency }}</p>
</template> </template>
<template v-else> <template v-else>

View File

@ -20,10 +20,10 @@
{{ $t('compliance') }} {{ $t('compliance') }}
</b-navbar-item> </b-navbar-item>
<b-navbar-item <b-navbar-item
href="http://docs.tornado.cash" href="https://docs.tornado.cash"
target="_blank" target="_blank"
data-test="docs_link" data-test="docs_link"
rel="noreferrer" rel="noopener noreferrer"
class="has-tag" class="has-tag"
> >
<b-icon icon="open-book" size="is-small" class="mr-1" /> <b-icon icon="open-book" size="is-small" class="mr-1" />

View File

@ -18,10 +18,21 @@
</template> </template>
<template v-slot:description>{{ notice.description }}</template> <template v-slot:description>{{ notice.description }}</template>
</i18n> </i18n>
<a v-if="notice.nova" href="https://nova.tornadocash.eth.link" target="_blank"> <a
v-if="notice.nova"
href="https://nova.tornadocash.eth.link"
target="_blank"
rel="noopener noreferrer"
>
Tornado Cash Nova Tornado Cash Nova
</a> </a>
<a v-if="notice.txHash" :href="txExplorerUrl(notice.txHash)" target="_blank" data-test="popup_message"> <a
v-if="notice.txHash"
:href="txExplorerUrl(notice.txHash)"
target="_blank"
data-test="popup_message"
rel="noopener noreferrer"
>
{{ $t('viewOnEtherscan') }} {{ $t('viewOnEtherscan') }}
</a> </a>
<n-link v-else-if="notice.routerLink" v-bind="notice.routerLink.params" @onClick="$forceUpdate()"> <n-link v-else-if="notice.routerLink" v-bind="notice.routerLink.params" @onClick="$forceUpdate()">

View File

@ -27,6 +27,7 @@
data-test="txhash_text" data-test="txhash_text"
:href="txExplorerUrl(tx.txHash)" :href="txExplorerUrl(tx.txHash)"
target="_blank" target="_blank"
rel="noopener noreferrer"
> >
{{ tx.txHash }} {{ tx.txHash }}
</a> </a>

View File

@ -123,7 +123,7 @@
<div class="column is-full-small"> <div class="column is-full-small">
<strong>{{ $t('proposalAddress') }}</strong> <strong>{{ $t('proposalAddress') }}</strong>
<div class="value"> <div class="value">
<a :href="contractUrl" class="address" target="_blank"> <a :href="contractUrl" class="address" target="_blank" rel="noopener noreferrer">
{{ data.target }} {{ data.target }}
</a> </a>
</div> </div>

View File

@ -12,7 +12,9 @@
</b-field> </b-field>
<div class="label-with-value"> <div class="label-with-value">
{{ $t('currentDelegate') }}: {{ $t('currentDelegate') }}:
<a target="_blank" :href="addressExplorerUrl(currentDelegate)">{{ delegateMsg }}</a> <a target="_blank" :href="addressExplorerUrl(currentDelegate)" rel="noopener noreferrer">{{
delegateMsg
}}</a>
</div> </div>
<div> <div>
<b-tooltip <b-tooltip

View File

@ -5,7 +5,9 @@
</div> </div>
<div class="label-with-value"> <div class="label-with-value">
{{ $t('currentDelegate') }}: {{ $t('currentDelegate') }}:
<a target="_blank" :href="addressExplorerUrl(currentDelegate)">{{ delegateMsg }}</a> <a target="_blank" :href="addressExplorerUrl(currentDelegate)" rel="noopener noreferrer">{{
delegateMsg
}}</a>
</div> </div>
<b-tooltip <b-tooltip
class="is-block" class="is-block"

View File

@ -20,6 +20,7 @@
v-show="!hasErrorNote && depositTxHash" v-show="!hasErrorNote && depositTxHash"
:href="txExplorerUrl(depositTxHash)" :href="txExplorerUrl(depositTxHash)"
target="_blank" target="_blank"
rel="noopener noreferrer"
class="button is-icon" class="button is-icon"
> >
<b-tooltip <b-tooltip
@ -392,9 +393,6 @@ export default {
this.$emit('get-key', this.getKeys) this.$emit('get-key', this.getKeys)
}, },
mounted() { mounted() {
if (this.$route.query.note) {
this.withdrawNote = this.$route.query.note
}
this.$root.$on('resetWithdraw', () => { this.$root.$on('resetWithdraw', () => {
this.withdrawAddress = '' this.withdrawAddress = ''
this.withdrawNote = '' this.withdrawNote = ''

View File

@ -452,5 +452,9 @@
"name": "Name", "name": "Name",
"fee": "Fee" "fee": "Fee"
}, },
"withdrawalQueueIsOverloaded": "Withdrawal queue is overloaded" "withdrawalQueueIsOverloaded": "Withdrawal queue is overloaded",
"trustBanner": {
"trustLess": "You are using a public IPFS gateway. Tornado Cash dApp can not use all security features of your browser. Check out {link} for alternatives",
"link": "landing page"
}
} }

View File

@ -69,6 +69,7 @@ export default {
}, },
mounted() { mounted() {
this.$preventMultitabs() this.$preventMultitabs()
window.addEventListener('focus', this.$preventMultitabs)
if (process.browser) { if (process.browser) {
window.onNuxtReady(() => { window.onNuxtReady(() => {
@ -108,6 +109,9 @@ export default {
}) })
} }
}, },
beforeDestroy() {
window.removeEventListener('focus', this.$preventMultitabs)
},
methods: { methods: {
...mapActions('settings', ['checkCurrentRpc', 'preselectRpc']), ...mapActions('settings', ['checkCurrentRpc', 'preselectRpc']),
checkRecoveryKey() { checkRecoveryKey() {

View File

@ -39,6 +39,12 @@ const providerMiddleware = async ({ store }) => {
const chainId = hexToNumber(await provider.request({ method: 'eth_chainId' })) const chainId = hexToNumber(await provider.request({ method: 'eth_chainId' }))
await checkProvider({ store, accounts, chainId, providerName }) await checkProvider({ store, accounts, chainId, providerName })
} else {
const storedNetId = window.localStorage.getItem('netId')
if (networkConfig[`netId${storedNetId}`]) {
await store.dispatch('metamask/onNetworkChanged', { netId: Number(storedNetId) })
}
} }
} catch (err) { } catch (err) {
console.error(`Provider container has error: ${err.message}`) console.error(`Provider container has error: ${err.message}`)

View File

@ -47,6 +47,15 @@ export default {
title: 'Tornado.cash', title: 'Tornado.cash',
meta: [ meta: [
{ charset: 'utf-8' }, { charset: 'utf-8' },
{
'http-equiv': 'Content-Security-Policy',
content:
"img-src 'self' data:;font-src data:;style-src 'self' 'unsafe-inline';connect-src *;script-src 'self' 'unsafe-eval' 'unsafe-inline';default-src 'self';object-src 'none';base-uri 'none';upgrade-insecure-requests;child-src blob:;worker-src blob:;"
},
{
name: 'Referer-Policy',
content: 'no-referrer'
},
{ {
name: 'viewport', name: 'viewport',
content: 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' content: 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no'

View File

@ -71,6 +71,7 @@
v-if="txDepositInfo.txHash" v-if="txDepositInfo.txHash"
:href="txExplorerUrl(txDepositInfo.txHash)" :href="txExplorerUrl(txDepositInfo.txHash)"
target="_blank" target="_blank"
rel="noopener noreferrer"
class="value" class="value"
:data-value="txDepositInfo.txHash" :data-value="txDepositInfo.txHash"
> >
@ -84,6 +85,7 @@
v-if="txDepositInfo.txHash" v-if="txDepositInfo.txHash"
:href="addressExplorerUrl(txDepositInfo.from)" :href="addressExplorerUrl(txDepositInfo.from)"
target="_blank" target="_blank"
rel="noopener noreferrer"
class="value" class="value"
> >
{{ txDepositInfo.from }} {{ txDepositInfo.from }}
@ -158,6 +160,7 @@
v-if="txWithdrawalInfo.txHash" v-if="txWithdrawalInfo.txHash"
:href="txExplorerUrl(txWithdrawalInfo.txHash)" :href="txExplorerUrl(txWithdrawalInfo.txHash)"
target="_blank" target="_blank"
rel="noopener noreferrer"
class="value" class="value"
:data-value="txWithdrawalInfo.txHash" :data-value="txWithdrawalInfo.txHash"
> >
@ -171,6 +174,7 @@
v-if="txWithdrawalInfo.to" v-if="txWithdrawalInfo.to"
:href="addressExplorerUrl(txWithdrawalInfo.to)" :href="addressExplorerUrl(txWithdrawalInfo.to)"
target="_blank" target="_blank"
rel="noopener noreferrer"
class="value" class="value"
> >
{{ txWithdrawalInfo.to }} {{ txWithdrawalInfo.to }}

View File

@ -13,6 +13,22 @@
<i18n path="binanceInternalTxsNotification" /> <i18n path="binanceInternalTxsNotification" />
</b-notification> </b-notification>
<b-notification
:active="isActiveNotification.third"
class="main-notification"
type="is-warning"
icon-pack="icon"
has-icon
:aria-close-label="$t('closeNotification')"
@close="disableNotification({ key: 'third' })"
>
<i18n path="trustBanner.trustLess">
<template v-slot:link>
<a href="https://tornado.cash/">{{ $t('trustBanner.link') }}</a>
</template>
</i18n>
</b-notification>
<b-notification <b-notification
:active="isActiveNotification.first" :active="isActiveNotification.first"
class="main-notification" class="main-notification"
@ -27,7 +43,7 @@
<a <a
href="https://twitter.com/TornadoCash/status/1204745639759884289" href="https://twitter.com/TornadoCash/status/1204745639759884289"
target="_blank" target="_blank"
rel="noreferrer" rel="noopener noreferrer"
>{{ $t('indexNotificationLinkText') }}</a >{{ $t('indexNotificationLinkText') }}</a
> >
</template> </template>
@ -82,21 +98,20 @@ export default {
}, },
created() { created() {
this.$store.dispatch('application/setNativeCurrency', { netId: this.netId }) this.$store.dispatch('application/setNativeCurrency', { netId: this.netId })
}, this.checkIsTrustedUrl()
mounted() {
if (this.$route.query.note) {
this.activeTab = 1
}
}, },
methods: { methods: {
...mapActions('settings', ['disableNotification']), ...mapActions('settings', ['disableNotification']),
checkIsTrustedUrl() {
const isIpfs = this.$isLoadedFromIPFS()
if (!isIpfs) {
this.disableNotification({ key: 'third' })
}
},
onGetKey(fn) { onGetKey(fn) {
this.getKeys = fn this.getKeys = fn
}, },
async tabChanged(tabIndex) { async tabChanged(tabIndex) {
if (!this.$route.query.note) {
this.$root.$emit('resetWithdraw')
}
if (tabIndex === 1) { if (tabIndex === 1) {
this.$store.dispatch('relayer/pickRandomRelayer', { type: 'tornado' }) this.$store.dispatch('relayer/pickRandomRelayer', { type: 'tornado' })

View File

@ -3,20 +3,13 @@ export default ({ store, isHMR, app }, inject) => {
inject('isLoadedFromIPFS', main) inject('isLoadedFromIPFS', main)
} }
function main() { function main() {
const domainWhiteList = [ const whiteListedDomains = ['localhost:3000', 'tornadocash.eth.link', 'tornadocash.eth.limo']
'tornado.cash',
'localhost:3000',
'stage.tornado.cash',
'tornadocash.eth',
'tornadocash.eth.link',
'tornadocash.eth.limo',
'app.tornado.cash',
'donotshare.tornado.cash'
]
if (window.location.host.includes('tornadocash.netlify.app')) { const NETLIFY_REGEXP = /https:\/\/deploy-preview-(\d+)--tornadocash\.netlify\.app/
if (NETLIFY_REGEXP.test(window.location.host)) {
return false return false
} else if (!domainWhiteList.includes(window.location.host)) { } else if (!whiteListedDomains.includes(window.location.host)) {
console.warn('The page has been loaded from ipfs.io. LocalStorage is disabled') console.warn('The page has been loaded from ipfs.io. LocalStorage is disabled')
return true return true
} }

View File

@ -21,11 +21,17 @@ export default ({ store, isHMR }) => {
return return
} }
const paths = ['metamask.netId', 'application.selectedStatistic', 'application.selectedInstance']
if (!store.$isLoadedFromIPFS()) { if (!store.$isLoadedFromIPFS()) {
paths.push('txHashKeeper', 'settings', 'account', 'relayer.jobs', 'encryptedNote.ui') const paths = [
} 'metamask.netId',
'application.selectedStatistic',
'application.selectedInstance',
'txHashKeeper',
'settings',
'account',
'relayer.jobs',
'encryptedNote.ui'
]
migrate() migrate()
@ -34,3 +40,4 @@ export default ({ store, isHMR }) => {
paths paths
})(store) })(store)
} }
}

View File

@ -82,6 +82,8 @@ const mutations = {
}, },
SET_NET_ID(state, netId) { SET_NET_ID(state, netId) {
netId = parseInt(netId, 10) netId = parseInt(netId, 10)
window.localStorage.setItem('netId', netId)
state.netId = netId state.netId = netId
}, },
SET_RECONNECTING(state, bool) { SET_RECONNECTING(state, bool) {

View File

@ -337,13 +337,15 @@ export const actions = {
async getCustomRelayerData({ rootState, state, getters, rootGetters, dispatch }, { url, name }) { async getCustomRelayerData({ rootState, state, getters, rootGetters, dispatch }, { url, name }) {
const provider = getters.ethProvider.eth const provider = getters.ethProvider.eth
if (!url.startsWith('https:') && !url.startsWith('http:')) { const PROTOCOL_REGEXP = /^(http(s?))/
if (url.includes('.onion')) { if (!PROTOCOL_REGEXP.test(url)) {
if (url.endsWith('.onion')) {
url = `http://${url}` url = `http://${url}`
} else { } else {
url = `https://${url}` url = `https://${url}`
} }
} }
const urlParser = new URL(url) const urlParser = new URL(url)
urlParser.href = url urlParser.href = url
let ensName = name let ensName = name

View File

@ -20,7 +20,8 @@ export const state = () => {
...rpcData, ...rpcData,
isActiveNotification: { isActiveNotification: {
first: true, first: true,
second: true second: true,
third: true
} }
} }
} }