99 lines
3.4 KiB
JavaScript
99 lines
3.4 KiB
JavaScript
/**
|
|
* Batch user creation script.
|
|
*
|
|
* Usage:
|
|
* node create_users.js user1 pass1 [user2 pass2 ...]
|
|
* node create_users.js --file users.json
|
|
* node create_users.js --interactive
|
|
*
|
|
* JSON format (users.json):
|
|
* [
|
|
* { "username": "user1", "password": "pass1", "role": "user", "expires_at": null },
|
|
* { "username": "user2", "password": "pass2", "role": "user", "expires_at": "2026-12-31" }
|
|
* ]
|
|
*/
|
|
require('dotenv').config({ path: require('path').join(__dirname, '.env') });
|
|
|
|
const fs = require('fs');
|
|
const readline = require('readline');
|
|
const db = require('./db');
|
|
const auth = require('./auth');
|
|
|
|
db.initDB();
|
|
|
|
async function createOne(username, password, role = 'user', expiresAt = null) {
|
|
const existing = db.getUserByUsername(username);
|
|
if (existing) {
|
|
console.log(` [SKIP] '${username}' already exists`);
|
|
return false;
|
|
}
|
|
const hash = await auth.hashPassword(password);
|
|
db.createUser(username, hash, role, expiresAt || null);
|
|
console.log(` [OK] '${username}' created (role: ${role}${expiresAt ? ', expires: ' + expiresAt : ''})`);
|
|
return true;
|
|
}
|
|
|
|
async function main() {
|
|
const args = process.argv.slice(2);
|
|
let created = 0;
|
|
|
|
if (args.length === 0 || args.includes('--interactive') || args.includes('-i')) {
|
|
// ── Interactive mode ──
|
|
console.log('=== Interactive User Creation ===');
|
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
|
|
while (true) {
|
|
const username = await new Promise(resolve => rl.question('\nUsername (empty to finish): ', resolve));
|
|
if (!username) break;
|
|
|
|
const password = await new Promise(resolve => rl.question('Password: ', resolve));
|
|
if (!password) { console.log(' Password required, skipping.'); continue; }
|
|
|
|
const role = await new Promise(resolve => rl.question('Role [user/admin] (default: user): ', resolve));
|
|
const expires = await new Promise(resolve => rl.question('Expiry YYYY-MM-DD (default: never): ', resolve));
|
|
|
|
if (await createOne(username, password, role || 'user', expires || null)) created++;
|
|
}
|
|
rl.close();
|
|
|
|
} else if (args.includes('--file') || args.includes('-f')) {
|
|
// ── JSON file mode ──
|
|
const fileIdx = args.indexOf('--file');
|
|
const fIdx = args.indexOf('-f');
|
|
const filePath = args[fileIdx !== -1 ? fileIdx + 1 : fIdx + 1];
|
|
|
|
if (!filePath || !fs.existsSync(filePath)) {
|
|
console.error('File not found:', filePath);
|
|
process.exit(1);
|
|
}
|
|
|
|
const users = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
if (!Array.isArray(users)) {
|
|
console.error('JSON must be an array of user objects.');
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`Creating ${users.length} users from ${filePath}...\n`);
|
|
for (const u of users) {
|
|
if (await createOne(u.username, u.password, u.role || 'user', u.expires_at || null)) created++;
|
|
}
|
|
|
|
} else {
|
|
// ── CLI args mode: pairs of username password ──
|
|
if (args.length % 2 !== 0) {
|
|
console.error('Arguments must be in pairs: username password [username password ...]');
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`Creating ${args.length / 2} users...\n`);
|
|
for (let i = 0; i < args.length; i += 2) {
|
|
if (await createOne(args[i], args[i + 1])) created++;
|
|
}
|
|
}
|
|
|
|
console.log(`\nDone. ${created} user(s) created.`);
|
|
process.exit(0);
|
|
}
|
|
|
|
main().catch(err => { console.error('Error:', err); process.exit(1); });
|