server/scripts/console-password.ts
Rama main · réplica de lectura del repositorio original.
// 관리 콘솔(서버 PC 안에서만 열리는 관리 화면) 로그인 정하기 — 서버 PC 에서만 돌린다
// npm run console:password -w server 관리 비밀번호 정하기 (두 번 묻는다, 화면에 안 보인다)
// npm run console:password -w server -- --otp OTP 켜기·다시 만들기 (인증 앱에 키를 등록하고 지금 코드로 확인)
// npm run console:password -w server -- --no-otp OTP 끄기
// npm run console:password -w server -- --off 관리 비밀번호 지우기 (콘솔에 아무도 로그인할 수 없다)
// 바꾸면 열려 있던 콘솔 로그인은 모두 끊긴다. 사람 계정·볼트 암호화와는 관계없다.
import { audit } from '../src/http.ts';
import { HttpError } from '../src/http.ts';
import { config } from '../src/config.ts';
import { checkNewPassword, hashPassword } from '../src/password.ts';
import { newSecret, otpauthUri, sealSecret, verifyTotp } from '../src/totp.ts';
import { CONSOLE_PASSWORD, CONSOLE_TOTP, consoleState, setMeta } from '../src/console/auth.ts';
import { ask } from './prompt.ts';
const args = process.argv.slice(2);
const where = `http://127.0.0.1:${config.consolePort}/admin`;
if (args.includes('--off')) {
setMeta(CONSOLE_PASSWORD, null);
setMeta(CONSOLE_TOTP, null);
audit({ action: 'console_password', detail: { off: true } });
console.log('관리 콘솔 비밀번호와 OTP 를 지웠습니다. 이제 콘솔에 로그인할 수 없습니다.');
process.exit(0);
}
if (args.includes('--no-otp')) {
setMeta(CONSOLE_TOTP, null);
audit({ action: 'console_password', detail: { otp: false } });
console.log('관리 콘솔 OTP 를 껐습니다.');
process.exit(0);
}
if (args.includes('--otp')) {
if (!consoleState().passwordSet) {
console.error('먼저 관리 비밀번호를 정하세요: npm run console:password -w server');
process.exit(1);
}
const secret = newSecret();
console.log('\n인증 앱(Google Authenticator·1Password·Authy 등)에 아래 키를 등록하세요:');
console.log(` 키: ${secret.replace(/(.{4})/g, '$1 ').trim()}`);
console.log(` 주소: ${otpauthUri(secret, 'console')}\n`);
const code = await ask('인증 앱의 지금 6자리 코드: ', { hidden: false });
if (verifyTotp(secret, code.replace(/\s/g, ''), 0) === null) {
console.error('코드가 맞지 않습니다. OTP 는 바뀌지 않았습니다.');
process.exit(1);
}
setMeta(CONSOLE_TOTP, sealSecret(secret, 'console'));
audit({ action: 'console_password', detail: { otp: true } });
console.log(`관리 콘솔 OTP 를 켰습니다. ${where}`);
process.exit(0);
}
const password = await ask('새 관리 비밀번호: ');
const again = await ask('한 번 더: ');
if (password !== again) {
console.error('두 비밀번호가 다릅니다.');
process.exit(1);
}
try {
checkNewPassword(password);
} catch (err) {
console.error(err instanceof HttpError ? err.message : String(err));
process.exit(1);
}
setMeta(CONSOLE_PASSWORD, await hashPassword(password));
audit({ action: 'console_password', detail: { set: true } });
console.log(`관리 콘솔 비밀번호를 정했습니다. 서버 PC 에서 ${where} 를 여세요.`);
if (!consoleState().otp) console.log('OTP 도 켜려면: npm run console:password -w server -- --otp');
process.exit(0);