This commit is contained in:
Danil Kovtonyuk 2022-04-22 13:05:56 +10:00
commit 44f31f8b9f
No known key found for this signature in database
GPG key ID: E72A919BF08C3746
402 changed files with 47865 additions and 0 deletions

7
plugins/README.md Normal file
View file

@ -0,0 +1,7 @@
# PLUGINS
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains Javascript plugins that you want to run before mounting the root Vue.js application.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins).

4
plugins/clipboard.js Normal file
View file

@ -0,0 +1,4 @@
import Vue from 'vue'
import VueClipboard from 'vue-clipboard2'
Vue.use(VueClipboard)

25
plugins/detectIPFS.js Normal file
View file

@ -0,0 +1,25 @@
/* eslint-disable no-console */
export default ({ store, isHMR, app }, inject) => {
inject('isLoadedFromIPFS', main)
}
function main() {
const domainWhiteList = [
'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')) {
return false
} else if (!domainWhiteList.includes(window.location.host)) {
console.warn('The page has been loaded from ipfs.io. LocalStorage is disabled')
return true
}
return false
}

173
plugins/i18n.js Normal file
View file

@ -0,0 +1,173 @@
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import messages from '../langs/index'
import { LOCALES_NAMES } from '@/constants'
Vue.use(VueI18n)
let lang = 'en'
if (process.browser) {
const locale = localStorage.getItem('lang') || navigator.language.substr(0, 2).toLowerCase()
lang = !messages[locale] ? 'en' : locale
}
const dateTimeFormats = {
en: {
long: {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long',
hour: 'numeric',
minute: 'numeric',
hour12: true
}
},
es: {
long: {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}
},
fr: {
long: {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}
},
ru: {
long: {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}
},
tr: {
long: {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}
},
uk: {
long: {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}
},
zh: {
long: {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long',
hour: 'numeric',
minute: 'numeric',
hour12: true
}
}
}
const numberFormats = {
en: {
compact: {
notation: 'compact'
}
},
es: {
compact: {
notation: 'compact'
}
},
fr: {
compact: {
notation: 'compact'
}
},
ru: {
compact: {
notation: 'compact'
}
},
tr: {
compact: {
notation: 'compact'
}
},
uk: {
compact: {
notation: 'compact'
}
},
zh: {
compact: {
notation: 'compact'
}
}
}
function slavicPluralization(choice, choicesLength) {
/**
* @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
* @param choicesLength {number} an overall amount of available choices
* @returns a final choice index to select plural word by
*/
if (choice === 0) {
return 0
}
const teen = choice > 10 && choice < 20
const endsWithOne = choice % 10 === 1
if (choicesLength < 4) {
return !teen && endsWithOne ? 1 : 2
}
if (!teen && endsWithOne) {
return 1
}
if (!teen && choice % 10 >= 2 && choice % 10 <= 4) {
return 2
}
return choicesLength < 4 ? 2 : 3
}
const pluralizationRules = {
ru: slavicPluralization,
uk: slavicPluralization
}
// Create VueI18n instance with options
export default ({ app, route, store }) => {
app.i18n = new VueI18n({
locale: lang,
fallbackLocale: 'en',
messages,
silentFallbackWarn: true,
dateTimeFormats,
numberFormats,
pluralizationRules
})
if (lang === 'zh') {
lang += '-cn'
}
app.$moment.locale(lang)
app.$numbro.setLanguage(LOCALES_NAMES[lang])
}

283
plugins/idb.js Normal file
View file

