Add Prettier and ESLint tooling (Refs #77)
This commit is contained in:
+47
-18
@@ -18,38 +18,67 @@ function secret(prompt) {
|
||||
process.stdout.write('\n');
|
||||
};
|
||||
const listener = (text, key) => {
|
||||
if (key?.ctrl && key.name === 'c') { cleanup(); reject(new Error('Cancelled.')); }
|
||||
else if (key?.name === 'return' || key?.name === 'enter') { cleanup(); resolve(value); }
|
||||
else if (key?.name === 'backspace') value = [...value].slice(0,-1).join('');
|
||||
else if (text && !key?.ctrl && !key?.meta && !/[\x00-\x1f\x7f]/.test(text) && [...value].length < 128) value += text;
|
||||
if (key?.ctrl && key.name === 'c') {
|
||||
cleanup();
|
||||
reject(new Error('Cancelled.'));
|
||||
} else if (key?.name === 'return' || key?.name === 'enter') {
|
||||
cleanup();
|
||||
resolve(value);
|
||||
} else if (key?.name === 'backspace') value = [...value].slice(0, -1).join('');
|
||||
else if (
|
||||
text &&
|
||||
!key?.ctrl &&
|
||||
!key?.meta &&
|
||||
// eslint-disable-next-line no-control-regex -- Reject terminal control characters while collecting password input.
|
||||
!/[\x00-\x1f\x7f]/.test(text) &&
|
||||
[...value].length < 128
|
||||
)
|
||||
value += text;
|
||||
};
|
||||
process.stdin.on('keypress',listener);
|
||||
process.stdin.on('keypress', listener);
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const username = process.argv[2]?.toLowerCase();
|
||||
if (process.argv.length !== 3 || !username || !/^[a-z0-9][a-z0-9_.-]{2,63}$/.test(username)) throw new Error('Usage: node scripts/reset-admin.mjs <administrator-username>');
|
||||
if (!process.stdin.isTTY) throw new Error('Run this command in an interactive terminal. Passwords are never accepted as command arguments.');
|
||||
const database = new Database(process.env.DB_PATH || './data/cherry.db',{fileMustExist:true});
|
||||
if (process.argv.length !== 3 || !username || !/^[a-z0-9][a-z0-9_.-]{2,63}$/.test(username))
|
||||
throw new Error('Usage: node scripts/reset-admin.mjs <administrator-username>');
|
||||
if (!process.stdin.isTTY)
|
||||
throw new Error(
|
||||
'Run this command in an interactive terminal. Passwords are never accepted as command arguments.'
|
||||
);
|
||||
const database = new Database(process.env.DB_PATH || './data/cherry.db', {
|
||||
fileMustExist: true
|
||||
});
|
||||
database.pragma('busy_timeout=5000');
|
||||
const user = database.prepare("SELECT id FROM auth_users WHERE username=? AND role='admin' AND disabled=0").get(username);
|
||||
const user = database
|
||||
.prepare("SELECT id FROM auth_users WHERE username=? AND role='admin' AND disabled=0")
|
||||
.get(username);
|
||||
if (!user) throw new Error('An enabled administrator with that username was not found.');
|
||||
const password = await secret('New administrator password (8–128 characters): ');
|
||||
const confirmation = await secret('Repeat password: ');
|
||||
if (password !== confirmation) throw new Error('Passwords did not match.');
|
||||
const passwordHash = await hashPassword(password);
|
||||
database.transaction(() => {
|
||||
const changed = database.prepare("UPDATE auth_users SET password_hash=?,must_change_password=0,updated_at=? WHERE id=? AND role='admin' AND disabled=0")
|
||||
.run(passwordHash,Date.now(),user.id);
|
||||
if (changed.changes !== 1) throw new Error('Administrator changed during recovery. Try again.');
|
||||
database.prepare('DELETE FROM auth_sessions WHERE user_id=?').run(user.id);
|
||||
database.prepare('INSERT INTO auth_audit(actor_id,action,target_id,details,created_at) VALUES(NULL,?,?,?,?)')
|
||||
.run('password.recovered',user.id,'{"source":"local-cli"}',Date.now());
|
||||
}).immediate();
|
||||
database
|
||||
.transaction(() => {
|
||||
const changed = database
|
||||
.prepare(
|
||||
"UPDATE auth_users SET password_hash=?,must_change_password=0,updated_at=? WHERE id=? AND role='admin' AND disabled=0"
|
||||
)
|
||||
.run(passwordHash, Date.now(), user.id);
|
||||
if (changed.changes !== 1)
|
||||
throw new Error('Administrator changed during recovery. Try again.');
|
||||
database.prepare('DELETE FROM auth_sessions WHERE user_id=?').run(user.id);
|
||||
database
|
||||
.prepare(
|
||||
'INSERT INTO auth_audit(actor_id,action,target_id,details,created_at) VALUES(NULL,?,?,?,?)'
|
||||
)
|
||||
.run('password.recovered', user.id, '{"source":"local-cli"}', Date.now());
|
||||
})
|
||||
.immediate();
|
||||
database.close();
|
||||
console.log('Administrator password reset. Existing sessions have been revoked.');
|
||||
} catch (cause) {
|
||||
console.error(cause instanceof Error ? cause.message : 'Administrator recovery failed.');
|
||||
process.exitCode=1;
|
||||
process.exitCode = 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user