import * as userService from '../services/authService.js'; import * as oauthService from '../services/oauthService.js'; class AuthController { constructor() { this.register = this.register.bind(this); this.login = this.login.bind(this); this.forgotPassword = this.forgotPassword.bind(this); this.activateAccount = this.activateAccount.bind(this); this.logout = this.logout.bind(this); this.oauthProviders = this.oauthProviders.bind(this); this.oauthStart = this.oauthStart.bind(this); this.oauthExchange = this.oauthExchange.bind(this); this.oauthUserIdentities = this.oauthUserIdentities.bind(this); this.oauthUserStart = this.oauthUserStart.bind(this); this.oauthUserExchange = this.oauthUserExchange.bind(this); this.oauthUserRemove = this.oauthUserRemove.bind(this); } async register(req, res) { const { email, username, password, language } = req.body; try { const result = await userService.registerUser({ email, username, password, language }); res.status(201).json(result); } catch (error) { console.log(error); res.status(500).json({ error: error.message }); } } async login(req, res) { const { username, password } = req.body; try { const result = await userService.loginUser({ username, password }); console.log('User logged in successfully', result); res.status(200).json(result); } catch (error) { if (error.message === 'credentialsinvalid') { res.status(404).json({ error: error.message }); } else if (error.message === 'userblocked') { res.status(403).json({ error: error.message }); } else { res.status(500).json({ error: error.message }); } } } async logout(req, res) { const { userid: hashedUserId } = req.headers; await userService.logoutUser(hashedUserId); res.status(200).json({ result: 'loggedout' }); } async oauthProviders(req, res) { try { const providers = await oauthService.getOAuthProviders(); res.status(200).json({ providers }); } catch (error) { res.status(500).json({ error: error.message }); } } async oauthStart(req, res) { const { provider } = req.params; try { const redirectTo = await oauthService.startOAuthLogin({ providerSlug: provider }); res.redirect(302, redirectTo.toString()); } catch (error) { const status = error.message === 'providernotconfigured' ? 503 : 500; res.status(status).json({ error: error.message }); } } async oauthExchange(req, res) { const { code, state, iss } = req.body; try { const result = await oauthService.exchangeOAuthLogin({ code, state, iss }); res.status(200).json(result); } catch (error) { const knownErrors = new Set([ 'oauthcodemissing', 'oauthstatemissing', 'oauthsubjectmissing', 'providernotconfigured', 'oauthidentityconflict' ]); const status = knownErrors.has(error.message) ? 400 : 500; res.status(status).json({ error: error.message }); } } async oauthUserIdentities(req, res) { const { userid: hashedUserId } = req.headers; try { const User = (await import('../models/community/user.js')).default; const user = await User.findOne({ where: { hashedId: hashedUserId } }); if (!user) { return res.status(404).json({ error: 'usernotfound' }); } const identities = await oauthService.getUserOAuthIdentities(user.id); res.status(200).json({ identities }); } catch (error) { res.status(500).json({ error: error.message }); } } async oauthUserStart(req, res) { const hashedUserId = req.headers.userid || req.query.userid; const { provider } = req.params; try { const User = (await import('../models/community/user.js')).default; const user = await User.findOne({ where: { hashedId: hashedUserId } }); if (!user) { return res.status(404).json({ error: 'usernotfound' }); } const redirectTo = await oauthService.startOAuthLoginForUser({ userId: user.id, providerSlug: provider }); res.redirect(302, redirectTo.toString()); } catch (error) { const status = error.message === 'providernotconfigured' ? 503 : 500; res.status(status).json({ error: error.message }); } } async oauthUserExchange(req, res) { const hashedUserId = req.headers.userid || req.query.userid; const { code, state, iss } = req.body; try { const User = (await import('../models/community/user.js')).default; const user = await User.findOne({ where: { hashedId: hashedUserId } }); if (!user) { return res.status(404).json({ error: 'usernotfound' }); } const result = await oauthService.exchangeOAuthLoginForUser({ userId: user.id, code, state, iss }); res.status(200).json(result); } catch (error) { const knownErrors = new Set([ 'oauthcodemissing', 'oauthstatemissing', 'oauthsubjectmissing', 'providernotconfigured', 'oauthuseridmismatch', 'oauthidentityalreadylinked' ]); const status = knownErrors.has(error.message) ? 400 : 500; res.status(status).json({ error: error.message }); } } async oauthUserRemove(req, res) { const { userid: hashedUserId } = req.headers; const { identityId } = req.params; try { const User = (await import('../models/community/user.js')).default; const user = await User.findOne({ where: { hashedId: hashedUserId } }); if (!user) { return res.status(404).json({ error: 'usernotfound' }); } const result = await oauthService.removeOAuthIdentity({ userId: user.id, identityId: parseInt(identityId, 10) }); res.status(200).json(result); } catch (error) { const status = error.message === 'forbidden' ? 403 : 500; res.status(status).json({ error: error.message }); } } async forgotPassword(req, res) { const { email } = req.body; try { const result = await userService.handleForgotPassword({ email }); res.status(200).json(result); } catch (error) { res.status(500).json({ error: error.message }); } } async activateAccount(req, res) { const { token } = req.body; try { const result = await userService.activateUserAccount({ token }); res.status(200).json(result); } catch (error) { res.status(500).json({ error: error.message }); } } } export default AuthController;