New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@neoskop/ethereal-secrets-client

Package Overview
Dependencies
Maintainers
2
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

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

Comparing version 4.0.0 to 4.0.1

2

dist/index.d.ts

@@ -19,5 +19,3 @@ export interface EtherealSecretsClientConfig {

private _key;
private _agent;
constructor(config: EtherealSecretsClientConfig);
private fromBase64;
private toBase64;

@@ -24,0 +22,0 @@ private decrypt;

142

dist/index.js

@@ -10,3 +10,3 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

};
import { agent } from 'superagent';
import axios from 'axios';
export class EtherealSecretsClient {

@@ -19,19 +19,5 @@ constructor(config) {

: config.endpoint + '/';
this._agent = agent();
}
fromBase64(data) {
return new Uint8Array(window
.atob(data)
.split('')
.map(function (c) {
return c.charCodeAt(0);
}));
}
toBase64(data) {
const chunkSize = 0x1000;
const chunks = [];
for (let i = 0; i < data.length; i += chunkSize) {
chunks.push(String.fromCharCode.apply(null, data.subarray(i, i + chunkSize)));
}
return window.btoa(chunks.join(''));
return Buffer.from(data).toString('base64');
}

@@ -41,8 +27,8 @@ decrypt(secret, cipherText) {

const encryptedObj = JSON.parse(cipherText);
const iv = this.fromBase64(encryptedObj.iv);
const salt = this.fromBase64(encryptedObj.salt);
const data = this.fromBase64(encryptedObj.encrypted);
const additionalData = this.fromBase64(encryptedObj.additionalData);
const iv = Buffer.from(encryptedObj.iv, 'base64');
const salt = Buffer.from(encryptedObj.salt, 'base64');
const data = Buffer.from(encryptedObj.encrypted, 'base64');
const additionalData = Buffer.from(encryptedObj.additionalData, 'base64');
const key = yield this.deriveKey(secret, salt);
return new TextDecoder('utf8').decode(yield window.crypto.subtle.decrypt({
const clearText = yield window.crypto.subtle.decrypt({
name: 'AES-GCM',

@@ -52,3 +38,4 @@ iv,

additionalData,
}, key, data));
}, key, data);
return new TextDecoder('utf8').decode(clearText);
});

@@ -70,6 +57,6 @@ }

return JSON.stringify({
encrypted: this.toBase64(new Uint8Array(encrypted)),
salt: this.toBase64(salt),
iv: this.toBase64(iv),
additionalData: this.toBase64(additionalData),
encrypted: Buffer.from(new Uint8Array(encrypted)).toString('base64'),
salt: Buffer.from(salt).toString('base64'),
iv: Buffer.from(iv).toString('base64'),
additionalData: Buffer.from(additionalData).toString('base64'),
});

