chore: use monorepo organization
This commit is contained in:
parent
deaf7d6ecc
commit
a687827f7e
1099 changed files with 8184 additions and 11535 deletions
256
packages/server/lib/new-settings-loader.js
Normal file
256
packages/server/lib/new-settings-loader.js
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
const crypto = require('crypto')
|
||||
|
||||
const _ = require('lodash/fp')
|
||||
const db = require('./db')
|
||||
const { getOperatorId } = require('./operator')
|
||||
const { getTermsConditions, setTermsConditions } = require('./new-config-manager')
|
||||
|
||||
const NEW_SETTINGS_LOADER_SCHEMA_VERSION = 2
|
||||
const PASSWORD_FILLED = 'PASSWORD_FILLED'
|
||||
const SECRET_FIELDS = [
|
||||
'bitgo.BTCWalletPassphrase',
|
||||
'bitgo.LTCWalletPassphrase',
|
||||
'bitgo.ZECWalletPassphrase',
|
||||
'bitgo.BCHWalletPassphrase',
|
||||
'bitgo.DASHWalletPassphrase',
|
||||
'bitstamp.secret',
|
||||
'itbit.clientSecret',
|
||||
'kraken.privateKey',
|
||||
'binanceus.privateKey',
|
||||
'cex.privateKey',
|
||||
'binance.privateKey',
|
||||
'twilio.authToken',
|
||||
'telnyx.apiKey',
|
||||
'vonage.apiSecret',
|
||||
'inforu.apiKey',
|
||||
'galoy.walletId',
|
||||
'galoy.apiSecret',
|
||||
'bitfinex.secret',
|
||||
'sumsub.apiToken',
|
||||
'sumsub.privateKey'
|
||||
]
|
||||
|
||||
/*
|
||||
* JSON.stringify isn't necessarily deterministic so this function may compute
|
||||
* different hashes for the same object.
|
||||
*/
|
||||
const md5hash = text =>
|
||||
crypto
|
||||
.createHash('MD5')
|
||||
.update(text)
|
||||
.digest('hex')
|
||||
|
||||
const addTermsHash = configs => {
|
||||
const terms = _.omit(['hash'], getTermsConditions(configs))
|
||||
return !terms?.text ?
|
||||
configs :
|
||||
_.flow(
|
||||
_.get('text'),
|
||||
md5hash,
|
||||
hash => _.set('hash', hash, terms),
|
||||
setTermsConditions,
|
||||
_.assign(configs),
|
||||
)(terms)
|
||||
}
|
||||
|
||||
const notifyReload = (dbOrTx, operatorId) =>
|
||||
dbOrTx.none(
|
||||
'NOTIFY $1:name, $2',
|
||||
['reload', JSON.stringify({ operatorId })]
|
||||
)
|
||||
|
||||
function saveAccounts (accounts) {
|
||||
if (!accounts) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
const accountsSql = `UPDATE user_config SET data = $1, valid = TRUE, schema_version = $2 WHERE type = 'accounts';
|
||||
INSERT INTO user_config (type, data, valid, schema_version)
|
||||
SELECT 'accounts', $1, TRUE, $2 WHERE 'accounts' NOT IN (SELECT type FROM user_config)`
|
||||
|
||||
return Promise.all([loadAccounts(), getOperatorId('middleware')])
|
||||
.then(([currentAccounts, operatorId]) => {
|
||||
const newAccounts = _.merge(currentAccounts, accounts)
|
||||
|
||||
// Only allow one wallet scoring active at a time
|
||||
if (accounts.elliptic?.enabled && newAccounts.scorechain) {
|
||||
newAccounts.scorechain.enabled = false
|
||||
}
|
||||
|
||||
if (accounts.scorechain?.enabled && newAccounts.elliptic) {
|
||||
newAccounts.elliptic.enabled = false
|
||||
}
|
||||
|
||||
return db.tx(t =>
|
||||
t.none(accountsSql, [{ accounts: newAccounts }, NEW_SETTINGS_LOADER_SCHEMA_VERSION])
|
||||
.then(() => notifyReload(t, operatorId))
|
||||
).catch(console.error)
|
||||
})
|
||||
}
|
||||
|
||||
function loadAccounts (schemaVersion) {
|
||||
const sql = `SELECT data
|
||||
FROM user_config
|
||||
WHERE type = $1
|
||||
AND schema_version = $2
|
||||
AND valid
|
||||
ORDER BY id DESC
|
||||
LIMIT 1`
|
||||
|
||||
return db.oneOrNone(sql, ['accounts', schemaVersion || NEW_SETTINGS_LOADER_SCHEMA_VERSION])
|
||||
.then(_.compose(_.defaultTo({}), _.get('data.accounts')))
|
||||
}
|
||||
|
||||
function hideSecretFields (accounts) {
|
||||
return _.flow(
|
||||
_.filter(path => !_.isEmpty(_.get(path, accounts))),
|
||||
_.reduce(
|
||||
(accounts, path) => _.assoc(path, PASSWORD_FILLED, accounts),
|
||||
accounts
|
||||
)
|
||||
)(SECRET_FIELDS)
|
||||
}
|
||||
|
||||
function showAccounts (schemaVersion) {
|
||||
return loadAccounts(schemaVersion)
|
||||
.then(hideSecretFields)
|
||||
}
|
||||
|
||||
const insertConfigRow = (dbOrTx, data) =>
|
||||
dbOrTx.none(
|
||||
"INSERT INTO user_config (type, data, valid, schema_version) VALUES ('config', $1, TRUE, $2)",
|
||||
[data, NEW_SETTINGS_LOADER_SCHEMA_VERSION]
|
||||
)
|
||||
|
||||
function saveConfig (config) {
|
||||
return Promise.all([loadLatestConfigOrNone(), getOperatorId('middleware')])
|
||||
.then(([currentConfig, operatorId]) => {
|
||||
const newConfig = addTermsHash(_.assign(currentConfig, config))
|
||||
return db.tx(t =>
|
||||
insertConfigRow(t, { config: newConfig })
|
||||
.then(() => notifyReload(t, operatorId))
|
||||
).catch(console.error)
|
||||
})
|
||||
}
|
||||
|
||||
function removeFromConfig (fields) {
|
||||
return Promise.all([loadLatestConfigOrNone(), getOperatorId('middleware')])
|
||||
.then(([currentConfig, operatorId]) => {
|
||||
const newConfig = _.omit(fields, currentConfig)
|
||||
return db.tx(t =>
|
||||
insertConfigRow(t, { config: newConfig })
|
||||
.then(() => notifyReload(t, operatorId))
|
||||
).catch(console.error)
|
||||
})
|
||||
}
|
||||
|
||||
function migrationSaveConfig (config) {
|
||||
return loadLatestConfigOrNone()
|
||||
.then(currentConfig => {
|
||||
const newConfig = _.assign(currentConfig, config)
|
||||
return insertConfigRow(db, { config: newConfig })
|
||||
.catch(console.error)
|
||||
})
|
||||
}
|
||||
|
||||
function loadLatest (schemaVersion) {
|
||||
return Promise.all([loadLatestConfigOrNoneReturningVersion(schemaVersion), loadAccounts(schemaVersion)])
|
||||
.then(([configObj, accounts]) => ({
|
||||
config: configObj.config,
|
||||
accounts,
|
||||
version: configObj.version
|
||||
}))
|
||||
}
|
||||
|
||||
function loadLatestConfig () {
|
||||
const sql = `SELECT data
|
||||
FROM user_config
|
||||
WHERE type = 'config'
|
||||
AND schema_version = $1
|
||||
AND valid
|
||||
ORDER BY id DESC
|
||||
LIMIT 1`
|
||||
|
||||
return db.oneOrNone(sql, [NEW_SETTINGS_LOADER_SCHEMA_VERSION])
|
||||
.then(row => row ? row.data.config : {})
|
||||
.catch(err => {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
function loadLatestConfigOrNoneReturningVersion (schemaVersion) {
|
||||
const sql = `SELECT data, id
|
||||
FROM user_config
|
||||
WHERE type = 'config'
|
||||
AND schema_version = $1
|
||||
AND valid
|
||||
ORDER BY id DESC
|
||||
LIMIT 1`
|
||||
|
||||
return db.oneOrNone(sql, [schemaVersion || NEW_SETTINGS_LOADER_SCHEMA_VERSION])
|
||||
.then(row => row ? { config: row.data.config, version: row.id } : {})
|
||||
}
|
||||
|
||||
function loadLatestConfigOrNone (schemaVersion) {
|
||||
const sql = `SELECT data
|
||||
FROM user_config
|
||||
WHERE type = 'config'
|
||||
AND schema_version = $1
|
||||
ORDER BY id DESC
|
||||
LIMIT 1`
|
||||
|
||||
return db.oneOrNone(sql, [schemaVersion || NEW_SETTINGS_LOADER_SCHEMA_VERSION])
|
||||
.then(row => row ? row.data.config : {})
|
||||
}
|
||||
|
||||
function loadConfig (versionId) {
|
||||
const sql = `SELECT data
|
||||
FROM user_config
|
||||
WHERE id = $1
|
||||
AND type = 'config'
|
||||
AND schema_version = $2
|
||||
AND valid`
|
||||
|
||||
return db.one(sql, [versionId, NEW_SETTINGS_LOADER_SCHEMA_VERSION])
|
||||
.then(row => row.data.config)
|
||||
.catch(err => {
|
||||
if (err.name === 'QueryResultError') {
|
||||
throw new Error('No such config version: ' + versionId)
|
||||
}
|
||||
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
function load (versionId) {
|
||||
if (!versionId) Promise.reject('versionId is required')
|
||||
|
||||
return Promise.all([loadConfig(versionId), loadAccounts()])
|
||||
.then(([config, accounts]) => ({
|
||||
config,
|
||||
accounts
|
||||
}))
|
||||
}
|
||||
|
||||
const fetchCurrentConfigVersion = () => {
|
||||
const sql = `SELECT id FROM user_config
|
||||
WHERE type = 'config'
|
||||
AND valid
|
||||
ORDER BY id DESC
|
||||
LIMIT 1`
|
||||
return db.one(sql).then(row => row.id)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
saveConfig,
|
||||
migrationSaveConfig,
|
||||
saveAccounts,
|
||||
loadAccounts,
|
||||
showAccounts,
|
||||
loadLatest,
|
||||
loadLatestConfig,
|
||||
loadLatestConfigOrNone,
|
||||
load,
|
||||
removeFromConfig,
|
||||
fetchCurrentConfigVersion,
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue