Merge branch 'master' of github.com:shocknet/api
This commit is contained in:
commit
336e2f28fd
12 changed files with 859 additions and 135 deletions
|
|
@ -33,6 +33,7 @@
|
||||||
"cors": "^2.8.4",
|
"cors": "^2.8.4",
|
||||||
"debug": "^3.1.0",
|
"debug": "^3.1.0",
|
||||||
"dotenv": "^8.1.0",
|
"dotenv": "^8.1.0",
|
||||||
|
"eccrypto": "^1.1.6",
|
||||||
"express": "^4.14.1",
|
"express": "^4.14.1",
|
||||||
"express-session": "^1.17.1",
|
"express-session": "^1.17.1",
|
||||||
"google-proto-files": "^1.0.3",
|
"google-proto-files": "^1.0.3",
|
||||||
|
|
@ -65,12 +66,14 @@
|
||||||
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
||||||
"@types/bluebird": "^3.5.32",
|
"@types/bluebird": "^3.5.32",
|
||||||
"@types/dotenv": "^6.1.1",
|
"@types/dotenv": "^6.1.1",
|
||||||
|
"@types/eccrypto": "^1.1.2",
|
||||||
"@types/express": "^4.17.1",
|
"@types/express": "^4.17.1",
|
||||||
"@types/gun": "^0.9.2",
|
"@types/gun": "^0.9.2",
|
||||||
"@types/jest": "^24.0.18",
|
"@types/jest": "^24.0.18",
|
||||||
"@types/jsonwebtoken": "^8.3.7",
|
"@types/jsonwebtoken": "^8.3.7",
|
||||||
"@types/lodash": "^4.14.141",
|
"@types/lodash": "^4.14.141",
|
||||||
"@types/node-fetch": "^2.5.8",
|
"@types/node-fetch": "^2.5.8",
|
||||||
|
"@types/node-persist": "^3.1.1",
|
||||||
"@types/ramda": "types/npm-ramda#dist",
|
"@types/ramda": "types/npm-ramda#dist",
|
||||||
"@types/react": "16.x.x",
|
"@types/react": "16.x.x",
|
||||||
"@types/socket.io": "^2.1.11",
|
"@types/socket.io": "^2.1.11",
|
||||||
|
|
@ -105,4 +108,4 @@
|
||||||
"pre-commit": "yarn lint && yarn typecheck && yarn lint-staged"
|
"pre-commit": "yarn lint && yarn typecheck && yarn lint-staged"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ require('gun/lib/open')
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
require('gun/lib/load')
|
require('gun/lib/load')
|
||||||
const debounce = require('lodash/debounce')
|
const debounce = require('lodash/debounce')
|
||||||
|
//@ts-ignore
|
||||||
const Encryption = require('../../../utils/encryptionStore')
|
const { encryptedEmit, encryptedOn } = require('../../../utils/ECC/socket')
|
||||||
const Key = require('../contact-api/key')
|
const Key = require('../contact-api/key')
|
||||||
|
|
||||||
/** @type {import('../contact-api/SimpleGUN').ISEA} */
|
/** @type {import('../contact-api/SimpleGUN').ISEA} */
|
||||||
|
|
@ -237,18 +237,26 @@ const Config = require('../config')
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {object} EncryptedEmission
|
* @typedef {object} EncryptedEmissionLegacy
|
||||||
* @prop {string} encryptedData
|
* @prop {string} encryptedData
|
||||||
* @prop {string} encryptedKey
|
* @prop {string} encryptedKey
|
||||||
* @prop {string} iv
|
* @prop {string} iv
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} EncryptedEmission
|
||||||
|
* @prop {string} ciphertext
|
||||||
|
* @prop {string} mac
|
||||||
|
* @prop {string} iv
|
||||||
|
* @prop {string} ephemPublicKey
|
||||||
|
*/
|
||||||
|
|
||||||
// TO DO: move to common repo
|
// TO DO: move to common repo
|
||||||
/**
|
/**
|
||||||
* @typedef {object} SimpleSocket
|
* @typedef {object} SimpleSocket
|
||||||
* @prop {(eventName: string, data?: Emission|EncryptedEmission) => void} emit
|
* @prop {(eventName: string, data?: Emission|EncryptedEmissionLegacy|EncryptedEmission) => void} emit
|
||||||
* @prop {(eventName: string, handler: (data: any) => void) => void} on
|
* @prop {(eventName: string, handler: (data: any) => void) => void} on
|
||||||
* @prop {{ query: { 'x-shockwallet-device-id': string }}} handshake
|
* @prop {{ query: { 'x-shockwallet-device-id': string, encryptionId: string }}} handshake
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable init-declarations */
|
/* eslint-disable init-declarations */
|
||||||
|
|
@ -462,7 +470,7 @@ const instantiateGun = () => {
|
||||||
const _gun = /** @type {unknown} */ (new Gun({
|
const _gun = /** @type {unknown} */ (new Gun({
|
||||||
axe: false,
|
axe: false,
|
||||||
multicast: false,
|
multicast: false,
|
||||||
peers: Config.PEERS
|
peers: ['https://gun.shock.network:8765/gun']
|
||||||
}))
|
}))
|
||||||
|
|
||||||
gun = /** @type {GUNNode} */ (_gun)
|
gun = /** @type {GUNNode} */ (_gun)
|
||||||
|
|
@ -566,84 +574,16 @@ class Mediator {
|
||||||
|
|
||||||
/** @param {SimpleSocket} socket */
|
/** @param {SimpleSocket} socket */
|
||||||
encryptSocketInstance = socket => {
|
encryptSocketInstance = socket => {
|
||||||
|
const emit = encryptedEmit(socket)
|
||||||
|
const on = encryptedOn(socket)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
* @type {SimpleSocket['on']}
|
* @type {SimpleSocket['on']}
|
||||||
*/
|
*/
|
||||||
on: (eventName, cb) => {
|
on,
|
||||||
const deviceId = socket.handshake.query['x-shockwallet-device-id']
|
|
||||||
socket.on(eventName, _data => {
|
|
||||||
try {
|
|
||||||
if (Encryption.isNonEncrypted(eventName)) {
|
|
||||||
return cb(_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_data) {
|
|
||||||
return cb(_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = _data
|
|
||||||
|
|
||||||
if (!deviceId) {
|
|
||||||
const error = {
|
|
||||||
field: 'deviceId',
|
|
||||||
message: 'Please specify a device ID'
|
|
||||||
}
|
|
||||||
logger.error(JSON.stringify(error))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Encryption.isAuthorizedDevice({ deviceId })) {
|
|
||||||
const error = {
|
|
||||||
field: 'deviceId',
|
|
||||||
message: 'Please specify a device ID'
|
|
||||||
}
|
|
||||||
logger.error('Unknown Device', error)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (typeof data === 'string') {
|
|
||||||
data = JSON.parse(data)
|
|
||||||
}
|
|
||||||
const decryptedKey = Encryption.decryptKey({
|
|
||||||
deviceId,
|
|
||||||
message: data.encryptedKey
|
|
||||||
})
|
|
||||||
const decryptedMessage = Encryption.decryptMessage({
|
|
||||||
message: data.encryptedData,
|
|
||||||
key: decryptedKey,
|
|
||||||
iv: data.iv
|
|
||||||
})
|
|
||||||
const decryptedData = JSON.parse(decryptedMessage)
|
|
||||||
return cb(decryptedData)
|
|
||||||
} catch (err) {
|
|
||||||
logger.error(err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
/** @type {SimpleSocket['emit']} */
|
/** @type {SimpleSocket['emit']} */
|
||||||
emit: (eventName, data) => {
|
emit
|
||||||
try {
|
|
||||||
if (Encryption.isNonEncrypted(eventName)) {
|
|
||||||
socket.emit(eventName, data)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const deviceId = socket.handshake.query['x-shockwallet-device-id']
|
|
||||||
const authorized = Encryption.isAuthorizedDevice({ deviceId })
|
|
||||||
const encryptedMessage = authorized
|
|
||||||
? Encryption.encryptMessage({
|
|
||||||
message: data,
|
|
||||||
deviceId
|
|
||||||
})
|
|
||||||
: data
|
|
||||||
|
|
||||||
socket.emit(eventName, encryptedMessage)
|
|
||||||
} catch (err) {
|
|
||||||
logger.error(err.message)
|
|
||||||
logger.error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ const setAccessControlHeaders = (req, res) => {
|
||||||
res.header("Access-Control-Allow-Methods", "OPTIONS,POST,GET,PUT,DELETE")
|
res.header("Access-Control-Allow-Methods", "OPTIONS,POST,GET,PUT,DELETE")
|
||||||
res.header(
|
res.header(
|
||||||
"Access-Control-Allow-Headers",
|
"Access-Control-Allow-Headers",
|
||||||
"Origin, X-Requested-With, Content-Type, Accept, Authorization, public-key-for-decryption"
|
"Origin, X-Requested-With, Content-Type, Accept, Authorization, public-key-for-decryption, encryption-device-id"
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
115
src/routes.js
115
src/routes.js
|
|
@ -20,6 +20,7 @@ const getListPage = require('../utils/paginate')
|
||||||
const auth = require('../services/auth/auth')
|
const auth = require('../services/auth/auth')
|
||||||
const FS = require('../utils/fs')
|
const FS = require('../utils/fs')
|
||||||
const Encryption = require('../utils/encryptionStore')
|
const Encryption = require('../utils/encryptionStore')
|
||||||
|
const ECC = require('../utils/ECC')
|
||||||
const LightningServices = require('../utils/lightningServices')
|
const LightningServices = require('../utils/lightningServices')
|
||||||
const lndErrorManager = require('../utils/lightningServices/errors')
|
const lndErrorManager = require('../utils/lightningServices/errors')
|
||||||
const GunDB = require('../services/gunDB/Mediator')
|
const GunDB = require('../services/gunDB/Mediator')
|
||||||
|
|
@ -212,17 +213,19 @@ module.exports = async (
|
||||||
})
|
})
|
||||||
|
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
const deviceId = req.headers['x-shockwallet-device-id']
|
const legacyDeviceId = req.headers['x-shockwallet-device-id']
|
||||||
|
const deviceId = req.headers['encryption-device-id']
|
||||||
logger.debug('Decrypting route...')
|
logger.debug('Decrypting route...')
|
||||||
try {
|
try {
|
||||||
if (
|
if (
|
||||||
nonEncryptedRoutes.includes(req.path) ||
|
nonEncryptedRoutes.includes(req.path) ||
|
||||||
process.env.DISABLE_SHOCK_ENCRYPTION === 'true'
|
process.env.DISABLE_SHOCK_ENCRYPTION === 'true' ||
|
||||||
|
(deviceId && !legacyDeviceId)
|
||||||
) {
|
) {
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deviceId) {
|
if (!legacyDeviceId) {
|
||||||
const error = {
|
const error = {
|
||||||
field: 'deviceId',
|
field: 'deviceId',
|
||||||
message: 'Please specify a device ID'
|
message: 'Please specify a device ID'
|
||||||
|
|
@ -231,7 +234,7 @@ module.exports = async (
|
||||||
return res.status(401).json(error)
|
return res.status(401).json(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Encryption.isAuthorizedDevice({ deviceId })) {
|
if (!Encryption.isAuthorizedDevice({ deviceId: legacyDeviceId })) {
|
||||||
const error = {
|
const error = {
|
||||||
field: 'deviceId',
|
field: 'deviceId',
|
||||||
message: 'Please specify a device ID'
|
message: 'Please specify a device ID'
|
||||||
|
|
@ -263,7 +266,7 @@ module.exports = async (
|
||||||
reqData = req.body.data || req.body.encryptedData
|
reqData = req.body.data || req.body.encryptedData
|
||||||
}
|
}
|
||||||
const decryptedKey = Encryption.decryptKey({
|
const decryptedKey = Encryption.decryptKey({
|
||||||
deviceId,
|
deviceId: legacyDeviceId,
|
||||||
message: encryptedKey
|
message: encryptedKey
|
||||||
})
|
})
|
||||||
if (reqData) {
|
if (reqData) {
|
||||||
|
|
@ -294,6 +297,71 @@ module.exports = async (
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.use(async (req, res, next) => {
|
||||||
|
const legacyDeviceId = req.headers['x-shockwallet-device-id']
|
||||||
|
const deviceId = req.headers['encryption-device-id']
|
||||||
|
logger.info('Decrypting route...')
|
||||||
|
try {
|
||||||
|
if (
|
||||||
|
nonEncryptedRoutes.includes(req.path) ||
|
||||||
|
process.env.DISABLE_SHOCK_ENCRYPTION === 'true' ||
|
||||||
|
(legacyDeviceId && !deviceId)
|
||||||
|
) {
|
||||||
|
logger.info(
|
||||||
|
'Unprotected route detected! ' +
|
||||||
|
req.path +
|
||||||
|
' Legacy ID:' +
|
||||||
|
legacyDeviceId +
|
||||||
|
' Device ID:' +
|
||||||
|
deviceId
|
||||||
|
)
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!deviceId) {
|
||||||
|
const error = {
|
||||||
|
field: 'deviceId',
|
||||||
|
message: 'Please specify a device ID'
|
||||||
|
}
|
||||||
|
logger.error('Please specify a device ID')
|
||||||
|
return res.status(401).json(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ECC.isAuthorizedDevice({ deviceId })) {
|
||||||
|
const error = {
|
||||||
|
field: 'deviceId',
|
||||||
|
message: 'Please specify a device ID'
|
||||||
|
}
|
||||||
|
logger.error('Unknown Device')
|
||||||
|
return res.status(401).json(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.method === 'GET') {
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ECC.isEncryptedMessage(req.body)) {
|
||||||
|
logger.warn('Message not encrypted!', req.body)
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('Decrypting ECC message...')
|
||||||
|
|
||||||
|
const decryptedMessage = await ECC.decryptMessage({
|
||||||
|
deviceId,
|
||||||
|
encryptedMessage: req.body
|
||||||
|
})
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
req.body = JSON.parse(decryptedMessage)
|
||||||
|
|
||||||
|
return next()
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(err)
|
||||||
|
return res.status(401).json(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
app.use(async (req, res, next) => {
|
app.use(async (req, res, next) => {
|
||||||
logger.info(`Route: ${req.path}`)
|
logger.info(`Route: ${req.path}`)
|
||||||
if (unprotectedRoutes[req.method][req.path]) {
|
if (unprotectedRoutes[req.method][req.path]) {
|
||||||
|
|
@ -470,6 +538,43 @@ module.exports = async (
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.post('/api/encryption/exchange', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { publicKey, deviceId } = req.body
|
||||||
|
|
||||||
|
if (!publicKey) {
|
||||||
|
return res.status(400).json({
|
||||||
|
field: 'publicKey',
|
||||||
|
message: 'Please provide a valid public key'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!deviceId ||
|
||||||
|
!/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/iu.test(
|
||||||
|
deviceId
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return res.status(400).json({
|
||||||
|
field: 'deviceId',
|
||||||
|
message: 'Please provide a valid device ID'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const authorizedDevice = await ECC.authorizeDevice({
|
||||||
|
deviceId,
|
||||||
|
publicKey
|
||||||
|
})
|
||||||
|
return res.json(authorizedDevice)
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(err)
|
||||||
|
return res.status(401).json({
|
||||||
|
field: 'unknown',
|
||||||
|
message: err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
app.get('/api/lnd/wallet/status', async (req, res) => {
|
app.get('/api/lnd/wallet/status', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const walletStatus = await walletExists()
|
const walletStatus = await walletExists()
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ const server = program => {
|
||||||
const Storage = require('node-persist')
|
const Storage = require('node-persist')
|
||||||
const Path = require('path')
|
const Path = require('path')
|
||||||
const { Logger: CommonLogger } = require('shock-common')
|
const { Logger: CommonLogger } = require('shock-common')
|
||||||
|
const ECC = require('../utils/ECC')
|
||||||
const LightningServices = require('../utils/lightningServices')
|
const LightningServices = require('../utils/lightningServices')
|
||||||
const Encryption = require('../utils/encryptionStore')
|
const Encryption = require('../utils/encryptionStore')
|
||||||
const app = Express()
|
const app = Express()
|
||||||
|
|
@ -119,10 +120,16 @@ const server = program => {
|
||||||
* @param {(() => void)} next
|
* @param {(() => void)} next
|
||||||
*/
|
*/
|
||||||
const modifyResponseBody = (req, res, next) => {
|
const modifyResponseBody = (req, res, next) => {
|
||||||
const deviceId = req.headers['x-shockwallet-device-id']
|
const legacyDeviceId = req.headers['x-shockwallet-device-id']
|
||||||
|
const deviceId = req.headers['encryption-device-id']
|
||||||
const oldSend = res.send
|
const oldSend = res.send
|
||||||
|
|
||||||
if (!nonEncryptedRoutes.includes(req.path)) {
|
if (nonEncryptedRoutes.includes(req.path)) {
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (legacyDeviceId) {
|
||||||
res.send = (...args) => {
|
res.send = (...args) => {
|
||||||
if (args[0] && args[0].encryptedData && args[0].encryptionKey) {
|
if (args[0] && args[0].encryptedData && args[0].encryptionKey) {
|
||||||
logger.warn('Response loop detected!')
|
logger.warn('Response loop detected!')
|
||||||
|
|
@ -137,11 +144,13 @@ const server = program => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// arguments[0] (or `data`) contains the response body
|
// arguments[0] (or `data`) contains the response body
|
||||||
const authorized = Encryption.isAuthorizedDevice({ deviceId })
|
const authorized = Encryption.isAuthorizedDevice({
|
||||||
|
deviceId: legacyDeviceId
|
||||||
|
})
|
||||||
const encryptedMessage = authorized
|
const encryptedMessage = authorized
|
||||||
? Encryption.encryptMessage({
|
? Encryption.encryptMessage({
|
||||||
message: args[0] ? args[0] : {},
|
message: args[0] ? args[0] : {},
|
||||||
deviceId,
|
deviceId: legacyDeviceId,
|
||||||
metadata: {
|
metadata: {
|
||||||
hash
|
hash
|
||||||
}
|
}
|
||||||
|
|
@ -151,6 +160,38 @@ const server = program => {
|
||||||
oldSend.apply(res, args)
|
oldSend.apply(res, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deviceId) {
|
||||||
|
res.send = (...args) => {
|
||||||
|
if (args[0] && args[0].ciphertext && args[0].iv) {
|
||||||
|
logger.warn('Response loop detected!')
|
||||||
|
oldSend.apply(res, args)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const authorized = ECC.isAuthorizedDevice({
|
||||||
|
deviceId
|
||||||
|
})
|
||||||
|
|
||||||
|
// Using classic promises syntax to avoid
|
||||||
|
// modifying res.send's return type
|
||||||
|
if (authorized) {
|
||||||
|
ECC.encryptMessage({
|
||||||
|
deviceId,
|
||||||
|
message: args[0]
|
||||||
|
}).then(encryptedMessage => {
|
||||||
|
args[0] = JSON.stringify(encryptedMessage)
|
||||||
|
oldSend.apply(res, args)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!authorized) {
|
||||||
|
args[0] = JSON.stringify(args[0])
|
||||||
|
oldSend.apply(res, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,19 +312,27 @@ const server = program => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSessionSecret = async () => {
|
const storePersistentRandomField = async ({ fieldName, length = 16 }) => {
|
||||||
const sessionSecret = await Storage.getItem('config/sessionSecret')
|
const randomField = await Storage.getItem(fieldName)
|
||||||
|
|
||||||
if (sessionSecret) {
|
if (randomField) {
|
||||||
return sessionSecret
|
return randomField
|
||||||
}
|
}
|
||||||
|
|
||||||
const newSecret = await Encryption.generateRandomString()
|
const newValue = await Encryption.generateRandomString()
|
||||||
await Storage.setItem('config/sessionSecret', newSecret)
|
await Storage.setItem(fieldName, newValue)
|
||||||
return newSecret
|
return newValue
|
||||||
}
|
}
|
||||||
|
|
||||||
const sessionSecret = await getSessionSecret()
|
const [sessionSecret] = await Promise.all([
|
||||||
|
storePersistentRandomField({
|
||||||
|
fieldName: 'config/sessionSecret'
|
||||||
|
}),
|
||||||
|
storePersistentRandomField({
|
||||||
|
fieldName: 'encryption/hostId',
|
||||||
|
length: 8
|
||||||
|
})
|
||||||
|
])
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
session({
|
session({
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ const {
|
||||||
const { deepDecryptIfNeeded } = require('../services/gunDB/rpc')
|
const { deepDecryptIfNeeded } = require('../services/gunDB/rpc')
|
||||||
const GunEvents = require('../services/gunDB/contact-api/events')
|
const GunEvents = require('../services/gunDB/contact-api/events')
|
||||||
const SchemaManager = require('../services/schema')
|
const SchemaManager = require('../services/schema')
|
||||||
|
const { encryptedEmit, encryptedOn } = require('../utils/ECC/socket')
|
||||||
/**
|
/**
|
||||||
* @typedef {import('../services/gunDB/Mediator').SimpleSocket} SimpleSocket
|
* @typedef {import('../services/gunDB/Mediator').SimpleSocket} SimpleSocket
|
||||||
* @typedef {import('../services/gunDB/contact-api/SimpleGUN').ValidDataValue} ValidDataValue
|
* @typedef {import('../services/gunDB/contact-api/SimpleGUN').ValidDataValue} ValidDataValue
|
||||||
|
|
@ -28,7 +29,7 @@ module.exports = (
|
||||||
io
|
io
|
||||||
) => {
|
) => {
|
||||||
// This should be used for encrypting and emitting your data
|
// This should be used for encrypting and emitting your data
|
||||||
const emitEncryptedEvent = ({ eventName, data, socket }) => {
|
const encryptedEmitLegacy = ({ eventName, data, socket }) => {
|
||||||
try {
|
try {
|
||||||
if (Encryption.isNonEncrypted(eventName)) {
|
if (Encryption.isNonEncrypted(eventName)) {
|
||||||
return socket.emit(eventName, data)
|
return socket.emit(eventName, data)
|
||||||
|
|
@ -73,7 +74,7 @@ module.exports = (
|
||||||
const stream = lightning.subscribeInvoices({})
|
const stream = lightning.subscribeInvoices({})
|
||||||
stream.on('data', data => {
|
stream.on('data', data => {
|
||||||
logger.info('[SOCKET] New invoice data:', data)
|
logger.info('[SOCKET] New invoice data:', data)
|
||||||
emitEncryptedEvent({ eventName: 'invoice:new', data, socket })
|
encryptedEmitLegacy({ eventName: 'invoice:new', data, socket })
|
||||||
if (!data.settled) {
|
if (!data.settled) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -158,7 +159,7 @@ module.exports = (
|
||||||
//buddy needs to manage this
|
//buddy needs to manage this
|
||||||
} else {
|
} else {
|
||||||
//business as usual
|
//business as usual
|
||||||
emitEncryptedEvent({ eventName: 'transaction:new', data, socket })
|
encryptedEmitLegacy({ eventName: 'transaction:new', data, socket })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -258,6 +259,8 @@ module.exports = (
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const emit = encryptedEmit(socket)
|
||||||
|
|
||||||
const { $shock, publicKeyForDecryption } = socket.handshake.query
|
const { $shock, publicKeyForDecryption } = socket.handshake.query
|
||||||
|
|
||||||
const [root, path, method] = $shock.split('::')
|
const [root, path, method] = $shock.split('::')
|
||||||
|
|
@ -293,9 +296,9 @@ module.exports = (
|
||||||
publicKeyForDecryption
|
publicKeyForDecryption
|
||||||
)
|
)
|
||||||
|
|
||||||
socket.emit('$shock', decData, key)
|
emit('$shock', decData)
|
||||||
} else {
|
} else {
|
||||||
socket.emit('$shock', data, key)
|
emit('$shock', data)
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(
|
logger.error(
|
||||||
|
|
@ -335,6 +338,9 @@ module.exports = (
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const on = encryptedOn(socket)
|
||||||
|
const emit = encryptedEmit(socket)
|
||||||
|
|
||||||
const { services } = LightningServices
|
const { services } = LightningServices
|
||||||
|
|
||||||
const { service, method, args: unParsed } = socket.handshake.query
|
const { service, method, args: unParsed } = socket.handshake.query
|
||||||
|
|
@ -359,24 +365,24 @@ module.exports = (
|
||||||
})
|
})
|
||||||
})()
|
})()
|
||||||
|
|
||||||
socket.emit('data', data)
|
emit('data', data)
|
||||||
})
|
})
|
||||||
|
|
||||||
call.on('status', status => {
|
call.on('status', status => {
|
||||||
socket.emit('status', status)
|
emit('status', status)
|
||||||
})
|
})
|
||||||
|
|
||||||
call.on('end', () => {
|
call.on('end', () => {
|
||||||
socket.emit('end')
|
emit('end')
|
||||||
})
|
})
|
||||||
|
|
||||||
call.on('error', err => {
|
call.on('error', err => {
|
||||||
// 'error' is a reserved event name we can't use it
|
// 'error' is a reserved event name we can't use it
|
||||||
socket.emit('$error', err)
|
emit('$error', err)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Possibly allow streaming writes such as sendPaymentV2
|
// Possibly allow streaming writes such as sendPaymentV2
|
||||||
socket.on('write', args => {
|
on('write', args => {
|
||||||
call.write(args)
|
call.write(args)
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -467,12 +473,15 @@ module.exports = (
|
||||||
let chatsUnsub = emptyUnsub
|
let chatsUnsub = emptyUnsub
|
||||||
|
|
||||||
io.of('chats').on('connect', async socket => {
|
io.of('chats').on('connect', async socket => {
|
||||||
|
const on = encryptedOn(socket)
|
||||||
|
const emit = encryptedEmit(socket)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!isAuthenticated()) {
|
if (!isAuthenticated()) {
|
||||||
logger.info(
|
logger.info(
|
||||||
'not authenticated in gun for chats socket, will send NOT_AUTH'
|
'not authenticated in gun for chats socket, will send NOT_AUTH'
|
||||||
)
|
)
|
||||||
socket.emit(Common.Constants.ErrorCode.NOT_AUTH)
|
emit(Common.Constants.ErrorCode.NOT_AUTH)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -483,7 +492,7 @@ module.exports = (
|
||||||
|
|
||||||
if (!isAuth) {
|
if (!isAuth) {
|
||||||
logger.warn('invalid token for chats socket')
|
logger.warn('invalid token for chats socket')
|
||||||
socket.emit(Common.Constants.ErrorCode.NOT_AUTH)
|
emit(Common.Constants.ErrorCode.NOT_AUTH)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -522,30 +531,33 @@ module.exports = (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
socket.emit('$shock', processed)
|
emit('$shock', processed)
|
||||||
}
|
}
|
||||||
|
|
||||||
chatsUnsub = GunEvents.onChats(onChats)
|
chatsUnsub = GunEvents.onChats(onChats)
|
||||||
|
|
||||||
socket.on('disconnect', () => {
|
on('disconnect', () => {
|
||||||
chatsUnsub()
|
chatsUnsub()
|
||||||
chatsUnsub = emptyUnsub
|
chatsUnsub = emptyUnsub
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('Error inside chats socket connect: ' + e.message)
|
logger.error('Error inside chats socket connect: ' + e.message)
|
||||||
socket.emit('$error', e.message)
|
emit('$error', e.message)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let sentReqsUnsub = emptyUnsub
|
let sentReqsUnsub = emptyUnsub
|
||||||
|
|
||||||
io.of('sentReqs').on('connect', async socket => {
|
io.of('sentReqs').on('connect', async socket => {
|
||||||
|
const on = encryptedOn(socket)
|
||||||
|
const emit = encryptedEmit(socket)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!isAuthenticated()) {
|
if (!isAuthenticated()) {
|
||||||
logger.info(
|
logger.info(
|
||||||
'not authenticated in gun for sentReqs socket, will send NOT_AUTH'
|
'not authenticated in gun for sentReqs socket, will send NOT_AUTH'
|
||||||
)
|
)
|
||||||
socket.emit(Common.Constants.ErrorCode.NOT_AUTH)
|
emit(Common.Constants.ErrorCode.NOT_AUTH)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -556,13 +568,13 @@ module.exports = (
|
||||||
|
|
||||||
if (!isAuth) {
|
if (!isAuth) {
|
||||||
logger.warn('invalid token for sentReqs socket')
|
logger.warn('invalid token for sentReqs socket')
|
||||||
socket.emit(Common.Constants.ErrorCode.NOT_AUTH)
|
emit(Common.Constants.ErrorCode.NOT_AUTH)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sentReqsUnsub !== emptyUnsub) {
|
if (sentReqsUnsub !== emptyUnsub) {
|
||||||
logger.error(
|
logger.error(
|
||||||
'Tried to set sentReqs socket twice, this might be due to an app restart and the old socket not being recycled by socket.io in time, will disable the older subscription, which means the old socket wont work and data will be sent to this new socket instead'
|
'Tried to set sentReqs socket twice, this might be due to an app restart and the old socket not being recycled by io in time, will disable the older subscription, which means the old socket wont work and data will be sent to this new socket instead'
|
||||||
)
|
)
|
||||||
sentReqsUnsub()
|
sentReqsUnsub()
|
||||||
sentReqsUnsub = emptyUnsub
|
sentReqsUnsub = emptyUnsub
|
||||||
|
|
@ -594,30 +606,32 @@ module.exports = (
|
||||||
return stripped
|
return stripped
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
socket.emit('$shock', processed)
|
emit('$shock', processed)
|
||||||
}
|
}
|
||||||
|
|
||||||
sentReqsUnsub = GunEvents.onSimplerSentRequests(onSentReqs)
|
sentReqsUnsub = GunEvents.onSimplerSentRequests(onSentReqs)
|
||||||
|
|
||||||
socket.on('disconnect', () => {
|
on('disconnect', () => {
|
||||||
sentReqsUnsub()
|
sentReqsUnsub()
|
||||||
sentReqsUnsub = emptyUnsub
|
sentReqsUnsub = emptyUnsub
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('Error inside sentReqs socket connect: ' + e.message)
|
logger.error('Error inside sentReqs socket connect: ' + e.message)
|
||||||
socket.emit('$error', e.message)
|
emit('$error', e.message)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let receivedReqsUnsub = emptyUnsub
|
let receivedReqsUnsub = emptyUnsub
|
||||||
|
|
||||||
io.of('receivedReqs').on('connect', async socket => {
|
io.of('receivedReqs').on('connect', async socket => {
|
||||||
|
const on = encryptedOn(socket)
|
||||||
|
const emit = encryptedEmit(socket)
|
||||||
try {
|
try {
|
||||||
if (!isAuthenticated()) {
|
if (!isAuthenticated()) {
|
||||||
logger.info(
|
logger.info(
|
||||||
'not authenticated in gun for receivedReqs socket, will send NOT_AUTH'
|
'not authenticated in gun for receivedReqs socket, will send NOT_AUTH'
|
||||||
)
|
)
|
||||||
socket.emit(Common.Constants.ErrorCode.NOT_AUTH)
|
emit(Common.Constants.ErrorCode.NOT_AUTH)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -628,7 +642,7 @@ module.exports = (
|
||||||
|
|
||||||
if (!isAuth) {
|
if (!isAuth) {
|
||||||
logger.warn('invalid token for receivedReqs socket')
|
logger.warn('invalid token for receivedReqs socket')
|
||||||
socket.emit(Common.Constants.ErrorCode.NOT_AUTH)
|
emit(Common.Constants.ErrorCode.NOT_AUTH)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -657,18 +671,18 @@ module.exports = (
|
||||||
return stripped
|
return stripped
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.emit('$shock', processed)
|
emit('$shock', processed)
|
||||||
}
|
}
|
||||||
|
|
||||||
receivedReqsUnsub = GunEvents.onSimplerReceivedRequests(onReceivedReqs)
|
receivedReqsUnsub = GunEvents.onSimplerReceivedRequests(onReceivedReqs)
|
||||||
|
|
||||||
socket.on('disconnect', () => {
|
on('disconnect', () => {
|
||||||
receivedReqsUnsub()
|
receivedReqsUnsub()
|
||||||
receivedReqsUnsub = emptyUnsub
|
receivedReqsUnsub = emptyUnsub
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('Error inside receivedReqs socket connect: ' + e.message)
|
logger.error('Error inside receivedReqs socket connect: ' + e.message)
|
||||||
socket.emit('$error', e.message)
|
emit('$error', e.message)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
110
utils/ECC/crypto.js
Normal file
110
utils/ECC/crypto.js
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
const { Buffer } = require("buffer");
|
||||||
|
const FieldError = require("../fieldError")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} EncryptedMessageBuffer
|
||||||
|
* @prop {Buffer} ciphertext
|
||||||
|
* @prop {Buffer} iv
|
||||||
|
* @prop {Buffer} mac
|
||||||
|
* @prop {Buffer} ephemPublicKey
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} EncryptedMessageResponse
|
||||||
|
* @prop {string} ciphertext
|
||||||
|
* @prop {string} iv
|
||||||
|
* @prop {string} mac
|
||||||
|
* @prop {string} ephemPublicKey
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} value
|
||||||
|
*/
|
||||||
|
const convertUTF8ToBuffer = (value) => Buffer.from(value, 'utf-8');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} value
|
||||||
|
*/
|
||||||
|
const convertBase64ToBuffer = (value) => Buffer.from(value, 'base64');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Buffer} buffer
|
||||||
|
*/
|
||||||
|
const convertBufferToBase64 = (buffer) => buffer.toString("base64");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Buffer | string} key
|
||||||
|
*/
|
||||||
|
const processKey = (key) => {
|
||||||
|
if (Buffer.isBuffer(key)) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
const convertedKey = convertBase64ToBuffer(key);
|
||||||
|
return convertedKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {EncryptedMessageBuffer | EncryptedMessageResponse} encryptedMessage
|
||||||
|
* @returns {EncryptedMessageResponse}
|
||||||
|
*/
|
||||||
|
const convertToEncryptedMessageResponse = (encryptedMessage) => {
|
||||||
|
if (Buffer.isBuffer(encryptedMessage.ciphertext) &&
|
||||||
|
Buffer.isBuffer(encryptedMessage.iv) &&
|
||||||
|
Buffer.isBuffer(encryptedMessage.mac) &&
|
||||||
|
Buffer.isBuffer(encryptedMessage.ephemPublicKey)) {
|
||||||
|
return {
|
||||||
|
ciphertext: convertBufferToBase64(encryptedMessage.ciphertext),
|
||||||
|
iv: convertBufferToBase64(encryptedMessage.iv),
|
||||||
|
mac: convertBufferToBase64(encryptedMessage.mac),
|
||||||
|
ephemPublicKey: convertBufferToBase64(encryptedMessage.ephemPublicKey)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof encryptedMessage.ciphertext === "string") {
|
||||||
|
// @ts-ignore
|
||||||
|
return encryptedMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FieldError({
|
||||||
|
field: "encryptedMessage",
|
||||||
|
message: "Unknown encrypted message format"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {EncryptedMessageBuffer | EncryptedMessageResponse} encryptedMessage
|
||||||
|
* @returns {EncryptedMessageBuffer}
|
||||||
|
*/
|
||||||
|
const convertToEncryptedMessage = (encryptedMessage) => {
|
||||||
|
if (encryptedMessage.ciphertext instanceof Buffer &&
|
||||||
|
encryptedMessage.iv instanceof Buffer &&
|
||||||
|
encryptedMessage.mac instanceof Buffer &&
|
||||||
|
encryptedMessage.ephemPublicKey instanceof Buffer) {
|
||||||
|
// @ts-ignore
|
||||||
|
return encryptedMessage;
|
||||||
|
}
|
||||||
|
if (typeof encryptedMessage.ciphertext === "string" &&
|
||||||
|
typeof encryptedMessage.iv === "string" &&
|
||||||
|
typeof encryptedMessage.mac === "string" &&
|
||||||
|
typeof encryptedMessage.ephemPublicKey === "string") {
|
||||||
|
return {
|
||||||
|
ciphertext: convertBase64ToBuffer(encryptedMessage.ciphertext),
|
||||||
|
iv: convertBase64ToBuffer(encryptedMessage.iv),
|
||||||
|
mac: convertBase64ToBuffer(encryptedMessage.mac),
|
||||||
|
ephemPublicKey: convertBase64ToBuffer(encryptedMessage.ephemPublicKey)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw new FieldError({
|
||||||
|
field: "encryptedMessage",
|
||||||
|
message: "Unknown encrypted message format"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
convertUTF8ToBuffer,
|
||||||
|
convertBase64ToBuffer,
|
||||||
|
convertBufferToBase64,
|
||||||
|
convertToEncryptedMessage,
|
||||||
|
convertToEncryptedMessageResponse,
|
||||||
|
processKey
|
||||||
|
}
|
||||||
151
utils/ECC/index.js
Normal file
151
utils/ECC/index.js
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
/** @format */
|
||||||
|
const ECCrypto = require('eccrypto')
|
||||||
|
const Storage = require('node-persist')
|
||||||
|
const FieldError = require('../fieldError')
|
||||||
|
const {
|
||||||
|
convertBufferToBase64,
|
||||||
|
processKey,
|
||||||
|
convertToEncryptedMessageResponse,
|
||||||
|
convertUTF8ToBuffer,
|
||||||
|
convertToEncryptedMessage,
|
||||||
|
convertBase64ToBuffer
|
||||||
|
} = require('./crypto')
|
||||||
|
|
||||||
|
const nodeKeyPairs = new Map()
|
||||||
|
const devicePublicKeys = new Map()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} EncryptedMessage
|
||||||
|
* @prop {string} ciphertext
|
||||||
|
* @prop {string} iv
|
||||||
|
* @prop {string} mac
|
||||||
|
* @prop {string} ephemPublicKey
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the message supplied is encrypted or not
|
||||||
|
* @param {EncryptedMessage} message
|
||||||
|
*/
|
||||||
|
const isEncryptedMessage = message =>
|
||||||
|
message &&
|
||||||
|
message.ciphertext &&
|
||||||
|
message.iv &&
|
||||||
|
message.mac &&
|
||||||
|
message.ephemPublicKey
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a new encryption key pair that will be used
|
||||||
|
* when communicating with the deviceId specified
|
||||||
|
* @param {string} deviceId
|
||||||
|
*/
|
||||||
|
const generateKeyPair = deviceId => {
|
||||||
|
const privateKey = ECCrypto.generatePrivate()
|
||||||
|
const publicKey = ECCrypto.getPublic(privateKey)
|
||||||
|
const privateKeyBase64 = convertBufferToBase64(privateKey)
|
||||||
|
const publicKeyBase64 = convertBufferToBase64(publicKey)
|
||||||
|
|
||||||
|
nodeKeyPairs.set(deviceId, {
|
||||||
|
privateKey,
|
||||||
|
publicKey
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
privateKey,
|
||||||
|
publicKey,
|
||||||
|
privateKeyBase64,
|
||||||
|
publicKeyBase64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the specified device has a keypair generated
|
||||||
|
* @param {{ deviceId: string }} arg0
|
||||||
|
*/
|
||||||
|
const isAuthorizedDevice = ({ deviceId }) => devicePublicKeys.has(deviceId)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a new keypair for the deviceId specified and
|
||||||
|
* saves its publicKey locally
|
||||||
|
* @param {{ deviceId: string, publicKey: string }} arg0
|
||||||
|
*/
|
||||||
|
const authorizeDevice = async ({ deviceId, publicKey }) => {
|
||||||
|
const hostId = await Storage.get('encryption/hostId')
|
||||||
|
devicePublicKeys.set(deviceId, convertBase64ToBuffer(publicKey))
|
||||||
|
const keyPair = generateKeyPair(deviceId)
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
APIPublicKey: keyPair.publicKeyBase64,
|
||||||
|
hostId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts the specified message using the specified deviceId's
|
||||||
|
* public key
|
||||||
|
* @param {{ deviceId: string, message: string }} arg0
|
||||||
|
* @returns {Promise<import('./crypto').EncryptedMessageResponse>}
|
||||||
|
*/
|
||||||
|
const encryptMessage = async ({ message = '', deviceId }) => {
|
||||||
|
const publicKey = devicePublicKeys.get(deviceId)
|
||||||
|
|
||||||
|
if (!publicKey) {
|
||||||
|
throw new FieldError({
|
||||||
|
field: 'deviceId',
|
||||||
|
message: 'Unauthorized Device ID detected'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const processedPublicKey = processKey(publicKey)
|
||||||
|
const messageBuffer = convertUTF8ToBuffer(message)
|
||||||
|
const encryptedMessage = await ECCrypto.encrypt(
|
||||||
|
processedPublicKey,
|
||||||
|
messageBuffer
|
||||||
|
)
|
||||||
|
const encryptedMessageResponse = {
|
||||||
|
ciphertext: encryptedMessage.ciphertext,
|
||||||
|
iv: encryptedMessage.iv,
|
||||||
|
mac: encryptedMessage.mac,
|
||||||
|
ephemPublicKey: encryptedMessage.ephemPublicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertToEncryptedMessageResponse(encryptedMessageResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts the specified message using the API keypair
|
||||||
|
* associated with the specified deviceId
|
||||||
|
* @param {{ encryptedMessage: EncryptedMessage, deviceId: string }} arg0
|
||||||
|
*/
|
||||||
|
const decryptMessage = async ({ encryptedMessage, deviceId }) => {
|
||||||
|
try {
|
||||||
|
const keyPair = nodeKeyPairs.get(deviceId)
|
||||||
|
|
||||||
|
if (!keyPair) {
|
||||||
|
throw new FieldError({
|
||||||
|
field: 'deviceId',
|
||||||
|
message: 'Unauthorized Device ID detected'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const processedPrivateKey = processKey(keyPair.privateKey)
|
||||||
|
const decryptedMessage = await ECCrypto.decrypt(
|
||||||
|
processedPrivateKey,
|
||||||
|
convertToEncryptedMessage(encryptedMessage)
|
||||||
|
)
|
||||||
|
const parsedMessage = decryptedMessage.toString('utf8')
|
||||||
|
return parsedMessage
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
isAuthorizedDevice,
|
||||||
|
isEncryptedMessage,
|
||||||
|
generateKeyPair,
|
||||||
|
encryptMessage,
|
||||||
|
decryptMessage,
|
||||||
|
authorizeDevice
|
||||||
|
}
|
||||||
140
utils/ECC/socket.js
Normal file
140
utils/ECC/socket.js
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
/**
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
const Common = require('shock-common')
|
||||||
|
const logger = require('winston')
|
||||||
|
const { safeParseJSON } = require('../json')
|
||||||
|
const ECC = require('./index')
|
||||||
|
|
||||||
|
const nonEncryptedEvents = [
|
||||||
|
'ping',
|
||||||
|
'disconnect',
|
||||||
|
'IS_GUN_AUTH',
|
||||||
|
'SET_LAST_SEEN_APP',
|
||||||
|
Common.Constants.ErrorCode.NOT_AUTH
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../../services/gunDB/Mediator').SimpleSocket} SimpleSocket
|
||||||
|
* @typedef {import('../../services/gunDB/Mediator').Emission} Emission
|
||||||
|
* @typedef {import('../../services/gunDB/Mediator').EncryptedEmission} EncryptedEmission
|
||||||
|
* @typedef {import('../../services/gunDB/Mediator').EncryptedEmissionLegacy} EncryptedEmissionLegacy
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} eventName
|
||||||
|
*/
|
||||||
|
const isNonEncrypted = eventName => nonEncryptedEvents.includes(eventName)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {SimpleSocket} socket
|
||||||
|
* @returns {(eventName: string, args?: Emission | EncryptedEmission | EncryptedEmissionLegacy) => Promise<void>}
|
||||||
|
*/
|
||||||
|
const encryptedEmit = socket => async (eventName, ...args) => {
|
||||||
|
try {
|
||||||
|
if (isNonEncrypted(eventName)) {
|
||||||
|
return socket.emit(eventName, ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
const deviceId = socket.handshake.query.encryptionId
|
||||||
|
|
||||||
|
if (!deviceId) {
|
||||||
|
throw {
|
||||||
|
field: 'deviceId',
|
||||||
|
message: 'Please specify a device ID'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const authorized = ECC.isAuthorizedDevice({ deviceId })
|
||||||
|
|
||||||
|
if (!authorized) {
|
||||||
|
throw {
|
||||||
|
field: 'deviceId',
|
||||||
|
message: 'Please exchange keys with the API before using the socket'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const encryptedArgs = await Promise.all(
|
||||||
|
args.map(data => {
|
||||||
|
if (!data) {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
return ECC.encryptMessage({
|
||||||
|
message: typeof data === 'object' ? JSON.stringify(data) : data,
|
||||||
|
deviceId
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log('Encrypted args:', encryptedArgs)
|
||||||
|
|
||||||
|
return socket.emit(eventName, ...encryptedArgs)
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(
|
||||||
|
`[SOCKET] An error has occurred while encrypting an event (${eventName}):`,
|
||||||
|
err
|
||||||
|
)
|
||||||
|
|
||||||
|
return socket.emit('encryption:error', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {SimpleSocket} socket
|
||||||
|
* @returns {(eventName: string, callback: (data: any) => void) => void}
|
||||||
|
*/
|
||||||
|
const encryptedOn = socket => (eventName, callback) => {
|
||||||
|
try {
|
||||||
|
if (isNonEncrypted(eventName)) {
|
||||||
|
return socket.on(eventName, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
const deviceId = socket.handshake.query.encryptionId
|
||||||
|
|
||||||
|
if (!deviceId) {
|
||||||
|
throw {
|
||||||
|
field: 'deviceId',
|
||||||
|
message: 'Please specify a device ID'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const authorized = ECC.isAuthorizedDevice({ deviceId })
|
||||||
|
|
||||||
|
if (!authorized) {
|
||||||
|
throw {
|
||||||
|
field: 'deviceId',
|
||||||
|
message: 'Please exchange keys with the API before using the socket'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.on(eventName, async data => {
|
||||||
|
if (isNonEncrypted(eventName)) {
|
||||||
|
callback(data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
const decryptedMessage = await ECC.decryptMessage({
|
||||||
|
deviceId,
|
||||||
|
encryptedMessage: data
|
||||||
|
})
|
||||||
|
|
||||||
|
callback(safeParseJSON(decryptedMessage))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(
|
||||||
|
`[SOCKET] An error has occurred while decrypting an event (${eventName}):`,
|
||||||
|
err
|
||||||
|
)
|
||||||
|
|
||||||
|
return socket.emit('encryption:error', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
isNonEncrypted,
|
||||||
|
encryptedOn,
|
||||||
|
encryptedEmit
|
||||||
|
}
|
||||||
14
utils/JSON.js
Normal file
14
utils/JSON.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
/** @param {any} data */
|
||||||
|
const safeParseJSON = (data) => {
|
||||||
|
try {
|
||||||
|
const parsedJSON = JSON.parse(data);
|
||||||
|
return parsedJSON;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
safeParseJSON
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,8 @@ module.exports = {
|
||||||
"/api/lnd/wallet": true,
|
"/api/lnd/wallet": true,
|
||||||
"/api/lnd/wallet/existing": true,
|
"/api/lnd/wallet/existing": true,
|
||||||
"/api/lnd/auth": true,
|
"/api/lnd/auth": true,
|
||||||
"/api/security/exchangeKeys": true
|
"/api/security/exchangeKeys": true,
|
||||||
|
"/api/encryption/exchange": true
|
||||||
},
|
},
|
||||||
PUT: {},
|
PUT: {},
|
||||||
DELETE: {}
|
DELETE: {}
|
||||||
|
|
@ -30,5 +31,5 @@ module.exports = {
|
||||||
PUT: {},
|
PUT: {},
|
||||||
DELETE: {}
|
DELETE: {}
|
||||||
},
|
},
|
||||||
nonEncryptedRoutes: ['/api/security/exchangeKeys', '/healthz', '/ping', '/api/lnd/wallet/status', '/api/gun/auth']
|
nonEncryptedRoutes: ['/api/security/exchangeKeys', "/api/encryption/exchange", '/healthz', '/ping', '/api/lnd/wallet/status', '/api/gun/auth']
|
||||||
}
|
}
|
||||||
215
yarn.lock
215
yarn.lock
|
|
@ -634,6 +634,14 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/eccrypto@^1.1.2":
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/eccrypto/-/eccrypto-1.1.2.tgz#49c452e78c02f890036b8cbee7c18bd77aa16ce1"
|
||||||
|
integrity sha512-qmB/iGIoqDdCMHAcJiOKI4ZBI1Z3kBQGYQCkgNP/Z9ge5w/EVx5uxQYkGOFpllm6l2N/B3qXcn9vjqXGaV1vRQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/expect" "^1.20.4"
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/engine.io@*":
|
"@types/engine.io@*":
|
||||||
version "3.1.4"
|
version "3.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/@types/engine.io/-/engine.io-3.1.4.tgz#3d9472711d179daa7c95c051e50ad411e18a9bdc"
|
resolved "https://registry.yarnpkg.com/@types/engine.io/-/engine.io-3.1.4.tgz#3d9472711d179daa7c95c051e50ad411e18a9bdc"
|
||||||
|
|
@ -641,6 +649,11 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/expect@^1.20.4":
|
||||||
|
version "1.20.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/expect/-/expect-1.20.4.tgz#8288e51737bf7e3ab5d7c77bfa695883745264e5"
|
||||||
|
integrity sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==
|
||||||
|
|
||||||
"@types/express-serve-static-core@*":
|
"@types/express-serve-static-core@*":
|
||||||
version "4.16.9"
|
version "4.16.9"
|
||||||
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.9.tgz#69e00643b0819b024bdede95ced3ff239bb54558"
|
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.9.tgz#69e00643b0819b024bdede95ced3ff239bb54558"
|
||||||
|
|
@ -730,6 +743,13 @@
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
form-data "^3.0.0"
|
form-data "^3.0.0"
|
||||||
|
|
||||||
|
"@types/node-persist@^3.1.1":
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/node-persist/-/node-persist-3.1.1.tgz#de444e87561e8ad022e1f31ad4fee377d9db1b13"
|
||||||
|
integrity sha512-4PRvgEWkKrWWCZR5Hp/aoAu13z3+e99d9KtbXEDbcJPe84yDoRz3d2IEhiVcSe8fJubYMpXJhyGOdqJ8yoGZsA==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/node@*":
|
"@types/node@*":
|
||||||
version "12.7.4"
|
version "12.7.4"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.4.tgz#64db61e0359eb5a8d99b55e05c729f130a678b04"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.4.tgz#64db61e0359eb5a8d99b55e05c729f130a678b04"
|
||||||
|
|
@ -877,6 +897,11 @@ acorn-walk@^6.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c"
|
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c"
|
||||||
integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==
|
integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==
|
||||||
|
|
||||||
|
acorn@7.1.1:
|
||||||
|
version "7.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf"
|
||||||
|
integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==
|
||||||
|
|
||||||
acorn@^5.5.3:
|
acorn@^5.5.3:
|
||||||
version "5.7.4"
|
version "5.7.4"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e"
|
||||||
|
|
@ -1407,6 +1432,20 @@ binary-extensions@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
|
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
|
||||||
integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
|
integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
|
||||||
|
|
||||||
|
bindings@^1.5.0:
|
||||||
|
version "1.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
|
||||||
|
integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
|
||||||
|
dependencies:
|
||||||
|
file-uri-to-path "1.0.0"
|
||||||
|
|
||||||
|
bip66@^1.1.5:
|
||||||
|
version "1.1.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/bip66/-/bip66-1.1.5.tgz#01fa8748785ca70955d5011217d1b3139969ca22"
|
||||||
|
integrity sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=
|
||||||
|
dependencies:
|
||||||
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
bitcore-lib@^0.15.0:
|
bitcore-lib@^0.15.0:
|
||||||
version "0.15.0"
|
version "0.15.0"
|
||||||
resolved "https://registry.yarnpkg.com/bitcore-lib/-/bitcore-lib-0.15.0.tgz#f924be13869f2aab7e04aeec5642ad3359b6cec2"
|
resolved "https://registry.yarnpkg.com/bitcore-lib/-/bitcore-lib-0.15.0.tgz#f924be13869f2aab7e04aeec5642ad3359b6cec2"
|
||||||
|
|
@ -1434,6 +1473,11 @@ bn.js@=4.11.8, bn.js@^4.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
|
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
|
||||||
integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
|
integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
|
||||||
|
|
||||||
|
bn.js@^4.11.8, bn.js@^4.11.9:
|
||||||
|
version "4.12.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
|
||||||
|
integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
|
||||||
|
|
||||||
body-parser@1.19.0, body-parser@^1.16.0:
|
body-parser@1.19.0, body-parser@^1.16.0:
|
||||||
version "1.19.0"
|
version "1.19.0"
|
||||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
|
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
|
||||||
|
|
@ -1494,7 +1538,7 @@ braces@^3.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
fill-range "^7.0.1"
|
fill-range "^7.0.1"
|
||||||
|
|
||||||
brorand@^1.0.1:
|
brorand@^1.0.1, brorand@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
|
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
|
||||||
integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
|
integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
|
||||||
|
|
@ -1511,6 +1555,18 @@ browser-resolve@^1.11.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
resolve "1.1.7"
|
resolve "1.1.7"
|
||||||
|
|
||||||
|
browserify-aes@^1.0.6:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
|
||||||
|
integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==
|
||||||
|
dependencies:
|
||||||
|
buffer-xor "^1.0.3"
|
||||||
|
cipher-base "^1.0.0"
|
||||||
|
create-hash "^1.1.0"
|
||||||
|
evp_bytestokey "^1.0.3"
|
||||||
|
inherits "^2.0.1"
|
||||||
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
bs58@=4.0.1:
|
bs58@=4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
|
resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
|
||||||
|
|
@ -1545,6 +1601,11 @@ buffer-from@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
||||||
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
|
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
|
||||||
|
|
||||||
|
buffer-xor@^1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
|
||||||
|
integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=
|
||||||
|
|
||||||
buffer@^5.4.3:
|
buffer@^5.4.3:
|
||||||
version "5.4.3"
|
version "5.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115"
|
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115"
|
||||||
|
|
@ -1702,6 +1763,14 @@ ci-info@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
|
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
|
||||||
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
|
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
|
||||||
|
|
||||||
|
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
|
||||||
|
integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==
|
||||||
|
dependencies:
|
||||||
|
inherits "^2.0.1"
|
||||||
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
class-utils@^0.3.5:
|
class-utils@^0.3.5:
|
||||||
version "0.3.6"
|
version "0.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
|
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
|
||||||
|
|
@ -2005,6 +2074,29 @@ create-error-class@^3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
capture-stack-trace "^1.0.0"
|
capture-stack-trace "^1.0.0"
|
||||||
|
|
||||||
|
create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
|
||||||
|
integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
|
||||||
|
dependencies:
|
||||||
|
cipher-base "^1.0.1"
|
||||||
|
inherits "^2.0.1"
|
||||||
|
md5.js "^1.3.4"
|
||||||
|
ripemd160 "^2.0.1"
|
||||||
|
sha.js "^2.4.0"
|
||||||
|
|
||||||
|
create-hmac@^1.1.4:
|
||||||
|
version "1.1.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
|
||||||
|
integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
|
||||||
|
dependencies:
|
||||||
|
cipher-base "^1.0.3"
|
||||||
|
create-hash "^1.1.0"
|
||||||
|
inherits "^2.0.1"
|
||||||
|
ripemd160 "^2.0.0"
|
||||||
|
safe-buffer "^5.0.1"
|
||||||
|
sha.js "^2.4.8"
|
||||||
|
|
||||||
create-require@^1.1.0:
|
create-require@^1.1.0:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||||
|
|
@ -2244,6 +2336,15 @@ dotenv@^8.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.1.0.tgz#d811e178652bfb8a1e593c6dd704ec7e90d85ea2"
|
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.1.0.tgz#d811e178652bfb8a1e593c6dd704ec7e90d85ea2"
|
||||||
integrity sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA==
|
integrity sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA==
|
||||||
|
|
||||||
|
drbg.js@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/drbg.js/-/drbg.js-1.0.1.tgz#3e36b6c42b37043823cdbc332d58f31e2445480b"
|
||||||
|
integrity sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=
|
||||||
|
dependencies:
|
||||||
|
browserify-aes "^1.0.6"
|
||||||
|
create-hash "^1.1.2"
|
||||||
|
create-hmac "^1.1.4"
|
||||||
|
|
||||||
duplexer3@^0.1.4:
|
duplexer3@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
||||||
|
|
@ -2257,6 +2358,18 @@ ecc-jsbn@~0.1.1:
|
||||||
jsbn "~0.1.0"
|
jsbn "~0.1.0"
|
||||||
safer-buffer "^2.1.0"
|
safer-buffer "^2.1.0"
|
||||||
|
|
||||||
|
eccrypto@^1.1.6:
|
||||||
|
version "1.1.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/eccrypto/-/eccrypto-1.1.6.tgz#846bd1222323036f7a3515613704386399702bd3"
|
||||||
|
integrity sha512-d78ivVEzu7Tn0ZphUUaL43+jVPKTMPFGtmgtz1D0LrFn7cY3K8CdrvibuLz2AAkHBLKZtR8DMbB2ukRYFk987A==
|
||||||
|
dependencies:
|
||||||
|
acorn "7.1.1"
|
||||||
|
elliptic "6.5.4"
|
||||||
|
es6-promise "4.2.8"
|
||||||
|
nan "2.14.0"
|
||||||
|
optionalDependencies:
|
||||||
|
secp256k1 "3.7.1"
|
||||||
|
|
||||||
ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11:
|
ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11:
|
||||||
version "1.0.11"
|
version "1.0.11"
|
||||||
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
|
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
|
||||||
|
|
@ -2274,6 +2387,19 @@ elegant-spinner@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-2.0.0.tgz#f236378985ecd16da75488d166be4b688fd5af94"
|
resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-2.0.0.tgz#f236378985ecd16da75488d166be4b688fd5af94"
|
||||||
integrity sha512-5YRYHhvhYzV/FC4AiMdeSIg3jAYGq9xFvbhZMpPlJoBsfYgrw2DSCYeXfat6tYBu45PWiyRr3+flaCPPmviPaA==
|
integrity sha512-5YRYHhvhYzV/FC4AiMdeSIg3jAYGq9xFvbhZMpPlJoBsfYgrw2DSCYeXfat6tYBu45PWiyRr3+flaCPPmviPaA==
|
||||||
|
|
||||||
|
elliptic@6.5.4, elliptic@^6.4.1:
|
||||||
|
version "6.5.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
|
||||||
|
integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
|
||||||
|
dependencies:
|
||||||
|
bn.js "^4.11.9"
|
||||||
|
brorand "^1.1.0"
|
||||||
|
hash.js "^1.0.0"
|
||||||
|
hmac-drbg "^1.0.1"
|
||||||
|
inherits "^2.0.4"
|
||||||
|
minimalistic-assert "^1.0.1"
|
||||||
|
minimalistic-crypto-utils "^1.0.1"
|
||||||
|
|
||||||
elliptic@=6.4.0:
|
elliptic@=6.4.0:
|
||||||
version "6.4.0"
|
version "6.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
|
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
|
||||||
|
|
@ -2415,6 +2541,11 @@ es-to-primitive@^1.2.0:
|
||||||
is-date-object "^1.0.1"
|
is-date-object "^1.0.1"
|
||||||
is-symbol "^1.0.2"
|
is-symbol "^1.0.2"
|
||||||
|
|
||||||
|
es6-promise@4.2.8:
|
||||||
|
version "4.2.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
|
||||||
|
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
|
||||||
|
|
||||||
escape-html@~1.0.3:
|
escape-html@~1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||||
|
|
@ -2594,6 +2725,14 @@ event-target-shim@^5.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
|
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
|
||||||
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
|
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
|
||||||
|
|
||||||
|
evp_bytestokey@^1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02"
|
||||||
|
integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==
|
||||||
|
dependencies:
|
||||||
|
md5.js "^1.3.4"
|
||||||
|
safe-buffer "^5.1.1"
|
||||||
|
|
||||||
exec-sh@^0.3.2:
|
exec-sh@^0.3.2:
|
||||||
version "0.3.2"
|
version "0.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.2.tgz#6738de2eb7c8e671d0366aea0b0db8c6f7d7391b"
|
resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.2.tgz#6738de2eb7c8e671d0366aea0b0db8c6f7d7391b"
|
||||||
|
|
@ -2848,6 +2987,11 @@ file-stream-rotator@^0.5.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
moment "^2.11.2"
|
moment "^2.11.2"
|
||||||
|
|
||||||
|
file-uri-to-path@1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
||||||
|
integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
|
||||||
|
|
||||||
fill-range@^4.0.0:
|
fill-range@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
|
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
|
||||||
|
|
@ -3328,6 +3472,15 @@ has@^1.0.1, has@^1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
function-bind "^1.1.1"
|
function-bind "^1.1.1"
|
||||||
|
|
||||||
|
hash-base@^3.0.0:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33"
|
||||||
|
integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==
|
||||||
|
dependencies:
|
||||||
|
inherits "^2.0.4"
|
||||||
|
readable-stream "^3.6.0"
|
||||||
|
safe-buffer "^5.2.0"
|
||||||
|
|
||||||
hash.js@^1.0.0, hash.js@^1.0.3:
|
hash.js@^1.0.0, hash.js@^1.0.3:
|
||||||
version "1.1.7"
|
version "1.1.7"
|
||||||
resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
|
resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
|
||||||
|
|
@ -3336,7 +3489,7 @@ hash.js@^1.0.0, hash.js@^1.0.3:
|
||||||
inherits "^2.0.3"
|
inherits "^2.0.3"
|
||||||
minimalistic-assert "^1.0.1"
|
minimalistic-assert "^1.0.1"
|
||||||
|
|
||||||
hmac-drbg@^1.0.0:
|
hmac-drbg@^1.0.0, hmac-drbg@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
|
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
|
||||||
integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=
|
integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=
|
||||||
|
|
@ -3503,7 +3656,7 @@ inflight@^1.0.4:
|
||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
wrappy "1"
|
wrappy "1"
|
||||||
|
|
||||||
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
|
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||||
|
|
@ -4727,6 +4880,15 @@ map-visit@^1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
object-visit "^1.0.0"
|
object-visit "^1.0.0"
|
||||||
|
|
||||||
|
md5.js@^1.3.4:
|
||||||
|
version "1.3.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
|
||||||
|
integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==
|
||||||
|
dependencies:
|
||||||
|
hash-base "^3.0.0"
|
||||||
|
inherits "^2.0.1"
|
||||||
|
safe-buffer "^5.1.2"
|
||||||
|
|
||||||
media-typer@0.3.0:
|
media-typer@0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||||
|
|
@ -4913,11 +5075,16 @@ mute-stream@0.0.8:
|
||||||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
|
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
|
||||||
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
|
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
|
||||||
|
|
||||||
nan@^2.12.1, nan@^2.13.2:
|
nan@2.14.0, nan@^2.12.1, nan@^2.13.2:
|
||||||
version "2.14.0"
|
version "2.14.0"
|
||||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
||||||
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
|
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
|
||||||
|
|
||||||
|
nan@^2.14.0:
|
||||||
|
version "2.14.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
|
||||||
|
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
|
||||||
|
|
||||||
nanomatch@^1.2.9:
|
nanomatch@^1.2.9:
|
||||||
version "1.2.13"
|
version "1.2.13"
|
||||||
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
|
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
|
||||||
|
|
@ -5765,7 +5932,7 @@ readable-stream@^2.3.7:
|
||||||
string_decoder "~1.1.1"
|
string_decoder "~1.1.1"
|
||||||
util-deprecate "~1.0.1"
|
util-deprecate "~1.0.1"
|
||||||
|
|
||||||
readable-stream@^3.4.0:
|
readable-stream@^3.4.0, readable-stream@^3.6.0:
|
||||||
version "3.6.0"
|
version "3.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||||
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
|
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
|
||||||
|
|
@ -6015,6 +6182,14 @@ rimraf@^3.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
glob "^7.1.3"
|
glob "^7.1.3"
|
||||||
|
|
||||||
|
ripemd160@^2.0.0, ripemd160@^2.0.1:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
|
||||||
|
integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==
|
||||||
|
dependencies:
|
||||||
|
hash-base "^3.0.0"
|
||||||
|
inherits "^2.0.1"
|
||||||
|
|
||||||
rsvp@^4.8.4:
|
rsvp@^4.8.4:
|
||||||
version "4.8.5"
|
version "4.8.5"
|
||||||
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
|
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
|
||||||
|
|
@ -6051,7 +6226,7 @@ safe-buffer@5.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
|
||||||
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
|
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
|
||||||
|
|
||||||
safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
|
safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
|
||||||
version "5.2.1"
|
version "5.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||||
|
|
@ -6093,6 +6268,20 @@ sax@^1.2.4:
|
||||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||||
|
|
||||||
|
secp256k1@3.7.1:
|
||||||
|
version "3.7.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.7.1.tgz#12e473e0e9a7c2f2d4d4818e722ad0e14cc1e2f1"
|
||||||
|
integrity sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g==
|
||||||
|
dependencies:
|
||||||
|
bindings "^1.5.0"
|
||||||
|
bip66 "^1.1.5"
|
||||||
|
bn.js "^4.11.8"
|
||||||
|
create-hash "^1.2.0"
|
||||||
|
drbg.js "^1.0.1"
|
||||||
|
elliptic "^6.4.1"
|
||||||
|
nan "^2.14.0"
|
||||||
|
safe-buffer "^5.1.2"
|
||||||
|
|
||||||
semver-compare@^1.0.0:
|
semver-compare@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
|
resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
|
||||||
|
|
@ -6174,6 +6363,14 @@ setprototypeof@1.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
|
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
|
||||||
integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
|
integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
|
||||||
|
|
||||||
|
sha.js@^2.4.0, sha.js@^2.4.8:
|
||||||
|
version "2.4.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
|
||||||
|
integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
|
||||||
|
dependencies:
|
||||||
|
inherits "^2.0.1"
|
||||||
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
shebang-command@^1.2.0:
|
shebang-command@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
|
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
|
||||||
|
|
@ -7364,9 +7561,9 @@ xmlhttprequest-ssl@~1.5.4:
|
||||||
integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
|
integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
|
||||||
|
|
||||||
y18n@^3.2.0:
|
y18n@^3.2.0:
|
||||||
version "3.2.1"
|
version "3.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
|
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696"
|
||||||
integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
|
integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==
|
||||||
|
|
||||||
y18n@^4.0.0:
|
y18n@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue