Initial commit: PicUpper webcam upload service
This commit is contained in:
139
users.js
Normal file
139
users.js
Normal file
@@ -0,0 +1,139 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import crypto from 'crypto';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const USERS_FILE = process.env.PICUPPER_USERS_FILE || path.join(__dirname, 'users.json');
|
||||
|
||||
/**
|
||||
* Load users from JSON file
|
||||
*/
|
||||
export function loadUsers() {
|
||||
if (!fs.existsSync(USERS_FILE)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
try {
|
||||
const data = fs.readFileSync(USERS_FILE, 'utf-8');
|
||||
return JSON.parse(data);
|
||||
} catch (error) {
|
||||
console.error('Error loading users file:', error.message);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save users to JSON file
|
||||
*/
|
||||
export function saveUsers(users) {
|
||||
fs.writeFileSync(USERS_FILE, JSON.stringify(users, null, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a secure API key
|
||||
*/
|
||||
export function generateApiKey() {
|
||||
return crypto.randomBytes(32).toString('hex');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new user with generated API key
|
||||
*/
|
||||
export function addUser(username, description = '') {
|
||||
const users = loadUsers();
|
||||
|
||||
if (users[username]) {
|
||||
throw new Error(`User '${username}' already exists`);
|
||||
}
|
||||
|
||||
const apiKey = generateApiKey();
|
||||
|
||||
users[username] = {
|
||||
apiKey,
|
||||
description,
|
||||
createdAt: new Date().toISOString(),
|
||||
enabled: true
|
||||
};
|
||||
|
||||
saveUsers(users);
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user
|
||||
*/
|
||||
export function removeUser(username) {
|
||||
const users = loadUsers();
|
||||
|
||||
if (!users[username]) {
|
||||
throw new Error(`User '${username}' not found`);
|
||||
}
|
||||
|
||||
delete users[username];
|
||||
saveUsers(users);
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerate API key for a user
|
||||
*/
|
||||
export function regenerateApiKey(username) {
|
||||
const users = loadUsers();
|
||||
|
||||
if (!users[username]) {
|
||||
throw new Error(`User '${username}' not found`);
|
||||
}
|
||||
|
||||
const newApiKey = generateApiKey();
|
||||
users[username].apiKey = newApiKey;
|
||||
users[username].keyRegeneratedAt = new Date().toISOString();
|
||||
|
||||
saveUsers(users);
|
||||
return newApiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable a user
|
||||
*/
|
||||
export function setUserEnabled(username, enabled) {
|
||||
const users = loadUsers();
|
||||
|
||||
if (!users[username]) {
|
||||
throw new Error(`User '${username}' not found`);
|
||||
}
|
||||
|
||||
users[username].enabled = enabled;
|
||||
saveUsers(users);
|
||||
}
|
||||
|
||||
/**
|
||||
* List all users (without exposing full API keys)
|
||||
*/
|
||||
export function listUsers() {
|
||||
const users = loadUsers();
|
||||
|
||||
return Object.entries(users).map(([username, data]) => ({
|
||||
username,
|
||||
description: data.description,
|
||||
createdAt: data.createdAt,
|
||||
enabled: data.enabled,
|
||||
keyPreview: data.apiKey.substring(0, 8) + '...'
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an API key and return the username if valid
|
||||
*/
|
||||
export function validateApiKey(apiKey) {
|
||||
const users = loadUsers();
|
||||
|
||||
for (const [username, data] of Object.entries(users)) {
|
||||
if (data.apiKey === apiKey && data.enabled) {
|
||||
return username;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user