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

secure-store-redis

Package Overview
Dependencies
Maintainers
1
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

secure-store-redis - npm Package Compare versions

Comparing version 2.0.5 to 3.0.0-rc.1

src/index.test.ts

9

dist/index.d.ts

@@ -1,5 +0,4 @@

import { RedisConnectionPoolConfig } from "redis-connection-pool";
import { RedisClientOptions } from "redis";
interface SecureStoreConfig {
redis?: any;
redisConnectionPool?: RedisConnectionPoolConfig;
redis: RedisClientOptions;
}

@@ -9,5 +8,5 @@ export default class SecureStore {

secret: string;
private pool;
private client;
private config;
constructor(uid: string, secret: string, cfg?: SecureStoreConfig);
constructor(uid: string, secret: string, cfg: SecureStoreConfig);
init(): Promise<void>;

@@ -14,0 +13,0 @@ save(key: string, data: any, postfix?: string): Promise<number>;

@@ -15,41 +15,49 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const redis_connection_pool_1 = __importDefault(require("redis-connection-pool"));
const crypto_1 = require("crypto");
const ALGORITHM = 'aes-256-cbc', IV_LENGTH = 16;
const redis_1 = require("redis");
const debug_1 = __importDefault(require("debug"));
const log = (0, debug_1.default)("secure-store-redis");
const ALGORITHM = "aes-256-cbc", IV_LENGTH = 16;
class SecureStore {
constructor(uid, secret, cfg = {}) {
if (typeof uid !== 'string') {
throw new Error('A uid must be specified');
constructor(uid, secret, cfg) {
if (typeof uid !== "string") {
throw new Error("A uid must be specified");
}
else if (typeof secret !== 'string') {
throw new Error('No secret specified');
else if (typeof secret !== "string") {
throw new Error("No secret specified");
}
else if (secret.length !== 32) {
throw new Error('Secret must be 32 char string');
throw new Error("Secret must be 32 char string");
}
this.uid = uid;
this.secret = secret;
const redis = cfg.redis || {};
const redisConnectionPoolConfig = cfg.redisConnectionPool || {};
if (redis) {
redisConnectionPoolConfig.redis = redis;
}
this.config = redisConnectionPoolConfig;
this.config = cfg;
}
init() {
return __awaiter(this, void 0, void 0, function* () {
this.pool = yield (0, redis_connection_pool_1.default)(this.uid, this.config);
yield this.pool.init();
return new Promise((resolve, reject) => {
const client = (0, redis_1.createClient)(this.config.redis);
client.on("error", (err) => {
log("error connecting", err);
return reject(err);
});
client.connect().then(() => {
log("connected");
this.client = client;
resolve();
});
});
});
}
save(key, data, postfix = '') {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
save(key, data, postfix = "") {
return __awaiter(this, void 0, void 0, function* () {
if (typeof key !== 'string') {
throw new Error('No hash key specified');
if (typeof key !== "string") {
throw new Error("No hash key specified");
}
else if (!data) {
throw new Error('No data provided, nothing to save');
throw new Error("No data provided, nothing to save");
}
postfix = postfix ? ':' + postfix : '';
if (typeof data === 'object') {
postfix = postfix ? ":" + postfix : "";
if (typeof data === "object") {
try {

@@ -64,15 +72,15 @@ data = JSON.stringify(data);

const hash = SecureStore.shasum(key);
return yield this.pool.hset(this.uid + postfix, hash, data);
return yield this.client.hSet(this.uid + postfix, hash, data);
});
}
get(key, postfix = '') {
get(key, postfix = "") {
return __awaiter(this, void 0, void 0, function* () {
if (typeof key !== 'string') {
throw new Error('No hash key specified');
if (typeof key !== "string") {
throw new Error("No hash key specified");
}
postfix = postfix ? ':' + postfix : '';
postfix = postfix ? ":" + postfix : "";
const hash = SecureStore.shasum(key);
const res = yield this.pool.hget(this.uid + postfix, hash);
const res = yield this.client.hGet(this.uid + postfix, hash);
let data;
if (typeof res === 'string') {
if (typeof res === "string") {
try {

@@ -86,2 +94,3 @@ data = this.decrypt(res);

data = JSON.parse(data);
// eslint-disable-next-line no-empty
}

@@ -96,14 +105,13 @@ catch (e) { }

}
delete(key, postfix = '') {
delete(key, postfix = "") {
return __awaiter(this, void 0, void 0, function* () {
if (typeof key !== 'string') {
throw new Error('No hash key specified');
if (typeof key !== "string") {
throw new Error("No hash key specified");
}
postfix = postfix ? ':' + postfix : '';
postfix = postfix ? ":" + postfix : "";
const hash = SecureStore.shasum(key);
// @ts-ignore
return yield this.pool.hdel(this.uid + postfix, hash);
return yield this.client.hDel(this.uid + postfix, hash);
});
}
;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
encrypt(data) {

@@ -114,8 +122,8 @@ const iv = (0, crypto_1.randomBytes)(IV_LENGTH);

encrypted = Buffer.concat([encrypted, cipher.final()]);
return iv.toString('hex') + ':' + encrypted.toString('hex');
return iv.toString("hex") + ":" + encrypted.toString("hex");
}
decrypt(encrypted) {
let parts = encrypted.split(':');
const iv = Buffer.from(parts.shift(), 'hex');
const encryptedText = Buffer.from(parts.join(':'), 'hex');
const parts = encrypted.split(":");
const iv = Buffer.from(parts.shift(), "hex");
const encryptedText = Buffer.from(parts.join(":"), "hex");
const decipher = (0, crypto_1.createDecipheriv)(ALGORITHM, Buffer.from(this.secret), iv);

@@ -127,5 +135,5 @@ let decrypted = decipher.update(encryptedText);

static shasum(text) {
const s = (0, crypto_1.createHash)('sha256');
const s = (0, crypto_1.createHash)("sha256");
s.update(text);
return s.digest('hex');
return s.digest("hex");
}

@@ -132,0 +140,0 @@ }

{
"name": "secure-store-redis",
"version": "2.0.5",
"version": "3.0.0-rc.1",
"description": "A simple wrapper to encrypt and decrypt data stored in Redis",
"license": "MIT",
"private": false,
"packageManager": "pnpm@8.0.0",
"engines": {
"node": ">=16",
"pnpm": ">=8"
},
"keywords": [

@@ -26,21 +31,21 @@ "redis",

],
"scripts": {
"test": "npm run build && jaribu",
"lint": "eslint src/",
"lint:fix": "eslint --fix src/",
"build": "tsc"
},
"dependencies": {
"redis-connection-pool": "^4.0.1"
"redis": "4.6.6"
},
"devDependencies": {
"@types/chai": "4.3.5",
"@types/debug": "4.1.7",
"@types/eslint": "8.4.6",
"@types/node": "^18.7.13",
"@typescript-eslint/eslint-plugin": "^5.35.1",
"@typescript-eslint/parser": "^5.35.1",
"@types/mocha": "10.0.1",
"@types/node": "18.7.13",
"@typescript-eslint/eslint-plugin": "5.36.0",
"@typescript-eslint/parser": "5.36.0",
"chai": "4.3.7",
"debug": "4.3.4",
"eslint": "8.22.0",
"eslint-plugin-security-node": "1.1.1",
"jaribu": "2.2.3",
"typescript": "^4.8.2",
"typescript-eslint": "0.0.1-alpha.0"
"mocha": "10.2.0",
"prettier": "2.8.8",
"ts-node": "10.9.1",
"typescript": "4.8.2"
},

@@ -55,3 +60,10 @@ "repository": {

},
"homepage": "https://github.com/silverbucket/secure-store-redis"
}
"homepage": "https://github.com/silverbucket/secure-store-redis",
"scripts": {
"preinstall": "npx only-allow pnpm",
"test": "mocha -r ts-node/register src/*.test.ts",
"lint": "prettier --check . && eslint --max-warnings 0 .",
"lint:fix": "prettier --write . && eslint --max-warnings 0 --fix .",
"build": "tsc"
}
}
# secure-store-redis
A simple wrapper to encrypt and decrypt data stored in redis.
The main point is to ensure that any data you store in redis cannot be accessed
A simple wrapper to encrypt and decrypt data stored in redis.
The main point is to ensure that any data you store in redis cannot be accessed
by anyone else, without the key.
**NOTE** version `2.x` is a rewrite in TypeScript, using async functions, and is
**NOTE** version `2.x` is a rewrite in TypeScript, using async functions, and is
backwards incompatible with `1.x`
```javascript
const SecureStore = require('secure-store-redis').default;
const SecureStore = require("secure-store-redis").default;
const store = new SecureStore('myApp:store', '823HD8DG26JA0LK1239Hgb651TWfs0j1', {
redis: {
host: 'localhost',
port: 6379, // optional
// optionally use the 'url' property to specify entire redis connect string
// url: 'redis://localhost:6379',
} // optional
});
const store = new SecureStore(
"myApp:store",
"823HD8DG26JA0LK1239Hgb651TWfs0j1",
{
redis: {
host: "localhost",
port: 6379, // optional
// optionally use the 'url' property to specify entire redis connect string
// url: 'redis://localhost:6379',
}, // optional
}
);
await store.init();
await store.save('quote', 'i see dead people');
let res = await store.get('quote');
await store.save("quote", "i see dead people");
let res = await store.get("quote");
// res: 'i see dead people'
let res = await store.get('quote');
let res = await store.get("quote");
// res: null
const num = await store.delete('quote');
const num = await store.delete("quote");
// num: 1
await store.save('quote', 'i see dead people again');
await store.save("quote", "i see dead people again");
const otherStore = new SecureStore('myApp:store', 'this is the wrong secret', {
host: "127.0.0.1",
port: 6379
const otherStore = new SecureStore("myApp:store", "this is the wrong secret", {
host: "127.0.0.1",
port: 6379,
});
await otherStore.init();
let res = await otherStore.get('quote');
let res = await otherStore.get("quote");
// res: undefined
```

@@ -1,12 +0,25 @@

import redisConnectionPoolFactory, {
RedisConnectionPool, RedisConnectionPoolConfig
} from "redis-connection-pool";
import {randomBytes, createCipheriv, createDecipheriv, createHash} from 'crypto';
import {
randomBytes,
createCipheriv,
createDecipheriv,
createHash,
} from "crypto";
import {
createClient,
RedisClientOptions,
RedisClientType,
RedisFunctions,
RedisModules,
RedisScripts,
} from "redis";
const ALGORITHM = 'aes-256-cbc',
IV_LENGTH = 16;
import debug from "debug";
const log = debug("secure-store-redis");
const ALGORITHM = "aes-256-cbc",
IV_LENGTH = 16;
interface SecureStoreConfig {
redis?: any;
redisConnectionPool?: RedisConnectionPoolConfig;
redis: RedisClientOptions;
}

@@ -17,37 +30,51 @@

secret: string;
private pool: RedisConnectionPool;
private config: object;
client: RedisClientType<RedisModules, RedisFunctions, RedisScripts>;
private config: SecureStoreConfig;
constructor(uid: string, secret: string, cfg: SecureStoreConfig = {}) {
if (typeof uid !== 'string') {
throw new Error('A uid must be specified');
} else if (typeof secret !== 'string') {
throw new Error('No secret specified');
constructor(uid: string, secret: string, cfg: SecureStoreConfig) {
if (typeof uid !== "string") {
throw new Error("A uid must be specified");
} else if (typeof secret !== "string") {
throw new Error("No secret specified");
} else if (secret.length !== 32) {
throw new Error('Secret must be 32 char string');
throw new Error("Secret must be 32 char string");
}
this.uid = uid;
this.secret = secret;
const redis = cfg.redis || {};
const redisConnectionPoolConfig = cfg.redisConnectionPool || {};
if (redis) {
redisConnectionPoolConfig.redis = redis;
}
this.config = redisConnectionPoolConfig;
this.config = cfg;
}
async init() {
this.pool = await redisConnectionPoolFactory(this.uid, this.config);
await this.pool.init();
async quit() {
return this.client.quit();
}
async save(key: string, data: any, postfix: string = '') {
if (typeof key !== 'string') {
throw new Error('No hash key specified');
async disconnect() {
return this.client.disconnect();
}
async init(): Promise<void> {
return new Promise((resolve, reject) => {
const client = createClient(this.config.redis);
client.on("error", (err) => {
log("error connecting", err);
return reject(err);
});
client.connect().then(() => {
log("connected");
this.client = client;
resolve();
});
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async save(key: string, data: any, postfix = "") {
if (typeof key !== "string") {
throw new Error("No hash key specified");
} else if (!data) {
throw new Error('No data provided, nothing to save');
throw new Error("No data provided, nothing to save");
}
postfix = postfix ? ':' + postfix : '';
postfix = postfix ? ":" + postfix : "";
if (typeof data === 'object') {
if (typeof data === "object") {
try {

@@ -62,15 +89,15 @@ data = JSON.stringify(data);

const hash = SecureStore.shasum(key);
return await this.pool.hset(this.uid + postfix, hash, data);
return await this.client.HSET(this.uid + postfix, hash, data);
}
async get(key: string, postfix: string = '') {
if (typeof key !== 'string') {
throw new Error('No hash key specified');
async get(key: string, postfix = "") {
if (typeof key !== "string") {
throw new Error("No hash key specified");
}
postfix = postfix ? ':' + postfix : '';
postfix = postfix ? ":" + postfix : "";
const hash = SecureStore.shasum(key);
const res = await this.pool.hget(this.uid + postfix, hash);
const res = await this.client.HGET(this.uid + postfix, hash);
let data;
if (typeof res === 'string') {
if (typeof res === "string") {
try {

@@ -84,2 +111,3 @@ data = this.decrypt(res);

data = JSON.parse(data);
// eslint-disable-next-line no-empty
} catch (e) {}

@@ -92,12 +120,12 @@ } else {

async delete(key: string, postfix = '') {
if (typeof key !== 'string') {
throw new Error('No hash key specified');
async delete(key: string, postfix = "") {
if (typeof key !== "string") {
throw new Error("No hash key specified");
}
postfix = postfix ? ':' + postfix : '';
postfix = postfix ? ":" + postfix : "";
const hash = SecureStore.shasum(key);
// @ts-ignore
return await this.pool.hdel(this.uid + postfix, hash);
};
return await this.client.HDEL(this.uid + postfix, hash);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private encrypt(data: any): string {

@@ -109,9 +137,9 @@ const iv = randomBytes(IV_LENGTH);

encrypted = Buffer.concat([encrypted, cipher.final()]);
return iv.toString('hex') + ':' + encrypted.toString('hex');
return iv.toString("hex") + ":" + encrypted.toString("hex");
}
private decrypt(encrypted: string): string {
let parts = encrypted.split(':');
const iv = Buffer.from(parts.shift(), 'hex');
const encryptedText = Buffer.from(parts.join(':'), 'hex');
const parts = encrypted.split(":");
const iv = Buffer.from(parts.shift(), "hex");
const encryptedText = Buffer.from(parts.join(":"), "hex");
const decipher = createDecipheriv(ALGORITHM, Buffer.from(this.secret), iv);

@@ -125,6 +153,6 @@ let decrypted = decipher.update(encryptedText);

private static shasum(text: string): string {
const s = createHash('sha256');
const s = createHash("sha256");
s.update(text);
return s.digest('hex');
return s.digest("hex");
}
}

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