Update Node_modules

This commit is contained in:
2019-07-02 16:05:15 +02:00
parent 95a0ff3913
commit 9dab5e2dbc
3495 changed files with 39728 additions and 465154 deletions
+154
View File
@@ -0,0 +1,154 @@
'use strict'
class Crypto {
init(options) {
this.crypto = require('crypto')
this.algorithm = options.algorithm || 'aes-256-gcm'
this.hashing = options.hashing || 'sha512'
this.encodeas = options.encodeas || 'hex'
this.iv_size = options.iv_size || 16
this.at_size = options.at_size || 16
this.key_size = options.key_size || 32
this.secret = this._deriveKey(options.secret) || false
}
set(plaintext) {
const iv = this.crypto.randomBytes(this.iv_size).toString(this.encodeas)
const aad = this._digest(
iv + this.secret,
JSON.stringify(plaintext),
this.hashing,
this.encodeas
)
const ct = this._encrypt(
this.secret,
JSON.stringify(plaintext),
this.algorithm,
this.encodeas,
iv,
aad
)
const hmac = this._digest(this.secret, ct.ct, this.hashing, this.encodeas)
const obj = JSON.stringify({
hmac,
ct: ct.ct,
at: ct.at,
aad,
iv,
})
return obj
}
get(ciphertext) {
let ct
if (ciphertext) {
try {
ct = JSON.parse(ciphertext)
} catch (err) {
ct = ciphertext
}
}
const hmac = this._digest(this.secret, ct.ct, this.hashing, this.encodeas)
if (hmac !== ct.hmac) {
throw new Error('Encrypted session was tampered with!')
}
if (ct.at) {
ct.at = Buffer.from(ct.at)
}
const pt = this._decrypt(
this.secret,
ct.ct,
this.algorithm,
this.encodeas,
ct.iv,
ct.at,
ct.aad
)
return pt
}
_digest(key, obj, hashing, encodeas) {
const hmac = this.crypto.createHmac(this.hashing, key)
hmac.setEncoding(encodeas)
hmac.write(obj)
hmac.end()
return hmac.read().toString(encodeas)
}
_encrypt(key, pt, algo, encodeas, iv, aad) {
const cipher = this.crypto.createCipheriv(algo, key, iv, {
authTagLength: this.at_size,
})
let ct
let at
if (aad) {
try {
cipher.setAAD(Buffer.from(aad), {
plaintextLength: Buffer.byteLength(pt),
})
} catch (err) {
throw err
}
}
ct = cipher.update(pt, 'utf8', encodeas)
ct += cipher.final(encodeas)
try {
at = cipher.getAuthTag()
} catch (err) {
throw err
}
return at ? { ct, at } : { ct }
}
_decrypt(key, ct, algo, encodeas, iv, at, aad) {
const cipher = this.crypto.createDecipheriv(algo, key, iv)
let pt
if (at) {
try {
cipher.setAuthTag(Buffer.from(at))
} catch (err) {
throw err
}
}
if (aad) {
try {
cipher.setAAD(Buffer.from(aad), {
plaintextLength: Buffer.byteLength(ct),
})
} catch (err) {
throw err
}
}
pt = cipher.update(ct, encodeas, 'utf8')
pt += cipher.final('utf8')
return pt
}
_deriveKey(secret) {
const hash = this.crypto.createHash(this.hashing)
hash.update(secret)
const salt = hash.digest(this.encodeas).substr(0, 16)
const key = this.crypto.pbkdf2Sync(secret, salt, 10000, 64, this.hashing)
return key.toString(this.encodeas).substr(0, this.key_size)
}
}
module.exports = new Crypto()
+216 -99
View File
@@ -6,9 +6,7 @@ function withCallback(promise, cb) {
// Assume that cb is a function - type checks and handling type errors
// can be done by caller
if (cb) {
promise
.then(res => cb(null, res))
.catch(cb)
promise.then(res => cb(null, res)).catch(cb)
}
return promise
}
@@ -22,7 +20,9 @@ function defaultSerializeFunction(session) {
if (prop === 'cookie') {
// Convert the cookie instance to an object, if possible
// This gets rid of the duplicate object under session.cookie.data property
obj.cookie = session.cookie.toJSON ? session.cookie.toJSON() : session.cookie
obj.cookie = session.cookie.toJSON
? session.cookie.toJSON()
: session.cookie
} else {
obj[prop] = session[prop]
}
@@ -31,30 +31,28 @@ function defaultSerializeFunction(session) {
return obj
}
function computeTransformFunctions(options, defaultStringify) {
function computeTransformFunctions(options) {
if (options.serialize || options.unserialize) {
return {
serialize: options.serialize || defaultSerializeFunction,
unserialize: options.unserialize || (x => x)
unserialize: options.unserialize || (x => x),
}
}
if (options.stringify === false || defaultStringify === false) {
if (options.stringify === false) {
return {
serialize: defaultSerializeFunction,
unserialize: x => x
unserialize: x => x,
}
}
if (options.stringify === true || defaultStringify === true) {
return {
serialize: JSON.stringify,
unserialize: JSON.parse
}
// Default case
return {
serialize: JSON.stringify,
unserialize: JSON.parse,
}
}
module.exports = function (connect) {
module.exports = function(connect) {
const Store = connect.Store || connect.session.Store
const MemoryStore = connect.MemoryStore || connect.session.MemoryStore
@@ -69,45 +67,63 @@ module.exports = function (connect) {
super(options)
/* Use crypto? */
if (options.secret) {
try {
this.Crypto = require('./crypto.js')
this.Crypto.init(options)
delete options.secret
} catch (error) {
throw error
}
}
/* Options */
this.ttl = options.ttl || 1209600 // 14 days
this.collectionName = options.collection || 'sessions'
this.autoRemove = options.autoRemove || 'native'
this.autoRemoveInterval = options.autoRemoveInterval || 10
this.transformFunctions = computeTransformFunctions(options, true)
this.autoRemoveInterval = options.autoRemoveInterval || 10 // Minutes
this.writeOperationOptions = options.writeOperationOptions || {}
this.transformFunctions = computeTransformFunctions(options)
this.options = options
this.changeState('init')
const newConnectionCallback = (err, db) => {
const newConnectionCallback = (err, client) => {
if (err) {
this.connectionFailed(err)
} else {
this.handleNewConnectionAsync(db)
this.handleNewConnectionAsync(client)
}
}
if (options.url) {
// New native connection using url + mongoOptions
MongoClient.connect(options.url, options.mongoOptions || {}, newConnectionCallback)
const _options = options.mongoOptions || {}
if (typeof _options.useNewUrlParser !== 'boolean') {
_options.useNewUrlParser = true
}
MongoClient.connect(options.url, _options, newConnectionCallback)
} else if (options.mongooseConnection) {
// Re-use existing or upcoming mongoose connection
if (options.mongooseConnection.readyState === 1) {
this.handleNewConnectionAsync(options.mongooseConnection.db)
this.handleNewConnectionAsync(options.mongooseConnection)
} else {
options.mongooseConnection.once('open', () => this.handleNewConnectionAsync(options.mongooseConnection.db))
options.mongooseConnection.once('open', () =>
this.handleNewConnectionAsync(options.mongooseConnection)
)
}
} else if (options.db && options.db.listCollections) {
// Re-use existing or upcoming native connection
if (options.db.openCalled || options.db.openCalled === undefined) { // OpenCalled is undefined in mongodb@2.x
this.handleNewConnectionAsync(options.db)
} else if (options.client) {
if (options.client.isConnected()) {
this.handleNewConnectionAsync(options.client)
} else {
options.db.open(newConnectionCallback)
options.client.once('open', () =>
this.handleNewConnectionAsync(options.client)
)
}
} else if (options.dbPromise) {
options.dbPromise
.then(db => this.handleNewConnectionAsync(db))
} else if (options.clientPromise) {
options.clientPromise
.then(client => this.handleNewConnectionAsync(client))
.catch(err => this.connectionFailed(err))
} else {
throw new Error('Connection strategy not found')
@@ -121,23 +137,36 @@ module.exports = function (connect) {
throw err
}
handleNewConnectionAsync(db) {
this.db = db
return this
.setCollection(db.collection(this.collectionName))
handleNewConnectionAsync(client) {
this.client = client
this.db = typeof client.db !== 'function' ? client.db : client.db()
return this.setCollection(this.db.collection(this.collectionName))
.setAutoRemoveAsync()
.then(() => this.changeState('connected'))
}
setAutoRemoveAsync() {
const removeQuery = () => {
return {expires: {$lt: new Date()}}
return { expires: { $lt: new Date() } }
}
switch (this.autoRemove) {
case 'native':
return this.collection.createIndex({expires: 1}, {expireAfterSeconds: 0})
return this.collection.createIndex(
{ expires: 1 },
Object.assign({ expireAfterSeconds: 0 }, this.writeOperationOptions)
)
case 'interval':
this.timer = setInterval(() => this.collection.remove(removeQuery(), {w: 0}), this.autoRemoveInterval * 1000 * 60)
this.timer = setInterval(
() =>
this.collection.deleteMany(
removeQuery(),
Object.assign({}, this.writeOperationOptions, {
w: 0,
j: false,
})
),
this.autoRemoveInterval * 1000 * 60
)
this.timer.unref()
return Promise.resolve()
default:
@@ -180,7 +209,10 @@ module.exports = function (connect) {
}
computeStorageId(sessionId) {
if (this.options.transformId && typeof this.options.transformId === 'function') {
if (
this.options.transformId &&
typeof this.options.transformId === 'function'
) {
return this.options.transformId(sessionId)
}
return sessionId
@@ -189,25 +221,35 @@ module.exports = function (connect) {
/* Public API */
get(sid, callback) {
return withCallback(this.collectionReady()
.then(collection => collection.findOne({
_id: this.computeStorageId(sid),
$or: [
{expires: {$exists: false}},
{expires: {$gt: new Date()}}
]
}))
.then(session => {
if (session) {
const s = this.transformFunctions.unserialize(session.session)
if (this.options.touchAfter > 0 && session.lastModified) {
s.lastModified = session.lastModified
return withCallback(
this.collectionReady()
.then(collection =>
collection.findOne({
_id: this.computeStorageId(sid),
$or: [
{ expires: { $exists: false } },
{ expires: { $gt: new Date() } },
],
})
)
.then(session => {
if (session) {
if (this.Crypto) {
const tmpSession = this.transformFunctions.unserialize(
session.session
)
session.session = this.Crypto.get(tmpSession)
}
const s = this.transformFunctions.unserialize(session.session)
if (this.options.touchAfter > 0 && session.lastModified) {
s.lastModified = session.lastModified
}
this.emit('get', sid)
return s
}
this.emit('get', sid)
return s
}
})
, callback)
}),
callback
)
}
set(sid, session, callback) {
@@ -218,10 +260,21 @@ module.exports = function (connect) {
let s
if (this.Crypto) {
try {
session = this.Crypto.set(session)
} catch (error) {
return withCallback(Promise.reject(error), callback)
}
}
try {
s = {_id: this.computeStorageId(sid), session: this.transformFunctions.serialize(session)}
s = {
_id: this.computeStorageId(sid),
session: this.transformFunctions.serialize(session),
}
} catch (err) {
return callback(err)
return withCallback(Promise.reject(err), callback)
}
if (session && session.cookie && session.cookie.expires) {
@@ -234,33 +287,43 @@ module.exports = function (connect) {
// So we set the expiration to two-weeks from now
// - as is common practice in the industry (e.g Django) -
// or the default specified in the options.
s.expires = new Date(Date.now() + (this.ttl * 1000))
s.expires = new Date(Date.now() + this.ttl * 1000)
}
if (this.options.touchAfter > 0) {
s.lastModified = new Date()
}
return withCallback(this.collectionReady()
.then(collection => collection.updateOne({_id: this.computeStorageId(sid)}, {$set: s}, {upsert: true}))
.then(rawResponse => {
if (rawResponse.result) {
rawResponse = rawResponse.result
}
if (rawResponse && rawResponse.upserted) {
this.emit('create', sid)
} else {
this.emit('update', sid)
}
this.emit('set', sid)
})
, callback)
return withCallback(
this.collectionReady()
.then(collection =>
collection.updateOne(
{ _id: this.computeStorageId(sid) },
{ $set: s },
Object.assign({ upsert: true }, this.writeOperationOptions)
)
)
.then(rawResponse => {
if (rawResponse.result) {
rawResponse = rawResponse.result
}
if (rawResponse && rawResponse.upserted) {
this.emit('create', sid)
} else {
this.emit('update', sid)
}
this.emit('set', sid)
}),
callback
)
}
touch(sid, session, callback) {
const updateFields = {}
const touchAfter = this.options.touchAfter * 1000
const lastModified = session.lastModified ? session.lastModified.getTime() : 0
const lastModified = session.lastModified
? session.lastModified.getTime()
: 0
const currentDate = new Date()
// If the given options has a touchAfter property, check if the
@@ -270,7 +333,7 @@ module.exports = function (connect) {
const timeElapsed = currentDate.getTime() - session.lastModified
if (timeElapsed < touchAfter) {
return callback()
return withCallback(Promise.resolve(), callback)
}
updateFields.lastModified = currentDate
}
@@ -278,43 +341,97 @@ module.exports = function (connect) {
if (session && session.cookie && session.cookie.expires) {
updateFields.expires = new Date(session.cookie.expires)
} else {
updateFields.expires = new Date(Date.now() + (this.ttl * 1000))
updateFields.expires = new Date(Date.now() + this.ttl * 1000)
}
return withCallback(this.collectionReady()
.then(collection => collection.updateOne({_id: this.computeStorageId(sid)}, {$set: updateFields}))
.then(result => {
if (result.nModified === 0) {
throw new Error('Unable to find the session to touch')
} else {
this.emit('touch', sid, session)
}
})
, callback)
return withCallback(
this.collectionReady()
.then(collection =>
collection.updateOne(
{ _id: this.computeStorageId(sid) },
{ $set: updateFields },
this.writeOperationOptions
)
)
.then(result => {
if (result.nModified === 0) {
throw new Error('Unable to find the session to touch')
} else {
this.emit('touch', sid, session)
}
}),
callback
)
}
all(callback) {
return withCallback(
this.collectionReady()
.then(collection =>
collection.find({
$or: [
{ expires: { $exists: false } },
{ expires: { $gt: new Date() } },
],
})
)
.then(sessions => {
return new Promise((resolve, reject) => {
const results = []
sessions.forEach(
session =>
results.push(
this.transformFunctions.unserialize(session.session)
),
err => {
if (err) {
reject(err)
}
this.emit('all', results)
resolve(results)
}
)
})
}),
callback
)
}
destroy(sid, callback) {
return withCallback(this.collectionReady()
.then(collection => collection.deleteOne({_id: this.computeStorageId(sid)}))
.then(() => this.emit('destroy', sid))
, callback)
return withCallback(
this.collectionReady()
.then(collection =>
collection.deleteOne(
{ _id: this.computeStorageId(sid) },
this.writeOperationOptions
)
)
.then(() => this.emit('destroy', sid)),
callback
)
}
length(callback) {
return withCallback(this.collectionReady()
.then(collection => collection.count({}))
, callback)
return withCallback(
this.collectionReady().then(collection =>
collection.countDocuments({})
),
callback
)
}
clear(callback) {
return withCallback(this.collectionReady()
.then(collection => collection.drop())
, callback)
return withCallback(
this.collectionReady().then(collection =>
collection.drop(this.writeOperationOptions)
),
callback
)
}
close() {
if (this.db) {
this.db.close()
if (this.client) {
return this.client.close()
}
}
}