Socket
Socket
Sign inDemoInstall

metautil

Package Overview
Dependencies
Maintainers
1
Versions
56
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

metautil - npm Package Compare versions

Comparing version 3.2.0 to 3.3.0

lib/security.js

9

CHANGELOG.md

@@ -5,2 +5,8 @@ # Changelog

## [3.3.0][] - 2021-02-19
- Change library file structure
- Move Semaphore from metacom with fixes
- Move timeout function from metacom
## [3.2.0][] - 2021-02-03

@@ -32,3 +38,4 @@

[unreleased]: https://github.com/metarhia/metautil/compare/v3.2.0...HEAD
[unreleased]: https://github.com/metarhia/metautil/compare/v3.3.0...HEAD
[3.3.0]: https://github.com/metarhia/metautil/compare/v3.2.0...v3.3.0
[3.2.0]: https://github.com/metarhia/metautil/compare/v3.1.0...v3.2.0

@@ -35,0 +42,0 @@ [3.1.0]: https://github.com/metarhia/metautil/compare/v3.0.1...v3.1.0

282

metautil.js
'use strict';
const path = require('path');
const crypto = require('crypto');
const utilities = require('./lib/utilities.js');
const secutity = require('./lib/security.js');
const semaphore = require('./lib/semaphore.js');
const random = (min, max) => {
if (max === undefined) {
max = min;
min = 0;
}
return min + Math.floor(Math.random() * (max - min + 1));
};
const UINT32_MAX = 0xffffffff;
const BUF_LEN = 1024;
const BUF_SIZE = BUF_LEN * Uint32Array.BYTES_PER_ELEMENT;
const randomPrefetcher = {
buf: crypto.randomBytes(BUF_SIZE),
pos: 0,
};
const cryptoRandom = () => {
if (randomPrefetcher.pos === randomPrefetcher.buf.length) {
randomPrefetcher.pos = 0;
crypto.randomFillSync(randomPrefetcher.buf);
}
const val = randomPrefetcher.buf.readUInt32LE(randomPrefetcher.pos);
randomPrefetcher.pos += Uint32Array.BYTES_PER_ELEMENT;
return val / (UINT32_MAX + 1);
};
const sample = (arr) => {
const index = Math.floor(Math.random() * arr.length);
return arr[index];
};
const ipToInt = (ip = '127.0.0.1') => {
if (ip === '') return 0;
const bytes = ip.split('.');
let res = 0;
for (const byte of bytes) {
res = (res << 8) + parseInt(byte, 10);
}
return res;
};
const parseHost = (host) => {
if (!host) {
return 'no-host-name-in-http-headers';
}
const portOffset = host.indexOf(':');
if (portOffset > -1) host = host.substr(0, portOffset);
return host;
};
const replace = (str, substr, newstr) => {
if (substr === '') return str;
let src = str;
let res = '';
do {
const index = src.indexOf(substr);
if (index === -1) return res + src;
const start = src.substring(0, index);
src = src.substring(index + substr.length, src.length);
res += start + newstr;
} while (true);
};
const fileExt = (fileName) => {
const ext = path.extname(fileName).toLowerCase();
return replace(ext, '.', '');
};
const between = (s, prefix, suffix) => {
let i = s.indexOf(prefix);
if (i === -1) return '';
s = s.substring(i + prefix.length);
if (suffix) {
i = s.indexOf(suffix);
if (i === -1) return '';
s = s.substring(0, i);
}
return s;
};
const isFirstUpper = (s) => !!s && s[0] === s[0].toUpperCase();
const isConstant = (s) => s === s.toUpperCase();
const twoDigit = (n) => {
const s = n.toString();
if (n < 10) return '0' + s;
return s;
};
const nowDate = (date) => {
if (!date) date = new Date();
const yyyy = date.getUTCFullYear().toString();
const mm = twoDigit(date.getUTCMonth() + 1);
const dd = twoDigit(date.getUTCDate());
return `${yyyy}-${mm}-${dd}`;
};
const DURATION_UNITS = {
d: 86400, // days
h: 3600, // hours
m: 60, // minutes
s: 1, // seconds
};
const duration = (s) => {
if (typeof s === 'number') return s;
if (typeof s !== 'string') return 0;
let result = 0;
const parts = s.split(' ');
for (const part of parts) {
const unit = part.slice(-1);
const value = parseInt(part.slice(0, -1));
const mult = DURATION_UNITS[unit];
if (!isNaN(value) && mult) result += value * mult;
}
return result * 1000;
};
const generateKey = (length, possible) => {
const base = possible.length;
let key = '';
for (let i = 0; i < length; i++) {
const index = Math.floor(cryptoRandom() * base);
key += possible[index];
}
return key;
};
const crcToken = (secret, key) => {
const md5 = crypto.createHash('md5').update(key + secret);
return md5.digest('hex').substring(0, 4);
};
const generateToken = (secret, characters, length) => {
const key = generateKey(length - 4, characters);
return key + crcToken(secret, key);
};
const validateToken = (secret, token) => {
if (!token) return false;
const len = token.length;
const crc = token.slice(len - 4);
const key = token.slice(0, -4);
return crcToken(secret, key) === crc;
};
const makePrivate = (instance) => {
const iface = {};
const fields = Object.keys(instance);
for (const fieldName of fields) {
const field = instance[fieldName];
if (isConstant(fieldName)) {
iface[fieldName] = field;
} else if (typeof field === 'function') {
const bindedMethod = field.bind(instance);
iface[fieldName] = bindedMethod;
instance[fieldName] = bindedMethod;
}
}
return iface;
};
const protect = (allowMixins, ...namespaces) => {
for (const namespace of namespaces) {
const names = Object.keys(namespace);
for (const name of names) {
const target = namespace[name];
if (!allowMixins.includes(name)) Object.freeze(target);
}
}
};
const parseCookies = (cookie) => {
const values = {};
const items = cookie.split(';');
for (const item of items) {
const parts = item.split('=');
const key = parts[0].trim();
const val = parts[1] || '';
values[key] = val.trim();
}
return values;
};
// Only change these if you know what you're doing
const SCRYPT_PARAMS = { N: 32768, r: 8, p: 1, maxmem: 64 * 1024 * 1024 };
const SCRYPT_PREFIX = '$scrypt$N=32768,r=8,p=1,maxmem=67108864$';
const serializeHash = (hash, salt) => {
const saltString = salt.toString('base64').split('=')[0];
const hashString = hash.toString('base64').split('=')[0];
return `${SCRYPT_PREFIX}${saltString}$${hashString}`;
};
const deserializeHash = (phcString) => {
const parsed = phcString.split('$');
parsed.shift();
if (parsed[0] !== 'scrypt') {
throw new Error('Node.js crypto module only supports scrypt');
}
const params = Object.fromEntries(
parsed[1].split(',').map((p) => {
const kv = p.split('=');
kv[1] = Number(kv[1]);
return kv;
})
);
const salt = Buffer.from(parsed[2], 'base64');
const hash = Buffer.from(parsed[3], 'base64');
return { params, salt, hash };
};
const SALT_LEN = 32;
const KEY_LEN = 64;
const hashPassword = (password) =>
new Promise((resolve, reject) => {
crypto.randomBytes(SALT_LEN, (err, salt) => {
if (err) {
reject(err);
return;
}
crypto.scrypt(password, salt, KEY_LEN, SCRYPT_PARAMS, (err, hash) => {
if (err) {
reject(err);
return;
}
resolve(serializeHash(hash, salt));
});
});
});
let defaultHash;
hashPassword('').then((hash) => {
defaultHash = hash;
});
const validatePassword = (password, serHash = defaultHash) => {
const { params, salt, hash } = deserializeHash(serHash);
return new Promise((resolve, reject) => {
const callback = (err, hashedPassword) => {
if (err) {
reject(err);
return;
}
resolve(crypto.timingSafeEqual(hashedPassword, hash));
};
crypto.scrypt(password, salt, hash.length, params, callback);
});
};
module.exports = {
sample,
ipToInt,
parseHost,
replace,
fileExt,
between,
isFirstUpper,
isConstant,
nowDate,
duration,
generateKey,
generateToken,
crcToken,
validateToken,
random,
cryptoRandom,
makePrivate,
protect,
parseCookies,
hashPassword,
validatePassword,
};
module.exports = { ...utilities, ...secutity, ...semaphore };
{
"name": "metautil",
"version": "3.2.0",
"version": "3.3.0",
"author": "Timur Shemsedinov <timur.shemsedinov@gmail.com>",

@@ -13,3 +13,5 @@ "license": "MIT",

"main": "metautil.js",
"files": [],
"files": [
"lib/"
],
"engines": {

@@ -37,3 +39,3 @@ "node": "^12.9 || 14 || 15"

"devDependencies": {
"eslint": "^7.19.0",
"eslint": "^7.20.0",
"eslint-config-metarhia": "^7.0.1",

@@ -40,0 +42,0 @@ "eslint-config-prettier": "^7.2.0",

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