@@ -110,42 +97,41 @@ });

}
getRemote(fragmentIdentifier, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
try {
const keys = this.parseFragmentIdentifier(fragmentIdentifier);
const { secondFactor } = options;
const res = yield this._agent
.get(this._endpoint +
keys.remoteKey +
(secondFactor ? `?secondFactor=${secondFactor}` : ''))
.accept('application/json');
if (!res.body.data) {
throw new Error('The server did not answer with any data');
}
const clearText = yield this.decrypt(keys.localKey, res.body.data);
const result = {
clearText: clearText,
};
if (res.body.expiryDate) {
result.expiryDate = new Date(res.body.expiryDate);
}
return result;
getRemote(fragmentIdentifier_1) {
return __awaiter(this, arguments, void 0, function* (fragmentIdentifier, options = {}) {
const keys = this.parseFragmentIdentifier(fragmentIdentifier);
const { secondFactor } = options;
const res = yield axios.get(this._endpoint +
keys.remoteKey +
(secondFactor ? `?secondFactor=${secondFactor}` : ''), {
headers: {
'Content-Type': 'application/json',
},
});
if (!res.data.data) {
throw new Error('The server did not answer with any data');
}
catch (err) {
throw new Error(err.message);
const clearText = yield this.decrypt(keys.localKey, res.data.data);
const result = {
clearText: clearText,
};
if (res.data.expiryDate) {
result.expiryDate = new Date(res.data.expiryDate);
}
return result;
});
}
removeRemote(fragmentIdentifier, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
removeRemote(fragmentIdentifier_1) {
return __awaiter(this, arguments, void 0, function* (fragmentIdentifier, options = {}) {
const keys = this.parseFragmentIdentifier(fragmentIdentifier);
const { secondFactor } = options;
yield this._agent
.del(this._endpoint +
yield axios.delete(this._endpoint +
keys.remoteKey +
(secondFactor ? `?secondFactor=${secondFactor}` : ''))
.accept('application/json');
(secondFactor ? `?secondFactor=${secondFactor}` : ''), {
headers: {
'Content-Type': 'application/json',
},
});
});
}
saveRemote(clearText, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
saveRemote(clearText_1) {
return __awaiter(this, arguments, void 0, function* (clearText, options = {}) {
try {

@@ -155,14 +141,15 @@ const secret = this.generateLocalSecret();

const { secondFactor } = options;
const res = yield this._agent
.post(this._endpoint)
.send({ data: cipherText.toString(), secondFactor })
.accept('application/json');
if (!res.body.hasOwnProperty('key')) {
const res = yield axios.post(this._endpoint, { data: cipherText.toString(), secondFactor }, {
headers: {
'Content-Type': 'application/json',
},
});
if (!res.data.hasOwnProperty('key')) {
throw new Error('The server did not answer with a key');
}
const result = {
fragmentIdentifier: res.body.key + ';' + secret,
fragmentIdentifier: res.data.key + ';' + secret,
};
if (res.body.hasOwnProperty('expiryDate')) {
result.expiryDate = new Date(res.body.expiryDate);
if (res.data.hasOwnProperty('expiryDate')) {
result.expiryDate = new Date(res.data.expiryDate);
}

@@ -214,18 +201,15 @@ return result;

}
try {
const res = yield this._agent
.get(this._endpoint)
.withCredentials()
.accept('application/json');
if (!res.body.key) {
throw new Error('The server did not answer with a key');
}
if (this._cacheKey) {
this._key = res.body.key;
}
return res.body.key;
const res = yield axios.get(this._endpoint, {
headers: {
'Content-Type': 'application/json',
},
withCredentials: true,
});
if (!res.data.key) {
throw new Error('The server did not answer with a key');
}
catch (err) {
throw new Error(err.message);
if (this._cacheKey) {
this._key = res.data.key;
}
return res.data.key;
});

@@ -232,0 +216,0 @@ }

/**
* @jest-environment jsdom
* @jest-environment-options {"url": "http://server:8080"}
*/
export {};
/**
* @jest-environment jsdom
* @jest-environment-options {"url": "http://server:8080"}
*/

@@ -18,8 +19,3 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

};
Object.getOwnPropertyNames(config).forEach((key) => {
if (config.hasOwnProperty(key)) {
defaultConfig[key] = config[key];
}
});
return new EtherealSecretsClient(defaultConfig);
return new EtherealSecretsClient(Object.assign(defaultConfig, config));
}

@@ -75,7 +71,7 @@ describe('Ethereal Secrets Client', () => {

const sut = createClient();
return expect(sut.getRemote('invalididentifier')).rejects.toThrowError('invalid');
return expect(sut.getRemote('invalididentifier')).rejects.toThrow('invalid');
});
it('should reject unknown fragment identifier', () => {
const sut = createClient();
return expect(sut.getRemote('decafbad-dead-dead-dead-decafbadadad;decafbaddecafbaddecafbaddecafbaddecafbaddecafbaddecafbaddecafbad')).rejects.toThrowError('Not Found');
return expect(sut.getRemote('decafbad-dead-dead-dead-decafbadadad;decafbaddecafbaddecafbaddecafbaddecafbaddecafbaddecafbaddecafbad')).rejects.toThrow(/404/);
});

@@ -86,8 +82,7 @@ it('should not return data when the data was deleted beforehand', () => __awaiter(void 0, void 0, void 0, function* () {

yield sut.removeRemote(result.fragmentIdentifier);
return expect(sut.getRemote(result.fragmentIdentifier)).rejects.toThrowError('Not Found');
return expect(sut.getRemote(result.fragmentIdentifier)).rejects.toThrow(/404/);
}));
it('should allow storage of large inputs', () => {
const sut = createClient();
const randomValues = new Uint8Array(200000);
window.crypto.getRandomValues(randomValues);
const randomValues = window.crypto.getRandomValues(new Uint8Array(20000));
const bigInput = Array.from(randomValues, (dec) => {

@@ -108,3 +103,3 @@ return dec.toString(16).padStart(2, '0');

const result = yield sut.saveRemote('foo', { secondFactor: 'bar' });
return expect(sut.getRemote(result.fragmentIdentifier)).rejects.toThrowError(/unauthorized/i);
return expect(sut.getRemote(result.fragmentIdentifier)).rejects.toThrow(/401/);
}));

@@ -114,3 +109,3 @@ it('should throw error when data stored with second factor is tried to be deleted without', () => __awaiter(void 0, void 0, void 0, function* () {

const result = yield sut.saveRemote('foo', { secondFactor: 'bar' });
return expect(sut.removeRemote(result.fragmentIdentifier)).rejects.toThrowError(/unauthorized/i);
return expect(sut.removeRemote(result.fragmentIdentifier)).rejects.toThrow(/401/);
}));

@@ -120,3 +115,3 @@ it('should throw error when data stored with second factor is tried to be deleted with the wrong second factor', () => __awaiter(void 0, void 0, void 0, function* () {

const result = yield sut.saveRemote('foo', { secondFactor: 'baz' });
return expect(sut.removeRemote(result.fragmentIdentifier)).rejects.toThrowError(/unauthorized/i);
return expect(sut.removeRemote(result.fragmentIdentifier)).rejects.toThrow(/401/);
}));

@@ -123,0 +118,0 @@ it('should allow deletion of data stored with second factor', () => __awaiter(void 0, void 0, void 0, function* () {

@@ -1,8 +0,5 @@

import * as crypto from 'crypto';
import { webcrypto } from 'crypto';
import { TextEncoder, TextDecoder } from 'util';
Object.defineProperty(global.self, 'crypto', {
value: {
subtle: crypto.webcrypto.subtle,
getRandomValues: (arr) => crypto.randomBytes(arr.length),
},
Object.defineProperty(globalThis, 'crypto', {
value: webcrypto,
});

@@ -9,0 +6,0 @@ global.TextEncoder = TextEncoder;

{
"name": "@neoskop/ethereal-secrets-client",
"version": "4.0.0",
"version": "4.0.1",
"main": "dist/index.js",

@@ -20,9 +20,7 @@ "typings": "dist/index.d.ts",

"devDependencies": {
"@peculiar/webcrypto": "1.4.3",
"@types/jest": "29.5.5",
"@types/superagent": "4.1.19",
"concurrently": "8.2.1",
"@types/jest": "29.5.12",
"concurrently": "8.2.2",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"jsdom": "22.1.0",
"jsdom": "24.0.0",
"jsdom-global": "3.0.2",

@@ -32,10 +30,10 @@ "mock-local-storage": "1.1.24",

"parse5": "7.1.2",
"prettier": "3.0.3",
"rimraf": "5.0.4",
"ts-jest": "29.1.1",
"ts-node": "10.9.1",
"typescript": "5.2.2"
"prettier": "3.2.5",
"rimraf": "5.0.5",
"ts-jest": "29.1.2",
"ts-node": "10.9.2",
"typescript": "5.4.5"
},
"dependencies": {
"superagent": "8.1.2"
"axios": "1.6.8"
},

@@ -42,0 +40,0 @@ "engines": {

Sorry, the diff of this file is not supported yet

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