xypriss-security
Version:
Advanced High-Performance Security Framework. Military-grade encryption, post-quantum resilience, and fortified data structures.
202 lines • 8.78 kB
JavaScript
;
/***************************************************************************
* XyPriss Security - Advanced Hyper-Modular Security Framework
*
* @author NEHONIX (Nehonix-Team - https://github.com/Nehonix-Team)
* @license Nehonix Open Source License (NOSL)
*
* Copyright (c) 2025 NEHONIX. All rights reserved.
****************************************************************************/
Object.defineProperty(exports, "__esModule", { value: true });
exports.EFF_FILENAMES = exports.MAX_GENERATE_LENGTH = exports.MIN_GENERATE_LENGTH = exports.CHARSETS = void 0;
exports.loadEFFWordlist = loadEFFWordlist;
exports.getWordlist = getWordlist;
const fs_1 = require("fs");
const path_1 = require("path");
const constants_1 = require("../utils/constants");
const FALLBACK_WORDLIST_1 = require("./FALLBACK_WORDLIST");
// ─── Character Sets ───────────────────────────────────────────────────────────
exports.CHARSETS = {
uppercase: constants_1.CHAR_SETS.UPPERCASE,
lowercase: constants_1.CHAR_SETS.LOWERCASE,
numbers: constants_1.CHAR_SETS.NUMBERS,
symbols: constants_1.CHAR_SETS.SYMBOLS,
similarChars: constants_1.CHAR_SETS.RSIMILAR_CHARS,
};
/** Minimum length enforced on every `generate()` call. */
exports.MIN_GENERATE_LENGTH = 8;
/** Maximum length enforced on every `generate()` call. */
exports.MAX_GENERATE_LENGTH = 512;
/**
* Canonical filenames used by the EFF for each wordlist variant.
* Match the files available at:
* https://www.eff.org/files/2016/07/18/eff_large_wordlist.txt
* https://www.eff.org/files/2016/09/08/eff_short_wordlist_1.txt
* https://www.eff.org/files/2016/09/08/eff_short_wordlist_2_0.txt
*/
exports.EFF_FILENAMES = {
large: "eff_large_wordlist.txt",
short1: "eff_short_wordlist_1.txt",
short2: "eff_short_wordlist_2_0.txt",
};
/**
* Parses a raw EFF `.txt` wordlist file and returns a deduplicated,
* validated `readonly string[]` ready for use in `generatePassphrase()`.
*
* **Supported line formats (both are handled automatically):**
* ```
* # Numbered (dice-index prefix, tab-separated):
* 11111\tabacus
* 11112\tabrupt
*
* # Plain (one word per line):
* abacus
* abrupt
* ```
*
* Lines that are empty, start with `#`, or produce a word of length < 2
* after stripping are silently ignored.
*
* @param options - File location and variant configuration.
* @returns A readonly array of lowercased, trimmed words.
* @throws `Error` if the file cannot be read or yields fewer than 10 words.
*
* @example
* // Load from ./wordlists/eff_large_wordlist.txt
* const words = loadEFFWordlist({ dir: "./wordlists", variant: "large" });
*
* @example
* // Load a custom EFF-format file
* const words = loadEFFWordlist({ filePath: "/opt/security/my_words.txt" });
*/
function loadEFFWordlist(options = {}) {
const { dir, variant = "large", filePath } = options;
// ── Resolve path ────────────────────────────────────────────────────────────
let absolutePath;
if (filePath) {
absolutePath = (0, path_1.resolve)(filePath);
}
else if (dir) {
absolutePath = (0, path_1.resolve)(dir, exports.EFF_FILENAMES[variant]);
}
else {
const fs = require("fs");
const targetFile = exports.EFF_FILENAMES[variant];
const possiblePaths = [
// 1. Direct sibling (production: dist/src/mods or dev: src/mods)
(0, path_1.resolve)(__dirname, targetFile),
// 2. process.cwd() fallback
(0, path_1.resolve)(process.cwd(), "src", "mods", targetFile),
(0, path_1.resolve)(process.cwd(), "dist", "src", "mods", targetFile),
// 3. node_modules lookup
(0, path_1.resolve)(process.cwd(), "node_modules", "xypriss-security", "dist", "src", "mods", targetFile),
];
for (const p of possiblePaths) {
try {
if (fs.existsSync(p)) {
const stats = fs.statSync(p);
if (stats.isFile()) {
absolutePath = p;
break;
}
}
}
catch (e) {
// Ignore errors for specific path checks
}
}
if (!absolutePath) {
// Final fallback (will trigger caught exception in the read step)
absolutePath = (0, path_1.resolve)(__dirname, targetFile);
}
}
// ── Read file ───────────────────────────────────────────────────────────────
let raw;
try {
raw = (0, fs_1.readFileSync)(absolutePath, "utf-8");
}
catch (err) {
const msg = err instanceof Error ? err.message : String(err);
throw new Error(`loadEFFWordlist: could not read wordlist file at "${absolutePath}". ` +
`Ensure the EFF .txt file is present in the specified directory.\n` +
`Original error: ${msg}`);
}
// ── Parse lines ─────────────────────────────────────────────────────────────
const seen = new Set();
const words = [];
for (const rawLine of raw.split(/\r?\n/)) {
const line = rawLine.trim();
// Skip blank lines and comments
if (line.length === 0 || line.startsWith("#"))
continue;
// Numbered format: "11111\tword" or "1-1-1-1-1\tword"
// Plain format: "word"
const word = line.includes("\t")
? line.split("\t")[1]?.trim().toLowerCase()
: line.toLowerCase();
if (!word || word.length < 2)
continue;
// Deduplicate (paranoid guard — EFF lists should already be unique)
if (!seen.has(word)) {
seen.add(word);
words.push(word);
}
}
const WMLIMIT = 10;
// ── Validate result ─────────────────────────────────────────────────────────
if (words.length < WMLIMIT) {
throw new Error(`loadEFFWordlist: file "${absolutePath}" yielded only ${words.length} valid word(s). ` +
`Expected an EFF wordlist with at least ${WMLIMIT} entries.`);
}
return Object.freeze(words);
}
/**
* Unified wordlist accessor: tries to load an EFF file, falls back to the
* built-in list according to `allowFallback`.
*
* Use this function in `PasswordManager.generatePassphrase()` to stay
* decoupled from both the file system and the hardcoded list.
*
* @param options - File location, variant, and fallback policy.
* @returns A readonly array of words suitable for passphrase generation.
*
* @example
* // Prefer the large EFF list; warn & fall back if absent
* const words = getWordlist({ dir: "./assets/wordlists", variant: "large" });
*
* @example
* // Never fall back — throw if the file is missing
* const words = getWordlist({ filePath: "./eff_large_wordlist.txt", allowFallback: false });
*
* @example
* // Only use the built-in list (no file needed)
* const words = getWordlist({ allowFallback: "silent" });
* // → returns FALLBACK_WORDLIST without attempting any file read
*/
function getWordlist(options = {}) {
const { allowFallback = "warn", ...loadOptions } = options;
// If no file location is specified and fallback is allowed, skip the I/O
// entirely and return the built-in list immediately.
const hasFileHint = Boolean(loadOptions.filePath ?? loadOptions.dir);
if (!hasFileHint && allowFallback !== false) {
if (allowFallback === "warn") {
console.warn("[PasswordMDict] No EFF wordlist path provided. " +
"Using built-in 256-word fallback list. " +
"For production use, supply `dir` or `filePath` pointing to an EFF .txt file.");
}
return FALLBACK_WORDLIST_1.FALLBACK_WORDLIST;
}
try {
return loadEFFWordlist(loadOptions);
}
catch (err) {
if (allowFallback === false)
throw err;
if (allowFallback === "warn") {
console.warn(`[PasswordMDict] Failed to load EFF wordlist: ${err.message}\n` +
`Falling back to built-in 256-word list.`);
}
return FALLBACK_WORDLIST_1.FALLBACK_WORDLIST;
}
}
//# sourceMappingURL=PasswordMDict.js.map