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

@eik/sink-memory

Package Overview
Dependencies
Maintainers
0
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@eik/sink-memory - npm Package Compare versions

Comparing version 1.1.1 to 1.1.2

7

CHANGELOG.md

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

## [1.1.2](https://github.com/eik-lib/sink-memory/compare/v1.1.1...v1.1.2) (2024-08-15)
### Bug Fixes
* generate URL pathnames on Windows hosts ([#5](https://github.com/eik-lib/sink-memory/issues/5)) ([0f37c07](https://github.com/eik-lib/sink-memory/commit/0f37c072b798611e97e911f37b74b25a4a08e744))
## [1.1.1](https://github.com/eik-lib/sink-memory/compare/v1.1.0...v1.1.1) (2024-07-29)

@@ -2,0 +9,0 @@

50

lib/entry.js

@@ -1,33 +0,33 @@

import crypto from 'node:crypto';
import crypto from "node:crypto";
export default class Entry {
constructor({ mimeType = 'application/octet-stream', payload = [] } = {}) {
this._mimeType = mimeType;
this._payload = payload;
this._hash = '';
constructor({ mimeType = "application/octet-stream", payload = [] } = {}) {
this._mimeType = mimeType;
this._payload = payload;
this._hash = "";
if (Array.isArray(payload)) {
const hash = crypto.createHash('sha512');
payload.forEach((buffer) => {
hash.update(buffer.toString());
});
this._hash = `sha512-${hash.digest('base64')}`;
}
}
if (Array.isArray(payload)) {
const hash = crypto.createHash("sha512");
payload.forEach((buffer) => {
hash.update(buffer.toString());
});
this._hash = `sha512-${hash.digest("base64")}`;
}
}
get mimeType() {
return this._mimeType;
}
get mimeType() {
return this._mimeType;
}
get payload() {
return this._payload;
}
get payload() {
return this._payload;
}
get hash() {
return this._hash;
}
get hash() {
return this._hash;
}
get [Symbol.toStringTag]() {
return 'Entry';
}
get [Symbol.toStringTag]() {
return "Entry";
}
}

@@ -1,7 +0,7 @@

import { join } from 'node:path';
import { Readable, Writable } from 'node:stream';
import { ReadFile } from '@eik/common';
import Sink from '@eik/sink';
import MetricsClient from '@metrics/client';
import Entry from './entry.js';
import { join } from "node:path";
import { Readable, Writable } from "node:stream";
import { ReadFile } from "@eik/common";
import Sink from "@eik/sink";
import MetricsClient from "@metrics/client";
import Entry from "./entry.js";

@@ -14,228 +14,227 @@ /**

export default class SinkMemory extends Sink {
_metrics = new MetricsClient();
/** @type {Map<string, Entry>}*/
_state = new Map();
_metrics = new MetricsClient();
/** @type {Map<string, Entry>}*/
_state = new Map();
/**
*
* @param {SinkMemoryOptions} options
*/
constructor(options = {}) {
super();
this._rootPath = options.rootPath || '/';
this._counter = this._metrics.counter({
name: 'eik_core_sink_mem',
description:
'Counter measuring access to the in memory storage sink',
labels: {
operation: 'n/a',
success: false,
access: false,
},
});
}
/**
*
* @param {SinkMemoryOptions} options
*/
constructor(options = {}) {
super();
this._rootPath = options.rootPath || "/";
this._counter = this._metrics.counter({
name: "eik_core_sink_mem",
description: "Counter measuring access to the in memory storage sink",
labels: {
operation: "n/a",
success: false,
access: false,
},
});
}
get metrics() {
return this._metrics;
}
get metrics() {
return this._metrics;
}
/**
* @param {string} filePath
* @param {string} contentType
* @returns {Promise<Writable>}
*/
write(filePath, contentType) {
return new Promise((resolve, reject) => {
const operation = 'write';
/**
* @param {string} filePath
* @param {string} contentType
* @returns {Promise<Writable>}
*/
write(filePath, contentType) {
return new Promise((resolve, reject) => {
const operation = "write";
try {
Sink.validateFilePath(filePath);
Sink.validateContentType(contentType);
} catch (error) {
this._counter.inc({ labels: { operation } });
reject(error);
return;
}
try {
Sink.validateFilePath(filePath);
Sink.validateContentType(contentType);
} catch (error) {
this._counter.inc({ labels: { operation } });
reject(error);
return;
}
const pathname = join(this._rootPath, filePath);
const pathname = join(this._rootPath, filePath).replace(/\\/g, "/");
if (pathname.indexOf(this._rootPath) !== 0) {
reject(new Error(`Directory traversal - ${filePath}`));
this._counter.inc({ labels: { operation } });
return;
}
if (pathname.indexOf(this._rootPath) !== 0) {
reject(new Error(`Directory traversal - ${filePath}`));
this._counter.inc({ labels: { operation } });
return;
}
const payload = [];
const stream = new Writable({
write(chunk, encoding, cb) {
payload.push(chunk);
cb();
},
});
const payload = [];
const stream = new Writable({
write(chunk, encoding, cb) {
payload.push(chunk);
cb();
},
});
stream.on('finish', () => {
const entry = new Entry({
mimeType: contentType,
payload,
});
stream.on("finish", () => {
const entry = new Entry({
mimeType: contentType,
payload,
});
this._state.set(pathname, entry);
this._state.set(pathname, entry);
this._counter.inc({
labels: {
success: true,
access: true,
operation,
},
});
});
this._counter.inc({
labels: {
success: true,
access: true,
operation,
},
});
});
resolve(stream);
});
}
resolve(stream);
});
}
/**
* @param {string} filePath
* @throws {Error} if the file does not exist
* @returns {Promise<import('@eik/common').ReadFile>}
*/
read(filePath) {
return new Promise((resolve, reject) => {
const operation = 'read';
/**
* @param {string} filePath
* @throws {Error} if the file does not exist
* @returns {Promise<import('@eik/common').ReadFile>}
*/
read(filePath) {
return new Promise((resolve, reject) => {
const operation = "read";
try {
Sink.validateFilePath(filePath);
} catch (error) {
this._counter.inc({ labels: { operation } });
reject(error);
return;
}
try {
Sink.validateFilePath(filePath);
} catch (error) {
this._counter.inc({ labels: { operation } });
reject(error);
return;
}
const pathname = join(this._rootPath, filePath);
const pathname = join(this._rootPath, filePath).replace(/\\/g, "/");
if (pathname.indexOf(this._rootPath) !== 0) {
this._counter.inc({ labels: { operation } });
reject(new Error(`Directory traversal - ${filePath}`));
return;
}
if (pathname.indexOf(this._rootPath) !== 0) {
this._counter.inc({ labels: { operation } });
reject(new Error(`Directory traversal - ${filePath}`));
return;
}
const entry = this._state.get(pathname);
if (!entry) {
reject(new Error(`${filePath} does not exist`));
}
const entry = this._state.get(pathname);
if (!entry) {
reject(new Error(`${filePath} does not exist`));
}
const payload = entry.payload || [];
const obj = new ReadFile({
mimeType: entry.mimeType,
etag: entry.hash,
});
const payload = entry.payload || [];
const obj = new ReadFile({
mimeType: entry.mimeType,
etag: entry.hash,
});
obj.stream = new Readable({
read() {
payload.forEach((item) => {
this.push(item);
});
this.push(null);
},
});
obj.stream = new Readable({
read() {
payload.forEach((item) => {
this.push(item);
});
this.push(null);
},
});
obj.stream.on('end', () => {
this._counter.inc({
labels: {
success: true,
access: true,
operation,
},
});
});
obj.stream.on("end", () => {
this._counter.inc({
labels: {
success: true,
access: true,
operation,
},
});
});
resolve(obj);
});
}
resolve(obj);
});
}
/**
* @param {string} filePath
* @throws {Error} if the file does not exist
* @returns {Promise<void>}
*/
delete(filePath) {
return new Promise((resolve, reject) => {
const operation = 'delete';
/**
* @param {string} filePath
* @throws {Error} if the file does not exist
* @returns {Promise<void>}
*/
delete(filePath) {
return new Promise((resolve, reject) => {
const operation = "delete";
try {
Sink.validateFilePath(filePath);
} catch (error) {
this._counter.inc({ labels: { operation } });
reject(error);
return;
}
try {
Sink.validateFilePath(filePath);
} catch (error) {
this._counter.inc({ labels: { operation } });
reject(error);
return;
}
const pathname = join(this._rootPath, filePath);
const pathname = join(this._rootPath, filePath).replace(/\\/g, "/");
if (pathname.indexOf(this._rootPath) !== 0) {
this._counter.inc({ labels: { operation } });
reject(new Error(`Directory traversal - ${filePath}`));
return;
}
if (pathname.indexOf(this._rootPath) !== 0) {
this._counter.inc({ labels: { operation } });
reject(new Error(`Directory traversal - ${filePath}`));
return;
}
// Delete recursively
Array.from(this._state.keys()).forEach((key) => {
if (key.startsWith(pathname)) {
this._state.delete(key);
}
});
// Delete recursively
Array.from(this._state.keys()).forEach((key) => {
if (key.startsWith(pathname)) {
this._state.delete(key);
}
});
this._counter.inc({
labels: {
success: true,
access: true,
operation,
},
});
this._counter.inc({
labels: {
success: true,
access: true,
operation,
},
});
resolve();
});
}
resolve();
});
}
/**
* @param {string} filePath
* @throws {Error} if the file does not exist
* @returns {Promise<void>}
*/
exist(filePath) {
return new Promise((resolve, reject) => {
const operation = 'exist';
/**
* @param {string} filePath
* @throws {Error} if the file does not exist
* @returns {Promise<void>}
*/
exist(filePath) {
return new Promise((resolve, reject) => {
const operation = "exist";
try {
Sink.validateFilePath(filePath);
} catch (error) {
this._counter.inc({ labels: { operation } });
reject(error);
return;
}
try {
Sink.validateFilePath(filePath);
} catch (error) {
this._counter.inc({ labels: { operation } });
reject(error);
return;
}
const pathname = join(this._rootPath, filePath);
const pathname = join(this._rootPath, filePath).replace(/\\/g, "/");
if (pathname.indexOf(this._rootPath) !== 0) {
this._counter.inc({ labels: { operation } });
reject(new Error(`Directory traversal - ${filePath}`));
return;
}
if (pathname.indexOf(this._rootPath) !== 0) {
this._counter.inc({ labels: { operation } });
reject(new Error(`Directory traversal - ${filePath}`));
return;
}
this._counter.inc({
labels: {
success: true,
access: true,
operation,
},
});
this._counter.inc({
labels: {
success: true,
access: true,
operation,
},
});
if (this._state.has(pathname)) {
resolve();
return;
}
if (this._state.has(pathname)) {
resolve();
return;
}
reject(new Error(`${filePath} does not exist`));
});
}
reject(new Error(`${filePath} does not exist`));
});
}
}
{
"name": "@eik/sink-memory",
"version": "1.1.1",
"version": "1.1.2",
"description": "In-memory sink designed for tests.",

@@ -15,8 +15,9 @@ "main": "lib/main.js",

"scripts": {
"clean": "rimraf .tap node_modules types",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"test": "run-s test:*",
"test:unit": "tap --disable-coverage --allow-empty-coverage tests/**/*.js",
"test:types": "tsc --project tsconfig.test.json",
"types": "tsc --declaration --emitDeclarationOnly"
"test": "tap --disable-coverage --allow-empty-coverage tests/**/*.js",
"types": "run-s types:module types:test",
"types:module": "tsc",
"types:test": "tsc --project tsconfig.test.json"
},

@@ -42,13 +43,14 @@ "repository": {

"devDependencies": {
"@semantic-release/changelog": "6.0.3",
"@semantic-release/git": "10.0.1",
"eslint": "9.1.1",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-prettier": "5.1.3",
"globals": "15.0.0",
"@eik/eslint-config": "1.0.0",
"@eik/prettier-config": "1.0.1",
"@eik/semantic-release-config": "1.0.0",
"@eik/typescript-config": "1.0.0",
"eslint": "9.8.0",
"npm-run-all": "4.1.5",
"prettier": "3.3.2",
"prettier": "3.3.3",
"rimraf": "6.0.1",
"semantic-release": "24.0.0",
"tap": "18.8.0"
"tap": "18.8.0",
"typescript": "5.5.4"
}
}
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