generated from azures04/Base-REST-API
Introduce gamification and check-in support plus expanded transport/admin APIs. Added DDL for checkins, badges and user_badges. New repositories: badgeRepository, userBadgeRepository, checkinRepository. New routes: admin badge management, admin transport (lines/platforms/stations), public transport endpoints, user checkins and stations endpoints, and user badges on /me. Services updated: adminService (badge CRUD & user assignment), userService (checkins, badge queries), authService (hasAdminRights). Minor package.json name update. These changes implement database, repo, service and route wiring for badges, user_badins and checkin features and additional transport admin routes.
130 lines
4.4 KiB
JavaScript
130 lines
4.4 KiB
JavaScript
const cache = require("../modules/cache")
|
|
const bcrypt = require("bcryptjs")
|
|
const usersRepo = require("../repositories/usersRepo")
|
|
const adminService = require("./adminService")
|
|
const tokensService = require("./tokensService")
|
|
const identitiesRepo = require("../repositories/identitiesRepo")
|
|
const credentialsRepo = require("../repositories/credentialsRepo")
|
|
const { DefaultError } = require("../errors/errors")
|
|
|
|
async function registerLocal({ identifier, password, profile = { displayName, avatarURL } }) {
|
|
try {
|
|
const user = await usersRepo.create(identifier, process.env.SERVER_UUID, null, profile.displayName, profile.avatarURL)
|
|
const hashedPassword = await bcrypt.hash(password, Number(process.env.BCRYPT_SALT))
|
|
const credentials = await credentialsRepo.create(user.id, hashedPassword)
|
|
if (credentials.length == 0) {
|
|
throw new DefaultError(500, "Internal Server Error", "UserRegistration")
|
|
}
|
|
return user
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async function validatePassword({ password, passwordHash }) {
|
|
try {
|
|
await bcrypt.compare(password, passwordHash)
|
|
} catch (error) {
|
|
throw new DefaultError(401, "Bad credentials", "Wrong password")
|
|
}
|
|
}
|
|
|
|
async function loginLocal({ identifier, password }) {
|
|
try {
|
|
const user = await usersRepo.findByIdentifier(identifier)
|
|
const credentials = await credentialsRepo.findByUserId(user.id)
|
|
await validatePassword({ password: password, passwordHash: credentials.passwordHash })
|
|
const accessToken = await tokensService.signToken(user)
|
|
const refreshToken = await tokensService.signRefreshToken(user.id)
|
|
return { user, tokens: { accessToken, refreshToken } }
|
|
} catch (error) {
|
|
console.log(error)
|
|
throw new DefaultError(500, "Internal Server Error", error.toString())
|
|
}
|
|
}
|
|
|
|
async function refreshAccessToken({ refreshToken }) {
|
|
try {
|
|
const payload = await tokensService.verifyRefreshToken(refreshToken)
|
|
await tokensService.revokeRefreshToken(refreshToken)
|
|
const user = await usersRepo.findById(payload.userId)
|
|
const newAccessToken = await tokensService.signToken(user)
|
|
const newRefreshToken = await tokensService.signRefreshToken(user.id)
|
|
return { accessToken: newAccessToken, refreshToken: newRefreshToken }
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async function changePassword({ userId, password, newPassword }) {
|
|
try {
|
|
const credentials = await credentialsRepo.findByUserId(userId)
|
|
await validatePassword({ password, passwordHash: credentials.passwordHash })
|
|
await credentialsRepo.updatePassword(userId, newPassword)
|
|
return true
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async function resetPassword({ userId, newPassword }) {
|
|
try {
|
|
await credentialsRepo.updatePassword(userId, newPassword)
|
|
return true
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async function isNotLogged(req, res, next) {
|
|
if (req.headers.authorization && req.headers.authorization.startsWith("Bearer")) {
|
|
throw new DefaultError(401, "You must be logged out to do this action", "Auth header")
|
|
}
|
|
|
|
next()
|
|
}
|
|
|
|
async function isLogged(req, res, next) {
|
|
if (!req.headers.authorization) {
|
|
throw new DefaultError(401, "You must be logged in to do this action", "Auth header")
|
|
}
|
|
if (!req.headers.authorization.startsWith("Bearer ")) {
|
|
throw new DefaultError(422, "Wrong auth header format", "WhereIsBearer")
|
|
}
|
|
|
|
const tokenVerified = await tokensService.verifyAccessToken(req.headers.authorization.replace("Bearer ", ""))
|
|
const isBanned = await adminService.isUserBanned(tokenVerified.id)
|
|
if (isBanned) {
|
|
throw new DefaultError(403, "You're not allowed to do this action", "Banned")
|
|
}
|
|
|
|
let user = cache.users.get(tokenVerified.id)
|
|
if (!user) {
|
|
user = await usersRepo.findById(tokenVerified.id)
|
|
if (!user) {
|
|
throw new DefaultError(404, "User not found", "UserNotFound")
|
|
}
|
|
cache.users.put(tokenVerified.id, user)
|
|
}
|
|
|
|
req.user = user
|
|
next()
|
|
}
|
|
|
|
function hasAdminRights(req, res, next) {
|
|
if (req.user?.role == "admin") {
|
|
return next()
|
|
}
|
|
throw new DefaultError(403, "Forbidden", "You must be administrator.")
|
|
}
|
|
|
|
module.exports = {
|
|
isLogged,
|
|
loginLocal,
|
|
isNotLogged,
|
|
resetPassword,
|
|
registerLocal,
|
|
changePassword,
|
|
hasAdminRights,
|
|
refreshAccessToken,
|
|
} |