9143997f8e
929 problems (928 errors, 1 warning) -> 0, exit 0.
Rule breakdown, which corrects the report's premise -- `indent` dominated, not
`quotes`: indent 719, quotes 68, no-unused-vars 54, no-empty 36,
no-useless-escape 22, no-case-declarations 17, no-inner-declarations 6,
no-control-regex 5, no-useless-catch 1, no-console 1 (warn).
--fix handled only indent + quotes (719+68 = exactly the "fixable" count).
no-useless-escape was NOT auto-fixable in this eslint version, so the one
genuinely risky class never went through the autofixer -- all 22 were done by
hand. Two mechanical proofs on the autofix diff: a token-level AST diff
(espree, before vs after) shows exactly 68 differing tokens, all quotes, with
the 719 indent fixes producing zero token changes; and a cooked-value diff of
every string/template/regex literal shows 0 differences.
Regex escapes: eslint was correctly conservative and did not flag the
load-bearing ones -- \- in [^a-zA-Z0-9_\-\.] (unescaping makes an invalid
reversed _ -> . range) or in [!@#$%^&*()_+\-=...] (would become a + -> = range
silently matching ",-."). Every removal was a \/ \[ or \. inside a character
class; all 11 old/new pairs were brute-forced over 794 inputs with 0
mismatches.
Manual fixes: no-empty were all deliberate best-effort catches around activity
logging, annotated rather than restructured; no-case-declarations braced in
two adminBackup switches; no-inner-declarations converted to const arrows
after checking no call precedes the declaration and no this/arguments use;
no-control-regex and no-console got targeted disables with stated reasons;
one `catch (e) { throw e; }` wrapper removed.
Two unused bindings were near-misses worth noting: secureStatic.js's
`fullPath` is a path-traversal guard (safePathJoin throws on escape) and
restoreService.js's `backupManifest` is the throw-on-corrupt-manifest gate
before a rollback -- deleting either would have silently removed a check. Only
the bindings were dropped; the calls stay.
Two real bugs found and deliberately preserved with a comment plus a narrow
disable rather than deleted, since deleting would erase the evidence:
_workflowSeedBoot.js's `booted` is written but never read, so the intended
once-per-process guard is missing its early return and workflows re-seed on
every call; and quoteService.js's VALID_QUOTE_TRANSITIONS is a full state
machine nothing consults, so quote status changes are unvalidated.
Backend test suite: 253 suites / 2552 tests passing, 0 failures, before and
after.
Refs testplan REPORT.md #22 (Part 1.2.02).
122 lines
3.4 KiB
JavaScript
122 lines
3.4 KiB
JavaScript
const crypto = require('crypto');
|
|
|
|
/**
|
|
* Generate a secure random password
|
|
* @param {number} length - Password length (default: 16)
|
|
* @returns {string} Generated password
|
|
*/
|
|
function generateSecurePassword(length = 16) {
|
|
const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-=[]{}|;:,.<>?';
|
|
let password = '';
|
|
|
|
// Ensure at least one of each required character type
|
|
const lowercase = 'abcdefghijklmnopqrstuvwxyz';
|
|
const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
const numbers = '0123456789';
|
|
const special = '!@#$%^&*()_+-=[]{}|;:,.<>?';
|
|
|
|
// Add one of each required type
|
|
password += lowercase[crypto.randomInt(lowercase.length)];
|
|
password += uppercase[crypto.randomInt(uppercase.length)];
|
|
password += numbers[crypto.randomInt(numbers.length)];
|
|
password += special[crypto.randomInt(special.length)];
|
|
|
|
// Fill the rest randomly
|
|
for (let i = password.length; i < length; i++) {
|
|
password += charset[crypto.randomInt(charset.length)];
|
|
}
|
|
|
|
// Shuffle the password
|
|
return password.split('').sort(() => crypto.randomInt(3) - 1).join('');
|
|
}
|
|
|
|
/**
|
|
* Generate a human-readable password using words and numbers
|
|
* @returns {string} Generated password
|
|
*/
|
|
function generateReadablePassword() {
|
|
const adjectives = [
|
|
'Swift', 'Bright', 'Strong', 'Happy', 'Clever',
|
|
'Brave', 'Noble', 'Quick', 'Sharp', 'Bold'
|
|
];
|
|
|
|
const nouns = [
|
|
'Eagle', 'Mountain', 'River', 'Thunder', 'Forest',
|
|
'Ocean', 'Falcon', 'Dragon', 'Phoenix', 'Tiger'
|
|
];
|
|
|
|
const adjective = adjectives[crypto.randomInt(adjectives.length)];
|
|
const noun = nouns[crypto.randomInt(nouns.length)];
|
|
const number = crypto.randomInt(1000, 9999);
|
|
const special = '!@#$%'[crypto.randomInt(5)];
|
|
|
|
return `${adjective}${noun}${number}${special}`;
|
|
}
|
|
|
|
/**
|
|
* Validate password strength
|
|
* @param {string} password - Password to validate
|
|
* @returns {object} Validation result with score and messages
|
|
*/
|
|
function validatePasswordStrength(password) {
|
|
const result = {
|
|
score: 0,
|
|
messages: [],
|
|
isValid: false
|
|
};
|
|
|
|
// Length check
|
|
if (password.length < 8) {
|
|
result.messages.push('Password must be at least 8 characters long');
|
|
} else if (password.length < 12) {
|
|
result.score += 1;
|
|
} else {
|
|
result.score += 2;
|
|
}
|
|
|
|
// Character type checks
|
|
if (!/[a-z]/.test(password)) {
|
|
result.messages.push('Password must contain lowercase letters');
|
|
} else {
|
|
result.score += 1;
|
|
}
|
|
|
|
if (!/[A-Z]/.test(password)) {
|
|
result.messages.push('Password must contain uppercase letters');
|
|
} else {
|
|
result.score += 1;
|
|
}
|
|
|
|
if (!/[0-9]/.test(password)) {
|
|
result.messages.push('Password must contain numbers');
|
|
} else {
|
|
result.score += 1;
|
|
}
|
|
|
|
if (!/[!@#$%^&*()_+\-=[\]{}|;:,.<>?]/.test(password)) {
|
|
result.messages.push('Password must contain special characters');
|
|
} else {
|
|
result.score += 1;
|
|
}
|
|
|
|
// Common password check
|
|
const commonPasswords = [
|
|
'password', 'admin123', '12345678', 'qwerty', 'abc123',
|
|
'password123', 'admin', 'letmein', 'welcome', 'monkey'
|
|
];
|
|
|
|
if (commonPasswords.includes(password.toLowerCase())) {
|
|
result.score = 0;
|
|
result.messages.push('Password is too common');
|
|
}
|
|
|
|
result.isValid = result.score >= 4 && result.messages.length === 0;
|
|
|
|
return result;
|
|
}
|
|
|
|
module.exports = {
|
|
generateSecurePassword,
|
|
generateReadablePassword,
|
|
validatePasswordStrength
|
|
}; |