@ -0,0 +1,283 @@
import { openDB, deleteDB } from 'idb'
import networkConfig from '@/networkConfig'
import { INDEX_DB_ERROR, NETWORKS } from '@/constants'
// TODO method for migration, remove indexed
class IndexedDB {
constructor({ stores, dbName }) {
this.dbExists = false
this.isBlocked = false
this.options = {
upgrade(db) {
Object.values(db.objectStoreNames).forEach((value) => {
db.deleteObjectStore(value)
})
stores.forEach(({ name, keyPath, indexes }) => {
const store = db.createObjectStore(name, {
keyPath,
autoIncrement: true
})
if (Array.isArray(indexes)) {
indexes.forEach(({ name, unique = false }) => {
store.createIndex(name, name, { unique })
})
}
})
}
}
this.dbName = dbName
}
async initDB() {
try {
if (this.dbExists) {
return
}
this.db = await openDB(this.dbName, 31, this.options) // version (optional): Schema version, or undefined to open the current version.
this.onEventHandler()
this.dbExists = true
} catch (err) {
// need for private mode firefox browser
if (err.message.includes(INDEX_DB_ERROR)) {
this.isBlocked = true
return
}
if (err.message.includes('less than the existing version')) {
await this._removeExist()
}
console.error(`Method initDB has error: ${err.message}`)
}
}
onEventHandler() {
this.db.addEventListener('onupgradeneeded', async () => {
await this._removeExist()
})
}
async _removeExist() {
await deleteDB(this.dbName)
this.dbExists = false
await this.initDB()
}
async getFromIndex(params) {
if (this.isBlocked) {
return
}
try {
return await this._getFromIndex(params)
} catch (err) {
return undefined
}
}
async _getFromIndex({ storeName, indexName, key }) {
try {
const value = await this.db.getFromIndex(storeName, indexName, key)
return value
} catch (err) {
throw new Error(`Method getFromIndex has error: ${err.message}`)
}
}
async getAllFromIndex(params) {
if (this.isBlocked) {
return []
}
try {
return await this._getAllFromIndex(params)
} catch (err) {
return []
}
}
async _getAllFromIndex({ storeName, indexName, key, count }) {
try {
const value = await this.db.getAllFromIndex(storeName, indexName, key, count)
return value
} catch (err) {
throw new Error(`Method getAllFromIndex has error: ${err.message}`)
}
}
async getItem({ storeName, key }) {
try {
const store = this.db.transaction(storeName).objectStore(storeName)
const value = await store.get(key)
return value
} catch (err) {
throw new Error(`Method getItem has error: ${err.message}`)
}
}
async addItem({ storeName, data, key = '' }) {
try {
const tx = this.db.transaction(storeName, 'readwrite')
const isExist = await tx.objectStore(storeName).get(key)
if (!isExist) {
await tx.objectStore(storeName).add(data)
}
} catch (err) {
throw new Error(`Method addItem has error: ${err.message}`)
}
}
async putItem({ storeName, data }) {
try {
const tx = this.db.transaction(storeName, 'readwrite')
await tx.objectStore(storeName).put(data)
} catch (err) {
throw new Error(`Method putItem has error: ${err.message}`)
}
}
async getAll({ storeName }) {
try {
const tx = this.db.transaction(storeName, 'readonly')
const store = tx.objectStore(storeName)
const data = await store.getAll()
return data
} catch (err) {
throw new Error(`Method getAll has error: ${err.message}`)
}
}
async clearStore({ storeName, mode = 'readwrite' }) {
try {
const tx = this.db.transaction(storeName, mode)
await tx.objectStore(storeName).clear()
} catch (err) {
throw new Error(`Method clearStore has error: ${err.message}`)
}
}
async createTransactions({ storeName, data, mode = 'readwrite' }) {
try {
const tx = this.db.transaction(storeName, mode)
await tx.objectStore(storeName).add(data)
await tx.done
} catch (err) {
throw new Error(`Method createTransactions has error: ${err.message}`)
}
}
createMultipleTransactions({ storeName, data, index, mode = 'readwrite' }) {
try {
const tx = this.db.transaction(storeName, mode)
data.map((item) => {
if (item) {
tx.store.put({ ...item, ...index })
}
})
} catch (err) {
throw new Error(`Method createMultipleTransactions has error: ${err.message}`)
}
}
}
export default async (ctx, inject) => {
const DEPOSIT_INDEXES = [
{ name: 'instance', unique: false },
{ name: 'transactionHash', unique: false },
{ name: 'commitment', unique: true }
]
const WITHDRAWAL_INDEXES = [
{ name: 'instance', unique: false },
{ name: 'nullifierHash', unique: true } // keys on which the index is created
]
const LAST_EVENT_INDEXES = [{ name: 'name', unique: false }]
// TODO: generate from config
const defaultState = [
{
name: 'encrypted_events',
keyPath: 'transactionHash'
},
{
name: 'withdrawals',
keyPath: 'transactionHash',
indexes: WITHDRAWAL_INDEXES
},
{
name: 'lastEvents',
keyPath: 'name',
indexes: LAST_EVENT_INDEXES
}
]
const stores = [
{
name: 'register_events',
keyPath: 'ensName'
}
]
NETWORKS.forEach((netId) => {
defaultState.map((item) => {
stores.push({
...item,
name: `${item.name}_${netId}`
})
})
})
Object.keys(networkConfig).forEach((key) => {
const { tokens, nativeCurrency } = networkConfig[key]
const netId = key.replace('netId', '')
Object.keys(tokens).forEach((token) => {
Object.keys(tokens[token].instanceAddress).forEach((amount) => {
if (nativeCurrency === token) {
// ToDo make good)
stores.push({
name: `stringify_bloom_${token}_${amount}_${netId}`,
keyPath: 'hashBloom'
})
}
stores.push({
name: `deposits_${token}_${amount}_${netId}`,
keyPath: 'leafIndex', // the key by which it refers to the object must be in all instances of the storage
indexes: DEPOSIT_INDEXES
})
stores.push({
name: `stringify_tree_${token}_${amount}_${netId}`,
keyPath: 'hashTree'
})
})
})
})
const options = {
stores,
dbName: 'tornado_cash'
}
const instance = new IndexedDB(options)
await instance.initDB()
ctx.$indexedDB = instance
inject('indexedDB', instance)
}

