Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@neoskop/ethereal-secrets-middleware

Package Overview
Dependencies
Maintainers
3
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@neoskop/ethereal-secrets-middleware - npm Package Compare versions

Comparing version 1.2.2 to 1.2.3

dist/tsconfig.tsbuildinfo

5

dist/index.d.ts

@@ -1,4 +0,3 @@

/// <reference types="connect-redis" />
import { RedisStoreOptions } from 'connect-redis';
import { NextFunction, Request, Response } from "express-serve-static-core";
import { NextFunction, Request, Response } from 'express-serve-static-core';
export interface EtherealSecretsConfig {

@@ -11,3 +10,3 @@ local?: {

path?: string;
sameSite?: any;
sameSite?: boolean | 'lax' | 'strict' | 'none';
};

@@ -14,0 +13,0 @@ ttl?: number;

107

dist/index.js
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const session = require("express-session");
const UuidStatic = require("uuid");
const bodyParser = require("body-parser");
const RedisStore = require("connect-redis");
const crypto = require("crypto");
const deepmerge = require("deepmerge");
const IORedis = require("ioredis");
const Validator = require("validator");
const IORedis = require("ioredis");
const bodyParser = require("body-parser");
const deepmerge = require("deepmerge");
let parseUuid = function (req, res, uuidConsumer) {
let requestUuid = req.path.replace(/^\/|\/$/g, '');
if (Validator.isUUID(requestUuid)) {
const parseUuid = (req, res, uuidConsumer) => {
const requestUuid = req.path.replace(/^\/|\/$/g, '');
if (Validator.default.isUUID(requestUuid)) {
uuidConsumer(requestUuid);

@@ -28,3 +20,3 @@ }

};
let handleLocalEncryption = function (sessionHandler, req, res) {
const handleLocalEncryption = (sessionHandler, req, res) => {
sessionHandler(req, res, () => {

@@ -35,39 +27,38 @@ if (!req.session.key) {

res.json({
key: req.session.key
key: req.session.key,
});
});
};
let readRemotelyEncrypted = function (redisClient, uuid, res) {
return __awaiter(this, void 0, void 0, function* () {
let key = "remote:" + uuid;
let data = yield redisClient.get(key);
if (data == null) {
res.sendStatus(404);
const readRemotelyEncrypted = async (redisClient, uuid, res) => {
const key = 'remote:' + uuid;
const data = await redisClient.get(key);
if (data == null) {
res.sendStatus(404);
}
else {
const ttl = await redisClient.ttl(key);
if (ttl < 0) {
res.sendStatus(500);
}
else {
let ttl = yield redisClient.ttl(key);
if (ttl < 0) {
res.sendStatus(500);
}
else {
let expiryDate = new Date();
expiryDate.setSeconds(expiryDate.getSeconds() + ttl);
res.json({
data: data,
expiryDate: expiryDate.toUTCString()
});
}
const expiryDate = new Date();
expiryDate.setSeconds(expiryDate.getSeconds() + ttl);
res.json({
data: data,
expiryDate: expiryDate.toUTCString(),
});
}
});
}
};
let createRemotelyEncrypted = function (req, res, redisClient, config) {
const createRemotelyEncrypted = function (req, res, redisClient, config) {
bodyParser.json()(req, res, () => {
if (!req.body.hasOwnProperty('data') || req.body.data.length > config.maxLength) {
if (!req.body.hasOwnProperty('data') ||
req.body.data.length > config.maxLength) {
res.sendStatus(400);
}
else {
let uuid = UuidStatic.v4();
const uuid = UuidStatic.v4();
let ttl = config.defaultTtl;
if (req.body.hasOwnProperty('ttl')) {
let requestedTtl = parseInt(req.body.ttl);
const requestedTtl = parseInt(req.body.ttl);
if (requestedTtl > 0 && requestedTtl <= config.maxTtl) {

@@ -77,3 +68,3 @@ ttl = requestedTtl;

}
let redisKey = "remote:" + uuid;
const redisKey = 'remote:' + uuid;
redisClient.set(redisKey, req.body.data, (err) => {

@@ -91,3 +82,3 @@ if (err) {

key: uuid,
expiryDate: expiryDate.toUTCString()
expiryDate: expiryDate.toUTCString(),
});

@@ -99,7 +90,5 @@ });

};
function removeRemotelyEncrypted(redisClient, uuid, res) {
return __awaiter(this, void 0, void 0, function* () {
yield redisClient.del("remote:" + uuid);
res.sendStatus(200);
});
async function removeRemotelyEncrypted(redisClient, uuid, res) {
await redisClient.del('remote:' + uuid);
res.sendStatus(200);
}

@@ -112,4 +101,4 @@ function etherealSecrets(config = {}) {

name: 'sessionid',
secret: crypto.randomBytes(32).toString('hex')
}
secret: crypto.randomBytes(32).toString('hex'),
},
},

@@ -119,11 +108,12 @@ remote: {

defaultTtl: 2 * 24 * 60 * 60,
maxTtl: 14 * 24 * 60 * 60,
maxLength: 64 * 1000
}
maxTtl: 7 * 24 * 60 * 60,
maxLength: 64 * 1000,
},
}, config);
let redisConfig = Object.assign({
host: 'redis'
const redisConfig = Object.assign({
host: 'redis',
}, config.redis, { ttl: config.local.ttl });
let sessionConfig = {
store: new (RedisStore(session))(redisConfig),
const redisClient = new IORedis(redisConfig);
const sessionConfig = {
store: new (RedisStore(session))({ client: redisClient }),
name: config.local.cookie.name,

@@ -138,7 +128,6 @@ secret: config.local.cookie.secret,

secure: false,
sameSite: 'strict'
}, config.local.cookie)
sameSite: 'strict',
}, config.local.cookie),
};
let sessionHandler = session(sessionConfig);
let redisClient = !redisConfig.client ? new IORedis(redisConfig) : redisConfig.client;
const sessionHandler = session(sessionConfig);
return (req, res, next) => {

@@ -145,0 +134,0 @@ if (config.remote.enabled) {

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const chai = require("chai");
const cookieParser = require("cookie-parser");
const express = require("express");
const IORedis = require("ioredis");
const sinon = require("sinon");
const index_1 = require("../index");
const sinon = require("sinon");
const IORedis = require("ioredis");
const cookieParser = require("cookie-parser");
const chaiHttp = require("chai-http");
const chaiUuid = require("chai-uuid");
const UuidStatic = require("uuid");
before((done) => {
before(done => {
this.redis = new IORedis({ host: 'redis' });

@@ -26,3 +18,3 @@ chai.use(chaiHttp);

});
beforeEach((done) => {
beforeEach(done => {
this.app = express();

@@ -38,14 +30,14 @@ this.clock = sinon.useFakeTimers();

this.app.use('/secrets', index_1.etherealSecrets({
remote: remoteOptions
remote: remoteOptions,
}));
}
describe('Ethereal Secrets Middleware', () => {
it('should continue chain if no verb matches', () => {
it('should continue chain if no verb matches', async () => {
this.app.use('/secrets', index_1.etherealSecrets({
remote: {
enabled: true
enabled: true,
},
local: {
ttl: 5
}
ttl: 5,
},
}));

@@ -55,80 +47,94 @@ this.app.put('/secrets', (req, res) => {

});
return chai.request.agent(this.app)
.put('/secrets/')
.then(res => {
try {
const res = await chai.request.agent(this.app).put('/secrets/');
return chai.expect(res).to.have.status(418);
})
.catch(err => {
}
catch (err) {
return chai.expect(err.response).to.have.status(418);
});
}
});
it('should return new secret if no session exists', () => {
it('should return new secret if no session exists', async () => {
this.app.use('/secrets', index_1.etherealSecrets({
local: {
ttl: 5
}
ttl: 5,
},
}));
return chai.request(this.app)
.get('/secrets')
.set('Accept', 'application/json')
.then(res => {
try {
const res = await chai
.request(this.app)
.get('/secrets')
.set('Accept', 'application/json');
chai.expect(res).to.have.cookie('sessionid');
chai.expect(res).to.have.status(200).and.be.json;
chai.expect(res.body).to.be.an('object').with.key('key');
})
.catch(err => {
chai
.expect(res.body)
.to.be.an('object')
.with.key('key');
}
catch (err) {
throw err;
});
}
});
it('should return same secret on subsequent requests', () => {
it('should return same secret on subsequent requests', async () => {
this.app.use('/secrets', index_1.etherealSecrets({
local: {
ttl: 5
}
ttl: 5,
},
}));
let agent = chai.request.agent(this.app);
return agent
.get('/secrets')
.set('Accept', 'application/json')
.then(firstRes => {
return agent.get('/secrets').set('Accept', 'application/json').then(secondRes => {
try {
const firstRes = await agent
.get('/secrets')
.set('Accept', 'application/json');
try {
const secondRes = await agent
.get('/secrets')
.set('Accept', 'application/json');
return chai.expect(firstRes.body.key).to.equal(secondRes.body.key);
}).catch(err => {
}
catch (err) {
throw err;
});
})
.catch(err => {
throw err;
});
}
}
catch (err_1) {
throw err_1;
}
});
it('should return different secret on subsequent requests when cookie changes', () => {
it('should return different secret on subsequent requests when cookie changes', async () => {
this.app.use('/secrets', index_1.etherealSecrets({
local: {
ttl: 5
}
ttl: 5,
},
}));
return chai.request(this.app)
.get('/secrets')
.set('Accept', 'application/json')
.then(firstRes => {
return chai.request(this.app).get('/secrets').set('Accept', 'application/json').then(secondRes => {
try {
const firstRes = await chai
.request(this.app)
.get('/secrets')
.set('Accept', 'application/json');
try {
const secondRes = await chai
.request(this.app)
.get('/secrets')
.set('Accept', 'application/json');
return chai.expect(firstRes.body.key).to.not.equal(secondRes.body.key);
}).catch(err => {
}
catch (err) {
throw err;
});
})
.catch(err => {
throw err;
});
}
}
catch (err_1) {
throw err_1;
}
});
it('should return different secret on subsequent requests after the ttl of cookie elapses', () => {
it('should return different secret on subsequent requests after the ttl of cookie elapses', async () => {
this.app.use('/secrets', index_1.etherealSecrets({
local: {
ttl: 5
}
ttl: 5,
},
}));
return chai.request.agent(this.app)
.get('/secrets')
.set('Accept', 'application/json')
.then(res => {
try {
const res = await chai.request
.agent(this.app)
.get('/secrets')
.set('Accept', 'application/json');
let time = new Date();

@@ -138,8 +144,8 @@ time.setSeconds(time.getSeconds() + 5);

return chai.expect(res).to.have.header('set-cookie', regex);
})
.catch(err => {
}
catch (err) {
throw err;
});
}
});
it('should return different secret on subsequent requests after the ttl of redis entry elapses', () => {
it('should return different secret on subsequent requests after the ttl of redis entry elapses', async () => {
this.app.use('/secrets', index_1.etherealSecrets({

@@ -149,44 +155,52 @@ local: {

cookie: {
secret: 'supersecret'
}
}
secret: 'supersecret',
},
},
}));
return chai.request.agent(this.app)
.get('/secrets')
.set('Accept', 'application/json')
.then((res) => __awaiter(this, void 0, void 0, function* () {
let cookieValue = res.res.headers['set-cookie'][0].replace(/sessionid=(.+?);.+/, "$1");
try {
const res = await chai.request
.agent(this.app)
.get('/secrets')
.set('Accept', 'application/json');
let cookieValue = res
.get('Set-Cookie')[0]
.replace(/sessionid=(.+?);.+/, '$1');
let unsignedCookie = cookieParser.signedCookie(decodeURIComponent(cookieValue), 'supersecret');
let ttl = yield this.redis.ttl('sess:' + unsignedCookie);
let ttl = await this.redis.ttl('sess:' + unsignedCookie);
return chai.expect(ttl).to.be.lessThan(10);
}))
.catch(err => {
}
catch (err) {
throw err;
});
}
});
it('should store arbitrary data and return a uuid to it', () => {
it('should store arbitrary data and return a uuid to it', async () => {
setupRemoteMiddleware.call(this);
return chai.request(this.app)
.post('/secrets')
.send({
data: 'foo'
})
.then(res => {
try {
const res = await chai
.request(this.app)
.post('/secrets')
.send({
data: 'foo',
});
return Promise.all([
chai.expect(res).to.have.status(201),
chai.expect(res.body).to.be.an('object').with.keys('key', 'expiryDate'),
chai.expect(res.body['key']).to.be.a.uuid()
chai
.expect(res.body)
.to.be.an('object')
.with.keys('key', 'expiryDate'),
chai.expect(res.body['key']).to.be.a.uuid(),
]);
})
.catch(err => {
}
catch (err) {
throw err;
});
}
});
it('should store arbitrary as long as requested', () => {
setupRemoteMiddleware.call(this);
return chai.request(this.app)
return chai
.request(this.app)
.post('/secrets')
.send({
data: 'foo',
ttl: 1337
ttl: 1337,
})

@@ -198,4 +212,9 @@ .then(res => {

chai.expect(res).to.have.status(201),
chai.expect(res.body).to.be.an('object').with.keys('key', 'expiryDate'),
chai.expect(new Date(res.body['expiryDate']).getTime()).to.equal(timeInEliteFuture.getTime())
chai
.expect(res.body)
.to.be.an('object')
.with.keys('key', 'expiryDate'),
chai
.expect(new Date(res.body['expiryDate']).getTime())
.to.equal(timeInEliteFuture.getTime()),
]);

@@ -209,3 +228,4 @@ })

setupRemoteMiddleware.call(this);
return chai.request.agent(this.app)
return chai.request
.agent(this.app)
.post('/secrets')

@@ -222,6 +242,7 @@ .set('Accept', 'application/json')

setupRemoteMiddleware.call(this);
return chai.request.agent(this.app)
return chai.request
.agent(this.app)
.post('/secrets')
.send({
data: 'foo'
data: 'foo',
})

@@ -231,9 +252,16 @@ .set('Accept', 'application/json')

let key = res.body['key'];
return chai.request.agent(this.app).get('/secrets/' + key).then(res => {
return chai.request
.agent(this.app)
.get('/secrets/' + key)
.then(res => {
return Promise.all([
chai.expect(res).to.have.status(200),
chai.expect(res.body).to.be.an('object').with.keys('data', 'expiryDate'),
chai.expect(res.body['data']).to.equal('foo')
chai
.expect(res.body)
.to.be.an('object')
.with.keys('data', 'expiryDate'),
chai.expect(res.body['data']).to.equal('foo'),
]);
}).catch(err => {
})
.catch(err => {
throw err;

@@ -248,3 +276,4 @@ });

setupRemoteMiddleware.call(this);
return chai.request.agent(this.app)
return chai.request
.agent(this.app)
.get('/secrets/foobar')

@@ -261,3 +290,4 @@ .set('Accept', 'application/json')

setupRemoteMiddleware.call(this);
return chai.request.agent(this.app)
return chai.request
.agent(this.app)
.del('/secrets/foobar')

@@ -273,3 +303,4 @@ .then(res => {

setupRemoteMiddleware.call(this);
return chai.request.agent(this.app)
return chai.request
.agent(this.app)
.get('/secrets/' + UuidStatic.v4())

@@ -284,14 +315,18 @@ .set('Accept', 'application/json')

});
it('should return 404 for a uuid that was deleted', () => __awaiter(this, void 0, void 0, function* () {
it('should return 404 for a uuid that was deleted', async () => {
setupRemoteMiddleware.call(this);
return chai.request.agent(this.app)
return chai.request
.agent(this.app)
.post('/secrets')
.send({
data: 'foo'
data: 'foo',
})
.set('Accept', 'application/json')
.then((res) => __awaiter(this, void 0, void 0, function* () {
.then(async (res) => {
let key = res.body['key'];
yield chai.request.agent(this.app).del('/secrets/' + key);
return chai.request.agent(this.app).get('/secrets/' + key).then(res => {
await chai.request.agent(this.app).del('/secrets/' + key);
return chai.request
.agent(this.app)
.get('/secrets/' + key)
.then(res => {
return chai.expect(res).to.have.status(404);

@@ -302,96 +337,101 @@ })

});
}))
})
.catch(err => {
throw err;
});
}));
it('should return 404 for a key/value pair that has expired via the default ttl', () => __awaiter(this, void 0, void 0, function* () {
});
it('should return 404 for a key/value pair that has expired via the default ttl', async () => {
setupRemoteMiddleware.call(this, { defaultTtl: 9 });
return chai.request.agent(this.app)
return chai.request
.agent(this.app)
.post('/secrets')
.send({
data: 'foo'
data: 'foo',
})
.set('Accept', 'application/json')
.then((res) => __awaiter(this, void 0, void 0, function* () {
.then(async (res) => {
let key = res.body['key'];
let ttl = yield this.redis.ttl('remote:' + key);
let ttl = await this.redis.ttl('remote:' + key);
return Promise.all([
chai.expect(ttl).to.be.lessThan(10),
chai.expect(ttl).to.be.greaterThan(-1)
chai.expect(ttl).to.be.greaterThan(-1),
]);
}))
})
.catch(err => {
throw err;
});
}));
it('should return 404 for a key/value pair that has expired via the explicit ttl', () => __awaiter(this, void 0, void 0, function* () {
});
it('should return 404 for a key/value pair that has expired via the explicit ttl', async () => {
setupRemoteMiddleware.call(this);
return chai.request.agent(this.app)
return chai.request
.agent(this.app)
.post('/secrets')
.send({
data: 'foo',
ttl: 9
ttl: 9,
})
.set('Accept', 'application/json')
.then((res) => __awaiter(this, void 0, void 0, function* () {
.then(async (res) => {
let key = res.body['key'];
let ttl = yield this.redis.ttl('remote:' + key);
let ttl = await this.redis.ttl('remote:' + key);
return Promise.all([
chai.expect(ttl).to.be.lessThan(10),
chai.expect(ttl).to.be.greaterThan(-1)
chai.expect(ttl).to.be.greaterThan(-1),
]);
}))
})
.catch(err => {
throw err;
});
}));
it('should use default ttl in case of an invalid explicit ttl', () => __awaiter(this, void 0, void 0, function* () {
});
it('should use default ttl in case of an invalid explicit ttl', async () => {
setupRemoteMiddleware.call(this);
return chai.request.agent(this.app)
return chai.request
.agent(this.app)
.post('/secrets')
.send({
data: 'foo',
ttl: 'invalid'
ttl: 'invalid',
})
.set('Accept', 'application/json')
.then((res) => __awaiter(this, void 0, void 0, function* () {
.then(async (res) => {
let key = res.body['key'];
let ttl = yield this.redis.ttl('remote:' + key);
let ttl = await this.redis.ttl('remote:' + key);
return chai.expect(ttl).to.be.greaterThan(10);
}))
})
.catch(err => {
throw err;
});
}));
it('should use default ttl in case of a too large explicit ttl', () => __awaiter(this, void 0, void 0, function* () {
});
it('should use default ttl in case of a too large explicit ttl', async () => {
setupRemoteMiddleware.call(this, {
defaultTtl: 1337,
maxTtl: 2000
maxTtl: 2000,
});
return chai.request.agent(this.app)
return chai.request
.agent(this.app)
.post('/secrets')
.send({
data: 'foo',
ttl: 2001
ttl: 2001,
})
.set('Accept', 'application/json')
.then((res) => __awaiter(this, void 0, void 0, function* () {
.then(async (res) => {
let key = res.body['key'];
let ttl = yield this.redis.ttl('remote:' + key);
let ttl = await this.redis.ttl('remote:' + key);
return Promise.all([
chai.expect(ttl).to.be.lessThan(2000),
chai.expect(ttl).to.be.greaterThan(-1)
chai.expect(ttl).to.be.greaterThan(-1),
]);
}))
})
.catch(err => {
throw err;
});
}));
it('should return 400 in case of a too long data in body', () => __awaiter(this, void 0, void 0, function* () {
});
it('should return 400 in case of a too long data in body', async () => {
setupRemoteMiddleware.call(this, { maxLength: 8 });
return chai.request.agent(this.app)
return chai.request
.agent(this.app)
.post('/secrets')
.send({
data: 'way too long'
data: 'way too long',
})

@@ -405,4 +445,4 @@ .set('Accept', 'application/json')

});
}));
});
});
//# sourceMappingURL=index.js.map
{
"name": "@neoskop/ethereal-secrets-middleware",
"version": "1.2.2",
"version": "1.2.3",
"main": "dist/index.js",

@@ -12,5 +12,5 @@ "typings": "dist/index.d.ts",

"engines": {
"node": "12.4.0"
"node": ">= 12.4.0"
},
"repository": "https://github.com/neoskop/ethereal-secrets",
"repository": "https://bitbucket.org/neoskop/ethereal-secrets-middleware",
"scripts": {

@@ -20,41 +20,40 @@ "clean": "rimraf ./dist",

"build": "npm run clean; npm run tsc",
"start": "mocha -w --inspect=0.0.0.0:9229 --compilers ts:ts-node/register src/test/**/*.ts",
"test": "nyc --reporter=text mocha --compilers ts:ts-node/register src/test/**/*.ts",
"prepublish": "npm run build"
"start": "mocha -w --inspect=0.0.0.0:9229 --require ts-node/register src/test/**/*.ts",
"test": "nyc --reporter=text mocha --require ts-node/register src/test/**/*.ts"
},
"devDependencies": {
"@types/chai": "4.1.2",
"@types/chai-http": "^0.0.30",
"@types/cookie-parser": "^1.4.1",
"@types/deepmerge": "1.3.3",
"@types/express": "4.11.1",
"@types/express-session": "1.15.7",
"@types/ioredis": "0.0.24",
"@types/mocha": "2.2.48",
"@types/sinon": "2.3.7",
"@types/uuid": "3.4.3",
"@types/validator": "6.3.0",
"chai": "4.1.2",
"chai-http": "^4.0.0",
"chai-uuid": "^1.0.6",
"concurrently": "4.1.0",
"cookie-parser": "^1.4.3",
"mocha": "^5.2.0",
"nyc": "^14.1.1",
"rimraf": "2.6.2",
"sinon": "^2.4.1",
"ts-node": "^3.0.6",
"typescript": "2.7.1"
"@types/chai": "4.2.7",
"@types/chai-http": "4.2.0",
"@types/cookie-parser": "1.4.2",
"@types/deepmerge": "2.2.0",
"@types/express": "4.17.2",
"@types/express-session": "1.15.16",
"@types/ioredis": "4.14.2",
"@types/mocha": "5.2.7",
"@types/sinon": "7.5.1",
"@types/uuid": "3.4.6",
"@types/validator": "12.0.1",
"chai": "4.2.0",
"chai-http": "4.3.0",
"chai-uuid": "1.0.6",
"concurrently": "5.0.2",
"cookie-parser": "1.4.4",
"mocha": "6.2.2",
"nyc": "14.1.1",
"rimraf": "3.0.0",
"sinon": "7.5.0",
"ts-node": "8.5.4",
"typescript": "3.7.3"
},
"dependencies": {
"@types/body-parser": "1.16.8",
"@types/connect-redis": "0.0.6",
"body-parser": "1.18.2",
"connect-redis": "3.3.3",
"deepmerge": "1.5.2",
"express": "4.16.2",
"express-session": "^1.15.6",
"ioredis": "3.2.2",
"uuid": "3.2.1",
"validator": "9.4.1"
"@types/body-parser": "1.17.1",
"@types/connect-redis": "0.0.13",
"body-parser": "1.19.0",
"connect-redis": "4.0.3",
"deepmerge": "4.2.2",
"express": "4.17.1",
"express-session": "1.17.0",
"ioredis": "4.14.1",
"uuid": "3.3.3",
"validator": "12.1.0"
},

@@ -61,0 +60,0 @@ "nyc": {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc