Comparing version 1.0.6 to 1.0.8
@@ -38,4 +38,5 @@ //Low level connection to PostgreSQL database | ||
this.connecting = false | ||
if (this.config.listen && !Array.isArray(this.config.listen)) this.config.listen = [this.config.listen] | ||
if (this.config.listen) this.connect(() => { //Connect now so we can listen | ||
if (conf.listen && !Array.isArray(conf.listen)) conf.listen = [conf.listen] | ||
if (conf.listen) this.connect(() => { //Connect now so we can listen | ||
let q; while (q = this.queryQue.shift()) this.query(...q) //And process the queue | ||
@@ -42,0 +43,0 @@ if (this.connectCB) this.connectCB() |
@@ -18,13 +18,83 @@ //Manage the connection between a User Interface and the backend database | ||
const Ws = require('ws') //Web sockets | ||
const Https = require('https') | ||
const Http = require('http') | ||
const Url = require('url') | ||
const Format = require('pg-format') //String formatting/escaping | ||
const Base64 = require('base64-js') | ||
const Crypto = require('crypto') | ||
const Opers = ['=', '!=', '<', '<=', '>', '>=', '~', 'diff', 'in', 'null', 'true'] | ||
const PemHeader = "-----BEGIN PUBLIC KEY-----\n" | ||
const PemFooter = "\n-----END PUBLIC KEY-----" | ||
const VerifyTpt = { | ||
padding: Crypto.constants.RSA_PKCS1_PSS_PADDING, | ||
saltLength: 128 | ||
} | ||
module.exports = class Wyseman { | ||
constructor(dbConf, wsConf) { | ||
let wss = new Ws.Server({ //Initiate a new websocket connection | ||
port: wsConf.port, clientTracking: true | ||
}) | ||
constructor(dbConf, wsConf, adminConf) { | ||
let { port, credentials, actionHandler, expApp} = wsConf | ||
, ctx = {db:null, control:null, actionHandler, expApp} | ||
, log = this.log = dbConf.log || ctx.db.log || console.log | ||
, server = credentials ? Https.createServer(credentials) : Http.createServer() | ||
, adminDB = new DbClient(adminConf) //Admin access to the DB | ||
, validateToken = (user, token, pub, cb) => { //Validate user with one-time login token | ||
log.trace("Request to validate:", user) | ||
adminDB.query('select base.validate_token($1,$2,$3) as valid', [user, sign||token, pub], (err, res)=>{ | ||
if (err) log.error("Error validating user:", user, token, err) | ||
let valid = (!err && res && res.rows && res.rows.length >= 1) ? res.rows[0].valid : false | ||
if (valid) dbConf.user = user //Tell later db connect our username | ||
log.debug(" valid result:", valid) | ||
cb(valid) | ||
}) | ||
} | ||
, validateSignature = (user, sign, message, cb) => { //Validate a user with an existing key | ||
log.trace("Validate:", user, sign, message) | ||
adminDB.query('select conn_pub from base.ent_v where username = $1', [user], (err, res)=>{ | ||
if (err) log.error("Error getting user connection key:", user, err) | ||
let pubKey = (!err && res && res.rows && res.rows.length >= 1) ? res.rows[0].conn_pub : null | ||
, rawKey = Buffer.from(pubKey, 'hex') | ||
, rawSig = Buffer.from(sign, 'hex') | ||
, key = PemHeader + Base64.fromByteArray(rawKey) + PemFooter | ||
, verify = Crypto.createVerify('SHA256') | ||
log.trace(" user public:", user, key) | ||
verify.update(message) | ||
let valid = verify.verify(Object.assign({key}, VerifyTpt), rawSig) | ||
if (valid) dbConf.user = user //Tell later db connect our username | ||
log.trace(" valid:", valid) | ||
cb(valid) | ||
}) | ||
} | ||
, wss = new Ws.Server({ //Initiate a new websocket connection | ||
server, | ||
clientTracking: true, | ||
verifyClient: function(info, cb) { | ||
let { origin, req, secure } = info | ||
, query = Url.parse(req.url, true).query | ||
, { user, sign, date, token, pub } = query | ||
log.trace("Checking client:", origin, "cb:", !!cb, "q:", query, "s:", secure, "IP:", req.connection.remoteAddress) | ||
if (user && token && pub) | ||
validateToken(user, token, pub, (valid)=>{ | ||
cb(valid, 403, 'Invalid Login') //Tell websocket whether or not to connect | ||
}) | ||
else if (user && sign && date) { | ||
let message = JSON.stringify({ip: req.connection.remoteAddress, cookie: req.headers.cookie, userAgent: req.headers['user-agent'], date}) | ||
, now = new Date() | ||
, msgDate = new Date(date) | ||
log.trace("Check dates:", now, msgDate, "Time delta:", now - msgDate) | ||
validateSignature(user, sign, message, (valid)=>{ | ||
cb(valid, 403, 'Invalid Login') //Tell websocket whether or not to connect | ||
}) | ||
} else if (user && !secure) { | ||
cb(true) //On an insecure/debug web connection | ||
} else | ||
cb(false, 403, 'No login credentials') //tell websocket not to connect | ||
}, | ||
}) | ||
server.listen(port) | ||
wss.on('connection', (ws) => { //When connection from view is open | ||
let ctx = {db:null, control:null, wsConf} | ||
if (!dbConf.user) return //Shouldn't be able to get here without a username | ||
log.trace("DB Connect::", dbConf.user, dbConf) | ||
ctx.db = new DbClient(dbConf, (channel, message, mine) => { | ||
@@ -37,4 +107,3 @@ let data = JSON.parse(message) | ||
}) | ||
this.log = dbConf.logger || ctx.db.log | ||
this.log.trace("In Wyseman constructor conf:", JSON.stringify(dbConf), " Client port:", wsConf.port) | ||
this.log.trace("Wyseman connection conf:", "Client port:", port) | ||
@@ -50,3 +119,3 @@ ws.on('close', (code, reason) => { | ||
this.handler(packet, ctx, (omsg) => { //Handle/control an incoming packet | ||
this.handler(packet, ctx, (omsg) => { //Handle/control an incoming packet | ||
let jmsg = JSON.stringify(omsg) | ||
@@ -123,4 +192,4 @@ //this.log.trace('Sending back:', JSON.stringify(omsg, null, 2)) | ||
default: | ||
if (!ctx.control && ctx.wsConf && ctx.wsConf.actionHandler) | ||
ctx.control = new ctx.wsConf.actionHandler(ctx.wsConf.expApp) //Start a controller just in time | ||
if (!ctx.control && ctx.actionHandler) | ||
ctx.control = new ctx.actionHandler(ctx.expApp, ctx.db) //Start a controller just in time | ||
if (ctx.control && ctx.control.handle && ctx.control.handle(msg, sender)) return | ||
@@ -210,3 +279,3 @@ result.error = this.error('unknown action: ' + action, 'badAction') | ||
if (flist.length <= 0) { | ||
res.error = this.error("empty update", badUpdate); return null | ||
res.error = this.error("empty update", "badUpdate"); return null | ||
} | ||
@@ -213,0 +282,0 @@ res.query = Format('update %s set %s where %s returning *;', table, flist.join(', '), wh) |
{ | ||
"name": "wyseman", | ||
"version": "1.0.6", | ||
"version": "1.0.8", | ||
"description": "PostgreSQL Schema Manager with Javascript, Ruby, TCL API", | ||
@@ -24,2 +24,3 @@ "main": "lib/index.js", | ||
"erd": "bin/erd", | ||
"ticket": "bin/ticket", | ||
"wyseman": "bin/wyseman", | ||
@@ -29,2 +30,3 @@ "wysegi": "bin/wysegi" | ||
"dependencies": { | ||
"base64-js": "^1.3.0", | ||
"pg": "^7.5.0", | ||
@@ -31,0 +33,0 @@ "pg-format": "^1.0.4", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
614911
68
590
4
2
+ Addedbase64-js@^1.3.0
+ Addedbase64-js@1.5.1(transitive)