17
plugins/ipfs.js Normal file
View file

@ -0,0 +1,17 @@
/* eslint-disable camelcase, no-undef */
export default (context, inject) => {
const ipfsPathRegExp = /^(\/(?:ipfs|ipns)\/[^/]+)/
const ipfsPathPrefix = (window.location.pathname.match(ipfsPathRegExp) || [])[1] || ''
console.log('plugin __webpack_public_path__', __webpack_public_path__)
if (ipfsPathPrefix) {
__webpack_public_path__ = ipfsPathPrefix + '/_nuxt/'
if (typeof window !== 'undefined') {
context.app.router.history.base = ipfsPathPrefix || window.location.host
}
}
console.log('plugin __webpack_public_path__', __webpack_public_path__)
}

36
plugins/localStorage.js Normal file
View file

@ -0,0 +1,36 @@
/* eslint-disable no-console */
// ~/plugins/localStorage.js
import createPersistedState from 'vuex-persistedstate'
import { isStorageAvailable } from '@/utils'
const { OLD_STORE_NAME, STORE_NAME = 'tornadoClassicV2' } = process.env
function migrate() {
if (isStorageAvailable('localStorage') && OLD_STORE_NAME !== STORE_NAME) {
const oldStore = localStorage[OLD_STORE_NAME]
if (oldStore) {
localStorage.setItem(STORE_NAME, oldStore)
localStorage.removeItem(OLD_STORE_NAME)
}
}
}
export default ({ store, isHMR }) => {
if (isHMR) {
return
}
const paths = ['metamask.netId', 'application.selectedStatistic', 'application.selectedInstance']
if (!store.$isLoadedFromIPFS()) {
paths.push('txHashKeeper', 'settings', 'account', 'relayer.jobs', 'encryptedNote.ui')
}
migrate()
createPersistedState({
key: STORE_NAME,
paths
})(store)
}

View file

@ -0,0 +1,5 @@
import ru from './ru'
import uk from './uk'
import zh from './zh'
export const locales = [ru, uk, zh]

View file

@ -0,0 +1,53 @@
module.exports = {
languageTag: 'ru-RU',
delimiters: {
thousands: ' ',
decimal: ','
},
abbreviations: {
thousand: 'k',
million: 'm',
billion: 'b',
trillion: 't'
},
ordinal() {
// not ideal, but since in Russian it can taken on
// different forms (masculine, feminine, neuter)
// this is all we can do
return '.'
},
currency: {
symbol: 'руб.',
position: 'postfix',
code: 'RUB'
},
currencyFormat: {
thousandSeparated: true,
totalLength: 4,
spaceSeparated: true,
average: true
},
formats: {
fourDigits: {
totalLength: 4,
spaceSeparated: true,
average: true
},
fullWithTwoDecimals: {
output: 'currency',
mantissa: 2,
spaceSeparated: true,
thousandSeparated: true
},
fullWithTwoDecimalsNoCurrency: {
mantissa: 2,
thousandSeparated: true
},
fullWithNoDecimals: {
output: 'currency',
spaceSeparated: true,
thousandSeparated: true,
mantissa: 0
}
}
}

View file

@ -0,0 +1,53 @@
module.exports = {
languageTag: 'uk-UA',
delimiters: {
thousands: ' ',
decimal: ','
},
abbreviations: {
thousand: 'k',
million: 'm',
billion: 'b',
trillion: 't'
},
ordinal: () => {
// not ideal, but since in Ukrainian it can taken on
// different forms (masculine, feminine, neuter)
// this is all we can do
return ''
},
currency: {
symbol: '\u20B4',
position: 'postfix',
code: 'UAH'
},
currencyFormat: {
thousandSeparated: true,
totalLength: 4,
spaceSeparated: true,
average: true
},
formats: {
fourDigits: {
totalLength: 4,
spaceSeparated: true,
average: true
},
fullWithTwoDecimals: {
output: 'currency',
mantissa: 2,
spaceSeparated: true,
thousandSeparated: true
},
fullWithTwoDecimalsNoCurrency: {
mantissa: 2,
thousandSeparated: true
},
fullWithNoDecimals: {
output: 'currency',
spaceSeparated: true,
thousandSeparated: true,
mantissa: 0
}
}
}

