first commit
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
const express = require('express');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const sqlite3 = require('sqlite3');
|
||||
const { open } = require('sqlite');
|
||||
|
||||
const JWT_SECRET = 'super-secret-key-change-me';
|
||||
const DB_FILE = './users.db';
|
||||
|
||||
async function initDb() {
|
||||
const db = await open({
|
||||
filename: DB_FILE,
|
||||
driver: sqlite3.Database
|
||||
});
|
||||
await db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
username TEXT PRIMARY KEY,
|
||||
passwordHash TEXT
|
||||
)
|
||||
`);
|
||||
return db;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const db = await initDb();
|
||||
|
||||
if (process.argv.length > 2) {
|
||||
const command = process.argv[2];
|
||||
if (command === 'create') {
|
||||
const username = process.argv[3];
|
||||
if (!username) {
|
||||
console.error('Please provide a username: npm run airclientauth -- create <user>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const user = await db.get('SELECT * FROM users WHERE username = ?', [username]);
|
||||
if (user) {
|
||||
console.error('User already exists.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await db.run('INSERT INTO users (username, passwordHash) VALUES (?, ?)', [username, null]);
|
||||
|
||||
console.log(`User '${username}' created successfully.`);
|
||||
console.log(`Waiting for first login to set the password.`);
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.error('Unknown command. Available commands: create <user>');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
app.post('/login', async (req, res) => {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!username) {
|
||||
return res.status(400).json({ error: 'Username is required' });
|
||||
}
|
||||
|
||||
const user = await db.get('SELECT * FROM users WHERE username = ?', [username]);
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'User not found' });
|
||||
}
|
||||
|
||||
if (!user.passwordHash) {
|
||||
if (password) {
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
const hash = await bcrypt.hash(password, salt);
|
||||
|
||||
await db.run('UPDATE users SET passwordHash = ? WHERE username = ?', [hash, username]);
|
||||
|
||||
const token = jwt.sign({ username }, JWT_SECRET, { expiresIn: '1h' });
|
||||
return res.json({
|
||||
status: 'success',
|
||||
message: 'Password set successfully. Logged in.',
|
||||
token
|
||||
});
|
||||
} else {
|
||||
return res.status(403).json({
|
||||
status: 'require_password',
|
||||
message: 'First login requires setting a password.'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (!password) {
|
||||
return res.status(400).json({ error: 'Password is required' });
|
||||
}
|
||||
|
||||
const isMatch = await bcrypt.compare(password, user.passwordHash);
|
||||
if (!isMatch) {
|
||||
return res.status(401).json({ error: 'Invalid password' });
|
||||
}
|
||||
|
||||
const token = jwt.sign({ username }, JWT_SECRET, { expiresIn: '1h' });
|
||||
return res.json({
|
||||
status: 'success',
|
||||
message: 'Logged in successfully',
|
||||
token
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/verify', (req, res) => {
|
||||
const authHeader = req.headers.authorization;
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
return res.status(401).json({ valid: false, error: 'No token provided' });
|
||||
}
|
||||
|
||||
const token = authHeader.split(' ')[1];
|
||||
try {
|
||||
const decoded = jwt.verify(token, JWT_SECRET);
|
||||
return res.json({ valid: true, user: decoded.username });
|
||||
} catch (err) {
|
||||
return res.status(401).json({ valid: false, error: 'Invalid or expired token' });
|
||||
}
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server running on port ${PORT}`);
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user