random route stuff
This commit is contained in:
parent
d27ff64a74
commit
9a63772401
8 changed files with 143 additions and 124 deletions
|
|
@ -22,6 +22,7 @@ const pairing = require('../lib/admin/pairing')
|
||||||
const server = require('../lib/admin/server')
|
const server = require('../lib/admin/server')
|
||||||
const transactions = require('../lib/admin/transactions')
|
const transactions = require('../lib/admin/transactions')
|
||||||
const T = require('../lib/time')
|
const T = require('../lib/time')
|
||||||
|
const logger = require('../lib/logger')
|
||||||
|
|
||||||
const NEVER = new Date(Date.now() + 100 * T.years)
|
const NEVER = new Date(Date.now() + 100 * T.years)
|
||||||
|
|
||||||
|
|
@ -29,6 +30,9 @@ const devMode = argv.dev
|
||||||
|
|
||||||
let serverConfig
|
let serverConfig
|
||||||
|
|
||||||
|
const version = require('../package.json').version
|
||||||
|
logger.info('Version: %s', version)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const homeConfigPath = path.resolve(os.homedir(), '.lamassu', 'lamassu.json')
|
const homeConfigPath = path.resolve(os.homedir(), '.lamassu', 'lamassu.json')
|
||||||
serverConfig = JSON.parse(fs.readFileSync(homeConfigPath))
|
serverConfig = JSON.parse(fs.readFileSync(homeConfigPath))
|
||||||
|
|
@ -161,7 +165,9 @@ function register (req, res, next) {
|
||||||
return login.register(otp)
|
return login.register(otp)
|
||||||
.then(r => {
|
.then(r => {
|
||||||
if (r.expired) return res.status(401).send('OTP expired, generate new registration link')
|
if (r.expired) return res.status(401).send('OTP expired, generate new registration link')
|
||||||
if (!r.success) return res.status(401).send('Registration failed')
|
|
||||||
|
// Maybe user is using old registration key, attempt to authenticate
|
||||||
|
if (!r.success) return next()
|
||||||
|
|
||||||
const cookieOpts = {
|
const cookieOpts = {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
|
|
|
||||||
23
lib/app.js
23
lib/app.js
|
|
@ -1,7 +1,6 @@
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const http = require('http')
|
const http = require('http')
|
||||||
const https = require('https')
|
const https = require('https')
|
||||||
const express = require('express')
|
|
||||||
const argv = require('minimist')(process.argv.slice(2))
|
const argv = require('minimist')(process.argv.slice(2))
|
||||||
|
|
||||||
const routes = require('./routes')
|
const routes = require('./routes')
|
||||||
|
|
@ -11,7 +10,10 @@ const verifySchema = require('./verify-schema')
|
||||||
const settingsLoader = require('./settings-loader')
|
const settingsLoader = require('./settings-loader')
|
||||||
const options = require('./options')
|
const options = require('./options')
|
||||||
|
|
||||||
const devMode = argv.dev || argv.http || options.http
|
const devMode = argv.dev || options.http
|
||||||
|
|
||||||
|
const version = require('../package.json').version
|
||||||
|
logger.info('Version: %s', version)
|
||||||
|
|
||||||
function run () {
|
function run () {
|
||||||
let count = 0
|
let count = 0
|
||||||
|
|
@ -31,9 +33,6 @@ function run () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function runOnce () {
|
function runOnce () {
|
||||||
const app = express()
|
|
||||||
const localApp = express()
|
|
||||||
|
|
||||||
return verifySchema.valid()
|
return verifySchema.valid()
|
||||||
.then(() => settingsLoader.loadLatest())
|
.then(() => settingsLoader.loadLatest())
|
||||||
.then(settings => {
|
.then(settings => {
|
||||||
|
|
@ -46,23 +45,15 @@ function runOnce () {
|
||||||
}
|
}
|
||||||
|
|
||||||
const server = devMode
|
const server = devMode
|
||||||
? http.createServer(app)
|
? http.createServer(routes.app)
|
||||||
: https.createServer(httpsServerOptions, app)
|
: https.createServer(httpsServerOptions, routes.app)
|
||||||
|
|
||||||
const port = 3000
|
const port = 3000
|
||||||
const localPort = 3030
|
const localPort = 3030
|
||||||
const localServer = http.createServer(localApp)
|
const localServer = http.createServer(routes.localApp)
|
||||||
|
|
||||||
if (options.devMode) logger.info('In dev mode')
|
if (options.devMode) logger.info('In dev mode')
|
||||||
|
|
||||||
const opts = {
|
|
||||||
app,
|
|
||||||
localApp,
|
|
||||||
devMode
|
|
||||||
}
|
|
||||||
|
|
||||||
routes.init(opts)
|
|
||||||
|
|
||||||
server.listen(port, () => {
|
server.listen(port, () => {
|
||||||
console.log('lamassu-server listening on port ' +
|
console.log('lamassu-server listening on port ' +
|
||||||
port + ' ' + (devMode ? '(http)' : '(https)'))
|
port + ' ' + (devMode ? '(http)' : '(https)'))
|
||||||
|
|
|
||||||
13
lib/db.js
13
lib/db.js
|
|
@ -1,4 +1,13 @@
|
||||||
const pgp = require('pg-promise')()
|
const Pgp = require('pg-promise')
|
||||||
const psqlUrl = require('../lib/options').postgresql
|
const psqlUrl = require('../lib/options').postgresql
|
||||||
|
const logger = require('./logger')
|
||||||
|
|
||||||
module.exports = pgp(psqlUrl)
|
const pgp = Pgp({
|
||||||
|
pgNative: true,
|
||||||
|
error: (_, e) => {
|
||||||
|
if (e.cn) logger.error('Database not reachable.')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const db = pgp(psqlUrl)
|
||||||
|
module.exports = db
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,4 @@ const logger = new winston.Logger({
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
// log version
|
|
||||||
var version = require('../package.json').version
|
|
||||||
logger.info('Version: %s', version)
|
|
||||||
|
|
||||||
module.exports = logger
|
module.exports = logger
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,8 @@ function authorizeCaDownload (caToken) {
|
||||||
function isPaired (deviceId) {
|
function isPaired (deviceId) {
|
||||||
const sql = 'select device_id from devices where device_id=$1 and paired=TRUE'
|
const sql = 'select device_id from devices where device_id=$1 and paired=TRUE'
|
||||||
|
|
||||||
return db.one(sql, [deviceId])
|
return db.oneOrNone(sql, [deviceId])
|
||||||
.then(() => true)
|
.then(row => row && row.device_id === deviceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {pair, authorizeCaDownload, isPaired}
|
module.exports = {pair, authorizeCaDownload, isPaired}
|
||||||
|
|
|
||||||
182
lib/routes.js
182
lib/routes.js
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
const morgan = require('morgan')
|
const morgan = require('morgan')
|
||||||
const helmet = require('helmet')
|
const helmet = require('helmet')
|
||||||
const RateLimit = require('express-rate-limit')
|
|
||||||
const bodyParser = require('body-parser')
|
const bodyParser = require('body-parser')
|
||||||
const BigNumber = require('bignumber.js')
|
const BigNumber = require('bignumber.js')
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
const express = require('express')
|
||||||
|
|
||||||
const options = require('./options')
|
const options = require('./options')
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
|
|
@ -17,9 +17,7 @@ const settingsLoader = require('./settings-loader')
|
||||||
const plugins = require('./plugins')
|
const plugins = require('./plugins')
|
||||||
const helpers = require('./route-helpers')
|
const helpers = require('./route-helpers')
|
||||||
const poller = require('./poller')
|
const poller = require('./poller')
|
||||||
const T = require('./time')
|
const argv = require('minimist')(process.argv.slice(2))
|
||||||
|
|
||||||
module.exports = {init}
|
|
||||||
|
|
||||||
const CLOCK_SKEW = 60 * 1000
|
const CLOCK_SKEW = 60 * 1000
|
||||||
const REQUEST_TTL = 3 * 60 * 1000
|
const REQUEST_TTL = 3 * 60 * 1000
|
||||||
|
|
@ -27,6 +25,8 @@ const REQUEST_TTL = 3 * 60 * 1000
|
||||||
const pids = {}
|
const pids = {}
|
||||||
const reboots = {}
|
const reboots = {}
|
||||||
|
|
||||||
|
const devMode = argv.dev || options.http
|
||||||
|
|
||||||
function poll (req, res, next) {
|
function poll (req, res, next) {
|
||||||
const deviceId = req.deviceId
|
const deviceId = req.deviceId
|
||||||
const deviceTime = req.deviceTime
|
const deviceTime = req.deviceTime
|
||||||
|
|
@ -153,7 +153,7 @@ function ca (req, res) {
|
||||||
|
|
||||||
return pairing.authorizeCaDownload(token)
|
return pairing.authorizeCaDownload(token)
|
||||||
.then(ca => res.json({ca}))
|
.then(ca => res.json({ca}))
|
||||||
.catch(() => res.status(408).end())
|
.catch(() => res.sendStatus(403))
|
||||||
}
|
}
|
||||||
|
|
||||||
function pair (req, res, next) {
|
function pair (req, res, next) {
|
||||||
|
|
@ -320,107 +320,91 @@ function authorize (req, res, next) {
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
|
||||||
throw httpError('Unauthorized', 403)
|
return res.sendStatus(403)
|
||||||
})
|
})
|
||||||
.catch(next)
|
.catch(next)
|
||||||
}
|
}
|
||||||
|
|
||||||
function init (opts) {
|
const skip = options.logLevel === 'debug'
|
||||||
const skip = options.logLevel === 'debug'
|
? () => false
|
||||||
? () => false
|
: (req, res) => _.includes(req.path, ['/poll', '/state']) && res.statusCode === 200
|
||||||
: (req, res) => _.includes(req.path, ['/poll', '/state']) && res.statusCode === 200
|
|
||||||
|
|
||||||
const app = opts.app
|
const configRequiredRoutes = [
|
||||||
const localApp = opts.localApp
|
'/poll',
|
||||||
|
'/trade',
|
||||||
|
'/send',
|
||||||
|
'/cash_out',
|
||||||
|
'/dispense_ack',
|
||||||
|
'/event',
|
||||||
|
'/verify_user',
|
||||||
|
'/verify_transaction',
|
||||||
|
'/phone_code'
|
||||||
|
]
|
||||||
|
|
||||||
const authMiddleware = opts.devMode
|
const app = express()
|
||||||
? (req, res, next) => next()
|
const localApp = express()
|
||||||
: authorize
|
|
||||||
|
|
||||||
const configRequiredRoutes = [
|
app.use(helmet({noCache: true}))
|
||||||
'/poll',
|
app.use(bodyParser.json())
|
||||||
'/trade',
|
app.use(morgan('dev', {skip}))
|
||||||
'/send',
|
|
||||||
'/cash_out',
|
|
||||||
'/dispense_ack',
|
|
||||||
'/event',
|
|
||||||
'/verify_user',
|
|
||||||
'/verify_transaction',
|
|
||||||
'/phone_code'
|
|
||||||
]
|
|
||||||
|
|
||||||
const limiter = new RateLimit({
|
// These two have their own authorization
|
||||||
windowMs: T.minute,
|
app.post('/pair', populateDeviceId, pair)
|
||||||
max: 10,
|
app.get('/ca', ca)
|
||||||
delayMs: 0,
|
|
||||||
delayAfter: 0,
|
app.use(populateDeviceId)
|
||||||
keyGenerator: () => 'everybody'
|
if (!devMode) app.use(authorize)
|
||||||
|
app.use(configRequiredRoutes, populateSettings)
|
||||||
|
app.use(filterOldRequests)
|
||||||
|
app.post('*', cacheAction)
|
||||||
|
|
||||||
|
app.get('/poll', poll)
|
||||||
|
app.post('/trade', trade)
|
||||||
|
app.post('/send', send)
|
||||||
|
app.post('/state', stateChange)
|
||||||
|
app.post('/cash_out', cashOut)
|
||||||
|
app.post('/dispense_ack', dispenseAck)
|
||||||
|
|
||||||
|
app.post('/event', deviceEvent)
|
||||||
|
app.post('/verify_user', verifyUser)
|
||||||
|
app.post('/verify_transaction', verifyTx)
|
||||||
|
|
||||||
|
app.post('/phone_code', phoneCode)
|
||||||
|
app.post('/update_phone', updatePhone)
|
||||||
|
app.get('/phone_tx', fetchPhoneTx)
|
||||||
|
app.post('/register_redeem/:txId', registerRedeem)
|
||||||
|
app.get('/await_dispense/:txId', waitForDispense)
|
||||||
|
app.post('/dispense', dispense)
|
||||||
|
|
||||||
|
app.use(errorHandler)
|
||||||
|
|
||||||
|
localApp.get('/pid', (req, res) => {
|
||||||
|
const deviceId = req.query.device_id
|
||||||
|
const pidRec = pids[deviceId]
|
||||||
|
res.json(pidRec)
|
||||||
|
})
|
||||||
|
|
||||||
|
localApp.post('/reboot', (req, res) => {
|
||||||
|
const pid = req.body.pid
|
||||||
|
const deviceId = req.body.deviceId
|
||||||
|
|
||||||
|
if (!deviceId || !pid) {
|
||||||
|
return res.sendStatus(400)
|
||||||
|
}
|
||||||
|
|
||||||
|
reboots[deviceId] = pid
|
||||||
|
res.sendStatus(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
localApp.post('/dbChange', (req, res, next) => {
|
||||||
|
return settingsLoader.loadLatest()
|
||||||
|
.then(poller.reload)
|
||||||
|
.then(() => logger.info('Config reloaded'))
|
||||||
|
.catch(err => {
|
||||||
|
logger.error(err)
|
||||||
|
res.sendStatus(500)
|
||||||
})
|
})
|
||||||
|
})
|
||||||
app.use(morgan('dev', {skip}))
|
|
||||||
app.use(helmet())
|
|
||||||
app.use(populateDeviceId)
|
|
||||||
app.use(configRequiredRoutes, populateSettings)
|
|
||||||
app.use(bodyParser.json())
|
|
||||||
app.use(filterOldRequests)
|
|
||||||
app.post('*', cacheAction)
|
|
||||||
|
|
||||||
app.post('/pair', limiter, pair)
|
|
||||||
app.get('/ca', limiter, ca)
|
|
||||||
|
|
||||||
app.get('/poll', authMiddleware, poll)
|
|
||||||
|
|
||||||
app.post('/trade', authMiddleware, trade)
|
|
||||||
app.post('/send', authMiddleware, send)
|
|
||||||
app.post('/state', authMiddleware, stateChange)
|
|
||||||
app.post('/cash_out', authMiddleware, cashOut)
|
|
||||||
app.post('/dispense_ack', authMiddleware, dispenseAck)
|
|
||||||
|
|
||||||
app.post('/event', authMiddleware, deviceEvent)
|
|
||||||
app.post('/verify_user', authMiddleware, verifyUser)
|
|
||||||
app.post('/verify_transaction', authMiddleware, verifyTx)
|
|
||||||
|
|
||||||
app.post('/phone_code', authMiddleware, phoneCode)
|
|
||||||
app.post('/update_phone', authMiddleware, updatePhone)
|
|
||||||
app.get('/phone_tx', authMiddleware, fetchPhoneTx)
|
|
||||||
app.post('/register_redeem/:txId', authMiddleware, registerRedeem)
|
|
||||||
app.get('/await_dispense/:txId', authMiddleware, waitForDispense)
|
|
||||||
app.post('/dispense', authMiddleware, dispense)
|
|
||||||
|
|
||||||
app.use('*', errorHandler)
|
|
||||||
|
|
||||||
localApp.get('/pid', (req, res) => {
|
|
||||||
const deviceId = req.query.device_id
|
|
||||||
const pidRec = pids[deviceId]
|
|
||||||
res.json(pidRec)
|
|
||||||
})
|
|
||||||
|
|
||||||
localApp.post('/reboot', (req, res) => {
|
|
||||||
const pid = req.body.pid
|
|
||||||
const deviceId = req.body.deviceId
|
|
||||||
|
|
||||||
if (!deviceId || !pid) {
|
|
||||||
return res.sendStatus(400)
|
|
||||||
}
|
|
||||||
|
|
||||||
reboots[deviceId] = pid
|
|
||||||
res.sendStatus(200)
|
|
||||||
})
|
|
||||||
|
|
||||||
localApp.post('/dbChange', (req, res, next) => {
|
|
||||||
return settingsLoader.loadLatest()
|
|
||||||
.then(poller.reload)
|
|
||||||
.then(() => logger.info('Config reloaded'))
|
|
||||||
.catch(err => {
|
|
||||||
logger.error(err)
|
|
||||||
res.sendStatus(500)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
setInterval(pruneIdempotents, 60000)
|
|
||||||
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
function populateDeviceId (req, res, next) {
|
function populateDeviceId (req, res, next) {
|
||||||
const deviceId = ((typeof req.connection.getPeerCertificate === 'function' &&
|
const deviceId = ((typeof req.connection.getPeerCertificate === 'function' &&
|
||||||
|
|
@ -449,3 +433,7 @@ function populateSettings (req, res, next) {
|
||||||
.then(() => next())
|
.then(() => next())
|
||||||
.catch(next)
|
.catch(next)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setInterval(pruneIdempotents, 60000)
|
||||||
|
|
||||||
|
module.exports = {app, localApp}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
"node-hkdf-sync": "^1.0.0",
|
"node-hkdf-sync": "^1.0.0",
|
||||||
"numeral": "^2.0.1",
|
"numeral": "^2.0.1",
|
||||||
"pg": "^6.1.0",
|
"pg": "^6.1.0",
|
||||||
|
"pg-native": "^1.10.0",
|
||||||
"pg-promise": "^5.4.4",
|
"pg-promise": "^5.4.4",
|
||||||
"pify": "^2.3.0",
|
"pify": "^2.3.0",
|
||||||
"pretty-ms": "^2.1.0",
|
"pretty-ms": "^2.1.0",
|
||||||
|
|
|
||||||
32
yarn.lock
32
yarn.lock
|
|
@ -192,7 +192,7 @@ bignumber.js@^3.0.0, bignumber.js@^3.0.1:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-3.0.1.tgz#807652d10e39de37e9e3497247edc798bb746f76"
|
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-3.0.1.tgz#807652d10e39de37e9e3497247edc798bb746f76"
|
||||||
|
|
||||||
bindings@^1.2.1:
|
bindings@1.2.1, bindings@^1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11"
|
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11"
|
||||||
|
|
||||||
|
|
@ -1480,6 +1480,13 @@ levn@~0.3.0:
|
||||||
prelude-ls "~1.1.2"
|
prelude-ls "~1.1.2"
|
||||||
type-check "~0.3.2"
|
type-check "~0.3.2"
|
||||||
|
|
||||||
|
libpq@^1.7.0:
|
||||||
|
version "1.8.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/libpq/-/libpq-1.8.5.tgz#9ef5bb509e1658908c19474088031db3dc7d4e48"
|
||||||
|
dependencies:
|
||||||
|
bindings "1.2.1"
|
||||||
|
nan "^2.3.0"
|
||||||
|
|
||||||
load-json-file@^1.0.0:
|
load-json-file@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
|
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
|
||||||
|
|
@ -1641,7 +1648,7 @@ ms@0.7.2, ms@^0.7.1:
|
||||||
version "0.7.2"
|
version "0.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
|
||||||
|
|
||||||
nan@^2.0.5, nan@^2.2.0:
|
nan@^2.0.5, nan@^2.2.0, nan@^2.3.0:
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232"
|
resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232"
|
||||||
|
|
||||||
|
|
@ -1843,6 +1850,14 @@ pg-minify@0.4:
|
||||||
version "0.4.1"
|
version "0.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/pg-minify/-/pg-minify-0.4.1.tgz#a642c6bd256c7da833066590b1e414334a1f6e19"
|
resolved "https://registry.yarnpkg.com/pg-minify/-/pg-minify-0.4.1.tgz#a642c6bd256c7da833066590b1e414334a1f6e19"
|
||||||
|
|
||||||
|
pg-native@^1.10.0:
|
||||||
|
version "1.10.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/pg-native/-/pg-native-1.10.0.tgz#abe299214afa2be51db5f5104e14770c738230fd"
|
||||||
|
dependencies:
|
||||||
|
libpq "^1.7.0"
|
||||||
|
pg-types "1.6.0"
|
||||||
|
readable-stream "1.0.31"
|
||||||
|
|
||||||
pg-pool@1.*:
|
pg-pool@1.*:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-1.6.0.tgz#2e300199927b6d7db6be71e2e3435dddddf07b41"
|
resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-1.6.0.tgz#2e300199927b6d7db6be71e2e3435dddddf07b41"
|
||||||
|
|
@ -1869,6 +1884,10 @@ pg-types@1.*:
|
||||||
postgres-date "~1.0.0"
|
postgres-date "~1.0.0"
|
||||||
postgres-interval "~1.0.0"
|
postgres-interval "~1.0.0"
|
||||||
|
|
||||||
|
pg-types@1.6.0:
|
||||||
|
version "1.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-1.6.0.tgz#3872a0f199143025497f4ee2a65fdaf00d7ea8b3"
|
||||||
|
|
||||||
pg@5.1:
|
pg@5.1:
|
||||||
version "5.1.0"
|
version "5.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/pg/-/pg-5.1.0.tgz#073b9b36763ad8a5478dbb85effef45e739ba9d8"
|
resolved "https://registry.yarnpkg.com/pg/-/pg-5.1.0.tgz#073b9b36763ad8a5478dbb85effef45e739ba9d8"
|
||||||
|
|
@ -2061,6 +2080,15 @@ readable-stream@1.0.27-1:
|
||||||
isarray "0.0.1"
|
isarray "0.0.1"
|
||||||
string_decoder "~0.10.x"
|
string_decoder "~0.10.x"
|
||||||
|
|
||||||
|
readable-stream@1.0.31:
|
||||||
|
version "1.0.31"
|
||||||
|
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.31.tgz#8f2502e0bc9e3b0da1b94520aabb4e2603ecafae"
|
||||||
|
dependencies:
|
||||||
|
core-util-is "~1.0.0"
|
||||||
|
inherits "~2.0.1"
|
||||||
|
isarray "0.0.1"
|
||||||
|
string_decoder "~0.10.x"
|
||||||
|
|
||||||
readable-stream@1.1.x:
|
readable-stream@1.1.x:
|
||||||
version "1.1.14"
|
version "1.1.14"
|
||||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
|
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue