Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
// do not use destructuring or it will deopt
const split = cookie.split(';')
const cyphertextB64 = split[0]
const nonceB64 = split[1]
if (split.length <= 1) {
// the cookie is malformed
request.session = new Session({})
next()
return
}
const cipher = Buffer.from(cyphertextB64, 'base64')
const nonce = Buffer.from(nonceB64, 'base64')
if (cipher.length < sodium.crypto_secretbox_MACBYTES) {
// not long enough
request.session = new Session({})
next()
return
}
const msg = Buffer.allocUnsafe(cipher.length - sodium.crypto_secretbox_MACBYTES)
if (!sodium.crypto_secretbox_open_easy(msg, cipher, nonce, key)) {
// unable to decrypt
request.session = new Session({})
next()
return
}
request.session = new Session(JSON.parse(msg))
next()
async init (size) {
await super.init(size)
// Create sodium buffer
this._alignSize = Math.ceil(size / 8) * 8
this._b = sodium.sodium_malloc(this._alignSize)
// lock it
sodium.sodium_mprotect_noaccess(this._b)
// Destructor: Clear buffer memory
this.$pushDestructor(() => {
// normally sodium free would clear the buffer...
// but since we're waiting for js gc, let's clear it now
sodium.sodium_mprotect_readwrite(this._b)
this._b.fill(0)
sodium.sodium_mprotect_noaccess(this._b)
this._b = null
})
}
async init (size) {
await super.init(size)
this._alignSize = Math.ceil(size / 8) * 8
this._b = sodium.sodium_malloc(this._alignSize)
sodium.sodium_mprotect_noaccess(this._b)
this.$pushDestructor(() => {
// normally sodium free would clear the buffer...
// but since we're waiting for js gc, let's clear it now
sodium.sodium_mprotect_readwrite(this._b)
this._b.fill(0)
sodium.sodium_mprotect_noaccess(this._b)
this._b = null
})
}
async init (size) {
await super.init(size)
this._alignSize = Math.ceil(size / 8) * 8
this._b = sodium.sodium_malloc(this._alignSize)
sodium.sodium_mprotect_noaccess(this._b)
this.$pushDestructor(() => {
// normally sodium free would clear the buffer...
// but since we're waiting for js gc, let's clear it now
sodium.sodium_mprotect_readwrite(this._b)
this._b.fill(0)
sodium.sodium_mprotect_noaccess(this._b)
this._b = null
})
}
async init (size) {
await super.init(size)
// Create sodium buffer
this._alignSize = Math.ceil(size / 8) * 8
this._b = sodium.sodium_malloc(this._alignSize)
// lock it
sodium.sodium_mprotect_noaccess(this._b)
// Destructor: Clear buffer memory
this.$pushDestructor(() => {
// normally sodium free would clear the buffer...
// but since we're waiting for js gc, let's clear it now
sodium.sodium_mprotect_readwrite(this._b)
this._b.fill(0)
sodium.sodium_mprotect_noaccess(this._b)
this._b = null
})
}
export function vaultToHexString(organizationVaultSecret: string, vault: Vault): string {
const vaultString = JSON.stringify(vault);
const plaintextBuffer = Buffer.from(vaultString);
// The nonce/salt will be prepended to the ciphertext:
const dataBuffer = Buffer.alloc(
sodium.crypto_secretbox_NONCEBYTES + sodium.crypto_secretbox_MACBYTES + vaultString.length,
);
// A new nonce/salt is used every time the vault is updated:
const nonceBuffer = dataBuffer.slice(0, sodium.crypto_secretbox_NONCEBYTES);
sodium.randombytes_buf(nonceBuffer);
const keyBuffer = toKeyBuffer(organizationVaultSecret);
const cipherBuffer = dataBuffer.slice(sodium.crypto_secretbox_NONCEBYTES);
sodium.crypto_secretbox_easy(cipherBuffer, plaintextBuffer, nonceBuffer, keyBuffer);
return dataBuffer.toString("hex");
}
salt,
sodium.crypto_pwhash_OPSLIMIT_MODERATE,
sodium.crypto_pwhash_MEMLIMIT_MODERATE,
sodium.crypto_pwhash_ALG_DEFAULT)
}
if (options.key) {
key = options.key
if (typeof key === 'string') {
key = Buffer.from(key, 'base64')
} else if (!(key instanceof Buffer)) {
return next(new Error('key must be a string or a Buffer'))
}
if (key.length < sodium.crypto_secretbox_KEYBYTES) {
return next(new Error(`key must be at least ${sodium.crypto_secretbox_KEYBYTES} bytes`))
}
}
if (!key) {
return next(new Error('key or secret must specified'))
}
const cookieName = options.cookieName || 'session'
const cookieOptions = options.cookieOptions || options.cookie || {}
// just to add something to the shape
// TODO verify if it helps the perf
fastify.decorateRequest('session', null)
fastify
.register(require('fastify-cookie'))
Buffer.from(options.secret),
salt,
sodium.crypto_pwhash_OPSLIMIT_MODERATE,
sodium.crypto_pwhash_MEMLIMIT_MODERATE,
sodium.crypto_pwhash_ALG_DEFAULT)
}
if (options.key) {
key = options.key
if (typeof key === 'string') {
key = Buffer.from(key, 'base64')
} else if (!(key instanceof Buffer)) {
return next(new Error('key must be a string or a Buffer'))
}
if (key.length < sodium.crypto_secretbox_KEYBYTES) {
return next(new Error(`key must be at least ${sodium.crypto_secretbox_KEYBYTES} bytes`))
}
}
if (!key) {
return next(new Error('key or secret must specified'))
}
const cookieName = options.cookieName || 'session'
const cookieOptions = options.cookieOptions || options.cookie || {}
// just to add something to the shape
// TODO verify if it helps the perf
fastify.decorateRequest('session', null)
fastify
export function vaultFromHexString(organizationVaultSecret: string, dataHexString: string): Vault {
// The nonce/salt is prepended to the actual ciphertext:
const dataBuffer = Buffer.from(dataHexString, "hex");
const nonceBuffer = dataBuffer.slice(0, sodium.crypto_secretbox_NONCEBYTES);
const cipherBuffer = dataBuffer.slice(sodium.crypto_secretbox_NONCEBYTES);
const keyBuffer = toKeyBuffer(organizationVaultSecret);
const plaintextBuffer = Buffer.alloc(cipherBuffer.length - sodium.crypto_secretbox_MACBYTES);
if (!sodium.crypto_secretbox_open_easy(plaintextBuffer, cipherBuffer, nonceBuffer, keyBuffer)) {
throw Error("Vault decryption failed!");
}
const vaultString = plaintextBuffer.toString();
const vault: Vault = JSON.parse(vaultString);
return vault;
}
export function encrypt(organizationSecret: string, plaintext: string): string {
const plaintextBuffer = Buffer.from(plaintext);
// The nonce/salt will be prepended to the ciphertext:
const dataBuffer = Buffer.alloc(
sodium.crypto_secretbox_NONCEBYTES + sodium.crypto_secretbox_MACBYTES + plaintextBuffer.length,
);
// A new nonce/salt is used every time the vault is updated:
const nonceBuffer = dataBuffer.slice(0, sodium.crypto_secretbox_NONCEBYTES);
sodium.randombytes_buf(nonceBuffer);
const keyBuffer = toKeyBuffer(organizationSecret);
const cipherBuffer = dataBuffer.slice(sodium.crypto_secretbox_NONCEBYTES);
sodium.crypto_secretbox_easy(cipherBuffer, plaintextBuffer, nonceBuffer, keyBuffer);
return dataBuffer.toString("hex");
}