View file

@ -0,0 +1,47 @@
module.exports = {
languageTag: 'zh-CN',
delimiters: {
thousands: ',',
decimal: '.'
},
abbreviations: {
thousand: '千',
million: '百万',
billion: '十亿',
trillion: '兆'
},
ordinal() {
return '.'
},
currency: {
symbol: '¥',
position: 'prefix',
code: 'CNY'
},
currencyFormat: {
thousandSeparated: true,
totalLength: 4,
spaceSeparated: true,
average: true
},
formats: {
fourDigits: {
totalLength: 4,
spaceSeparated: true,
average: true
},
fullWithTwoDecimals: {
thousandSeparated: true,
mantissa: 2
},
fullWithTwoDecimalsNoCurrency: {
mantissa: 2,
thousandSeparated: true
},
fullWithNoDecimals: {
output: 'currency',
thousandSeparated: true,
mantissa: 0
}
}
}

10
plugins/numbro/numbro.js Normal file
View file

@ -0,0 +1,10 @@
import numbro from 'numbro'
import { locales } from './languages'
export default (ctx, inject) => {
locales.forEach((lang) => {
numbro.registerLanguage(lang)
})
ctx.$numbro = numbro
inject('numbro', numbro)
}

View file

@ -0,0 +1,36 @@
/* eslint-disable no-console */
export default ({ store, isHMR, app }, inject) => {
inject('preventMultitabs', main)
}
function main(store) {
const id = Date.now()
window.id = id
window.localStorage.setItem('firstTab', id)
const onLocalStorageEvent = function(e) {
// the second tab will write its id to this key. The first one will notice it
if (e.key === 'firstTab') {
const newID = Date.now()
console.log('Another tab detected. Setting the new page id', newID)
setTimeout(() => {
window.localStorage.secondTab = newID // this is going to be a message for the second tab
}, 200)
}
// the second tab proccesses the message
if (e.key === 'secondTab' && window.id.toString() === window.localStorage.firstTab) {
console.log('There is another tab that already opened. We will close this one')
window.multipleTabsDetected = true
window.onbeforeunload = null
window.alert(
'Multiple tabs opened. Your page will be closed. Please only use single instance of https://tornado.cash'
)
window.location = 'https://twitter.com/tornadocash'
}
}
// this event will only trigger when a window other than itself makes changes to local storage.
setTimeout(() => {
window.addEventListener('storage', onLocalStorageEvent, false)
}, 100)
}

76
plugins/sessionStorage.js Normal file
View file

@ -0,0 +1,76 @@
import { soliditySha3 } from 'web3-utils'
let isSessionStorageEnabled = null
try {
window.sessionStorage.setItem('test', 'test')
window.sessionStorage.removeItem('test')
isSessionStorageEnabled = true
} catch (e) {
isSessionStorageEnabled = false
}
const setItem = (key, value) => {
if (isSessionStorageEnabled) {
window.sessionStorage.setItem(
soliditySha3(key),
JSON.stringify({
data: value,
timeStamp: Date.now()
})
)
}
}
const getItem = (key) => {
if (isSessionStorageEnabled) {
const value = window.sessionStorage.getItem(soliditySha3(key))
try {
return JSON.parse(String(value))
} catch (err) {
return value
}
}
return undefined
}
const removeItem = (key) => {
if (isSessionStorageEnabled) {
return window.sessionStorage.removeItem(soliditySha3(key))
}
}
const clear = () => {
if (isSessionStorageEnabled) {
window.sessionStorage.clear()
}
}
const subscribe = (key, originalListener) => {
const listener = (event) => {
if (event.storageArea === window.sessionStorage && event.key === key) {
originalListener(event.newValue, event.oldValue)
}
}
window.addEventListener('storage', listener, false)
return listener
}
const unsubscribe = (listener) => {
window.removeEventListener('storage', listener, false)
}
export default (ctx, inject) => {
const sessionStorage = {
setItem,
getItem,
removeItem,
clear,
subscribe,
unsubscribe
}
ctx.$sessionStorage = sessionStorage
inject('sessionStorage', sessionStorage)
}

4
plugins/vidle.js Normal file
View file

@ -0,0 +1,4 @@
import Vue from 'vue'
import Vidle from 'v-idle'
Vue.use(Vidle)