main
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* 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); });
|
||||
Reference in New Issue
Block a user