routes/auth.js - git - Webernet Explorer _X
git 🏠 Home 👤 Sign up Self hosted git, retro shell
★ otgit, code hosting from the year 2000 ★
📄 octuna / routes / auth.js
134 lines · 4.8 KB · Raw
1const config = require('../lib/config');
2const auth = require('../lib/auth');
3const limit = require('../lib/limit');
4const data = require('../lib/data');
5const respond = require('../lib/respond');
6const validate = require('../lib/validate');
7 
8const loginLimiter = limit.make(
9 config.get('limits.login.max'),
10 config.get('limits.login.windowMin') * 60000
11);
12const signupLimiter = limit.make(
13 config.get('limits.signup.max'),
14 config.get('limits.signup.windowMin') * 60000
15);
16const writeLimiter = limit.make(
17 config.get('limits.write.max'),
18 config.get('limits.write.windowMin') * 60000
19);
20 
21function signup(req, res) {
22 const ip = respond.clientIp(req);
23 if (!signupLimiter(ip)) return respond.tooMany(res);
24 if (!config.get('auth.allowSignup')) return respond.forbidden(res, 'Signup is disabled');
25 respond.readJson(req, (err, body) => {
26 if (err) return respond.badRequest(res, err.message);
27 const username = String(body.username || '').toLowerCase().trim();
28 const password = String(body.password || '');
29 if (!validate.isValidName(username)) return respond.badRequest(res, 'Invalid username');
30 if (validate.isReservedName(username)) return respond.badRequest(res, 'Username reserved');
31 if (password.length < 8) return respond.badRequest(res, 'Password too short (min 8 chars)');
32 const users = data.users();
33 if (users.has(username)) return respond.json(res, 409, { error: 'Username taken' });
34 const record = {
35 username,
36 ...auth.createPasswordRecord(password),
37 displayName: validate.nonEmptyString(body.displayName, 64)
38 ? String(body.displayName).slice(0, 64)
39 : username,
40 bio: '',
41 createdAt: Date.now()
42 };
43 users.set(username, record);
44 auth.setSessionCookie(res, username);
45 respond.json(res, 201, { ok: true, username });
46 });
47}
48 
49function login(req, res) {
50 const ip = respond.clientIp(req);
51 if (!loginLimiter(ip)) return respond.tooMany(res, 'Too many login attempts, try later');
52 respond.readJson(req, (err, body) => {
53 if (err) return respond.badRequest(res, err.message);
54 const username = String(body.username || '').toLowerCase().trim();
55 const password = String(body.password || '');
56 const user = data.users().get(username);
57 if (!user || !auth.verifyPassword(password, user)) {
58 return respond.json(res, 401, { error: 'Invalid username or password' });
59 }
60 auth.setSessionCookie(res, username);
61 respond.json(res, 200, { ok: true, username });
62 });
63}
64 
65function logout(_req, res) {
66 auth.clearSessionCookie(res);
67 respond.json(res, 200, { ok: true });
68}
69 
70function me(req, res) {
71 const session = auth.getSession(req);
72 if (!session) return respond.json(res, 200, { user: null });
73 const user = data.users().get(session.username);
74 if (!user) return respond.json(res, 200, { user: null });
75 respond.json(res, 200, {
76 user: {
77 username: user.username,
78 displayName: user.displayName,
79 bio: user.bio,
80 createdAt: user.createdAt,
81 isAdmin: session.username === config.get('admin.user')
82 }
83 });
84}
85 
86function changePassword(req, res) {
87 const session = auth.requireAuth(req, res);
88 if (!session) return;
89 const ip = respond.clientIp(req);
90 if (!writeLimiter(ip)) return respond.tooMany(res);
91 respond.readJson(req, (err, body) => {
92 if (err) return respond.badRequest(res, err.message);
93 const current = String(body.current || '');
94 const next = String(body.password || '');
95 if (next.length < 8) return respond.badRequest(res, 'Password too short (min 8 chars)');
96 const users = data.users();
97 const user = users.get(session.username);
98 if (!user || !auth.verifyPassword(current, user)) {
99 return respond.json(res, 401, { error: 'Current password incorrect' });
100 }
101 users.set(session.username, { ...user, ...auth.createPasswordRecord(next) });
102 respond.json(res, 200, { ok: true });
103 });
104}
105 
106function updateProfile(req, res) {
107 const session = auth.requireAuth(req, res);
108 if (!session) return;
109 respond.readJson(req, (err, body) => {
110 if (err) return respond.badRequest(res, err.message);
111 const users = data.users();
112 const user = users.get(session.username);
113 if (!user) return respond.notFound(res);
114 const updated = { ...user };
115 if (validate.nonEmptyString(body.displayName, 64)) {
116 updated.displayName = String(body.displayName).slice(0, 64);
117 }
118 if (typeof body.bio === 'string') {
119 updated.bio = body.bio.slice(0, 256);
120 }
121 users.set(session.username, updated);
122 respond.json(res, 200, { ok: true });
123 });
124}
125 
126module.exports = function register(router) {
127 router.post('/api/signup', signup);
128 router.post('/api/login', login);
129 router.post('/api/logout', logout);
130 router.get('/api/me', me);
131 router.post('/api/me/password', changePassword);
132 router.post('/api/me/profile', updateProfile);
133};
134 
Done 🔒 Internet