UNPKG

@underpostnet/underpost

Version:

Underpost Platform — end-to-end CI/CD and application-delivery toolchain CLI. Covers bare metal, Kubernetes, K3s, kubeadm, LXD, container/image orchestration, secrets, databases, cron jobs, monitoring, SSH, runners, PWA + Workbox delivery, and release orc

368 lines (328 loc) 11.2 kB
import { hashPassword } from '../../server/auth.js'; import fs from 'fs-extra'; import { loggerFactory } from '../../server/logger.js'; import { UserController } from './user.controller.js'; import express from 'express'; import { DataBaseProviderService } from '../../db/DataBaseProvider.js'; const logger = loggerFactory(import.meta); class UserRouter { /** * @param {import('../types.js').RouterOptions} options * @returns {import('express').Router} */ static router(options) { const router = express.Router(); // Admin user seed — fire-and-forget async on first router mount. (async () => { try { const User = DataBaseProviderService.getModel('user', options); const adminUser = await User.findOne({ role: 'admin' }); if (!adminUser) { const defaultPassword = process.env.DEFAULT_ADMIN_PASSWORD || 'changethis'; const hashedPassword = await hashPassword(defaultPassword); const result = await User.create({ username: 'admin', email: process.env.DEFAULT_ADMIN_EMAIL || 'admin@' + options.host, password: hashedPassword, role: 'admin', emailConfirmed: true, publicKey: [], }); logger.warn('Default admin user created. Please change the default password immediately!', { username: result._doc.username, email: result._doc.email, role: result._doc.role, }); } } catch (error) { logger.error('Error checking/creating admin user', { error: error.message }); } // Cache mailer images into options.png so route handlers can serve them // without re-reading the filesystem on every request. options.png = { buffer: { 'invalid-token': fs.readFileSync(`./src/client/public/default/assets/mailer/api-user-invalid-token.png`), recover: fs.readFileSync(`./src/client/public/default/assets/mailer/api-user-recover.png`), check: fs.readFileSync(`./src/client/public/default/assets/mailer/api-user-check.png`), avatar: fs.readFileSync(`./src/client/public/default/assets/mailer/api-user-default-avatar.png`), }, header: (res, req) => { res.set('Cross-Origin-Resource-Policy', 'cross-origin'); res.set('Access-Control-Allow-Headers', '*'); if (req && req.headers && req.headers.origin) { res.set('Access-Control-Allow-Origin', req.headers.origin); } else res.setHeader('Access-Control-Allow-Origin', '*'); res.set('Content-Type', 'image/png'); }, }; })(); router.post(`/mailer/:id`, options.authMiddleware, async (req, res) => { /* #swagger.ignore = true */ return await UserController.post(req, res, options); }); router.get(`/assets/:id`, async (req, res) => { /* #swagger.ignore = true */ return await UserController.get(req, res, options); }); router.get(`/mailer/:id`, async (req, res) => { /* #swagger.ignore = true */ return await UserController.get(req, res, options); }); router.get(`/email/:email`, options.authMiddleware, async (req, res) => { /* #swagger.ignore = true */ return await UserController.get(req, res, options); }); router.post(`/:id`, async (req, res) => { /* #swagger.ignore = true */ return await UserController.post(req, res, options); }); // #swagger.start /* #swagger.auto = false #swagger.tags = ['user'] #swagger.summary = 'Log in' #swagger.description = 'This endpoint get a JWT for authenticated user' #swagger.path = '/user/auth' #swagger.method = 'post' #swagger.responses[200] = { description: 'User created successfully', content: { 'application/json': { schema: { $ref: '#/components/schemas/userResponse' } } } } #swagger.responses[400] = { description: 'Bad request. Please check the input data', content: { 'application/json': { schema: { $ref: '#/components/schemas/userBadRequestResponse' } } } } */ // #swagger.end router.post(`/`, async (req, res) => { /* #swagger.auto = false #swagger.tags = ['user'] #swagger.summary = 'Create user' #swagger.description = 'This endpoint will create a new user account' #swagger.path = '/user' #swagger.method = 'post' #swagger.responses[200] = { description: 'User created successfully', content: { 'application/json': { schema: { $ref: '#/components/schemas/userResponse' } } } } #swagger.responses[400] = { description: 'Bad request. Please check the input data', content: { 'application/json': { schema: { $ref: '#/components/schemas/userBadRequestResponse' } } } } */ return await UserController.post(req, res, options); }); router.get(`/recover/:id`, async (req, res) => { /* #swagger.ignore = true */ return await UserController.get(req, res, options); }); router.get(`/u/:username`, async (req, res) => { /* #swagger.ignore = true */ return await UserController.get(req, res, options); }); router.get(`/:id`, options.authMiddleware, async (req, res) => { /* #swagger.auto = false #swagger.tags = ['user'] #swagger.summary = 'Get user data by ID' #swagger.description = 'This endpoint get user data by ID' #swagger.path = '/user/{id}' #swagger.method = 'get' #swagger.produces = ['application/json'] #swagger.consumes = ['application/json'] #swagger.security = [{ 'bearerAuth': [] }] #swagger.parameters['id'] = { in: 'path', description: 'User ID', required: true, type: 'string' } #swagger.responses[200] = { description: 'get user successfully', content: { 'application/json': { schema: { $ref: '#/components/schemas/userGetResponse' } } } } #swagger.responses[400] = { description: 'Bad request. Please check the input data', content: { 'application/json': { schema: { $ref: '#/components/schemas/userBadRequestResponse' } } } } */ return await UserController.get(req, res, options); }); router.get(`/`, options.authMiddleware, async (req, res) => { /* #swagger.ignore = true */ return await UserController.get(req, res, options); }); router.put(`/recover/:id`, async (req, res) => { /* #swagger.ignore = true */ return await UserController.put(req, res, options); }); router.put(`/profile-image/:id`, options.authMiddleware, async (req, res) => { /* #swagger.ignore = true */ return await UserController.put(req, res, options); }); router.put(`/:id`, options.authMiddleware, async (req, res) => { /* #swagger.auto = false #swagger.tags = ['user'] #swagger.summary = 'Update user data by ID' #swagger.description = 'This endpoint will update user data by ID' #swagger.path = '/user/{id}' #swagger.method = 'put' #swagger.security = [{ 'bearerAuth': [] }] #swagger.parameters['id'] = { in: 'path', description: 'User ID', required: true, type: 'string' } #swagger.responses[200] = { description: 'User updated successfully', content: { 'application/json': { schema: { $ref: '#/components/schemas/userUpdateResponse' } } } } #swagger.responses[400] = { description: 'Bad request. Please check the input data', content: { 'application/json': { schema: { $ref: '#/components/schemas/userBadRequestResponse' } } } } */ return await UserController.put(req, res, options); }); router.put(`/`, options.authMiddleware, async (req, res) => { /* #swagger.ignore = true */ return await UserController.put(req, res, options); }); router.delete(`/:id`, options.authMiddleware, async (req, res) => { /* #swagger.auto = false #swagger.tags = ['user'] #swagger.summary = 'Delete user data by ID' #swagger.description = 'This endpoint deletes user data by ID, the path ID must match with the ID of the authenticated user' #swagger.path = '/user/{id}' #swagger.method = 'delete' #swagger.produces = ['application/json'] #swagger.consumes = ['application/json'] #swagger.security = [{ 'bearerAuth': [] }] #swagger.parameters['id'] = { in: 'path', description: 'User ID', required: true, type: 'string' } #swagger.responses[200] = { description: 'get user successfully', content: { 'application/json': { schema: { $ref: '#/components/schemas/userGetResponse' } } } } #swagger.responses[400] = { description: 'Bad request. Please check the input data', content: { 'application/json': { schema: { $ref: '#/components/schemas/userBadRequestResponse' } } } } */ return await UserController.delete(req, res, options); }); router.delete(`/`, options.authMiddleware, async (req, res) => { /* #swagger.ignore = true */ return await UserController.delete(req, res, options); }); // Username public profile redirect — registered directly on the app so the // /u/:username shortlink works outside the API path prefix. options.app.get(`${options.path === '/' ? '' : options.path}/u/:username`, async (req, res, next) => { /* #swagger.ignore = true */ return res.redirect(`${options.path === '/' ? '' : options.path}/u?cid=${req.params.username}`); }); return router; } } const ApiRouter = (options) => UserRouter.router(options); export { ApiRouter, UserRouter };