const express = require('express') const { body } = require('express-validator') const { login, refresh, logout } = require('./mobile.controller') const { requireAuth } = require('../../../auth/session.middleware') const { loginLimiter, mobileRefreshLimiter } = require('../../../middleware/rateLimit') const { slowLogin, backoffGuard } = require('../../../middleware/loginProtection') const validate = require('../../../middleware/validate') const mobileSsoRouter = require('./mobileSso.routes') const mobileRouter = express.Router() // Native SSO authorization bridge (M9) — /auth/mobile/sso/{start,exchange}. // Additive alongside the credential login below; reuses the website SSO flow and // terminates in the same bearer tokens. mobileRouter.use('/sso', mobileSsoRouter) // Mobile login is a credential surface too, so it sits behind the SAME guards as // web login (cheapest rejection first): per-IP backoff → progressive slowdown → // hard rate cap. const loginGuards = [backoffGuard, slowLogin, loginLimiter] // POST /auth/mobile/login — { username, password, code? } mobileRouter.post( '/login', // #swagger.tags = ['Auth · Mobile'] // #swagger.summary = 'Native login → access + refresh tokens' // #swagger.description = 'Bearer-token login for native clients. Single-request 2FA: if the account has TOTP on and no/invalid code is supplied, returns 401 { totpRequired: true } and the client retries with a code.' /* #swagger.requestBody = { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/MobileLoginRequest" } } } } */ /* #swagger.responses[200] = { description: 'Access + refresh tokens', content: { "application/json": { schema: { $ref: "#/components/schemas/MobileTokenResponse" } } } } */ /* #swagger.responses[400] = { description: 'Validation error', content: { "application/json": { schema: { $ref: "#/components/schemas/ValidationError" } } } } */ /* #swagger.responses[401] = { description: 'Invalid credentials, or a TOTP code is required', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */ /* #swagger.responses[429] = { description: 'Too many attempts (rate limited / backoff)', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */ ...loginGuards, body('username').isString().trim().notEmpty(), body('password').isString().notEmpty(), // Optional TOTP code (single-request 2FA); only checked when the account has 2FA on. body('code').optional().isString().trim().isLength({ min: 6, max: 8 }), // Optional friendly device label for the Active Devices list. body('device_name').optional({ values: 'falsy' }).isString().trim().isLength({ max: 100 }), validate, login, ) // POST /auth/mobile/refresh — { refreshToken } mobileRouter.post( '/refresh', // #swagger.tags = ['Auth · Mobile'] // #swagger.summary = 'Rotate a refresh token for a fresh token pair' // #swagger.description = 'Refresh tokens are single-use: the presented token is revoked and a new access + refresh pair is issued. Reusing a rotated token fails with 401.' /* #swagger.requestBody = { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/MobileRefreshRequest" } } } } */ /* #swagger.responses[200] = { description: 'New access + refresh tokens', content: { "application/json": { schema: { $ref: "#/components/schemas/MobileTokenResponse" } } } } */ /* #swagger.responses[400] = { description: 'Validation error', content: { "application/json": { schema: { $ref: "#/components/schemas/ValidationError" } } } } */ /* #swagger.responses[401] = { description: 'Invalid or expired session', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */ /* #swagger.responses[429] = { description: 'Too many refresh attempts', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */ mobileRefreshLimiter, body('refreshToken').isString().notEmpty(), validate, refresh, ) // POST /auth/mobile/logout — { refreshToken?, all? } — requires a valid bearer. mobileRouter.post( '/logout', // #swagger.tags = ['Auth · Mobile'] // #swagger.summary = 'Revoke the current (or all) refresh tokens' // #swagger.description = 'Requires a valid bearer access token. Revokes the given refresh token, or every session for the user when { all: true }. Idempotent.' // #swagger.security = [{ "bearerAuth": [] }] /* #swagger.requestBody = { content: { "application/json": { schema: { $ref: "#/components/schemas/MobileLogoutRequest" } } } } */ /* #swagger.responses[200] = { description: 'Logged out', content: { "application/json": { schema: { $ref: "#/components/schemas/Message" } } } } */ /* #swagger.responses[401] = { description: 'Missing or invalid bearer token', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */ requireAuth, body('refreshToken').optional().isString(), body('all').optional().isBoolean(), validate, logout, ) module.exports = mobileRouter