generated from azures04/Base-REST-API
Introduce user bans and caching, extend schemas, and add auth/user endpoints. Adds bans DDL and banRepo plus adminService to manage bans; introduces modules/cache for in-memory user caching used by authService and userService. Updates users and credentials DDLs (role, isDisabled, shouldReset). Changes tokensService to include role in access tokens and store refresh tokens as SHA-256 hashes. Updates repos (credentials create RETURNING, usersRepo.updateProfile positional params), enhances authService with isLogged/isNotLogged middleware, ban checks, and refreshed token flow. Adds auth routes (login, logout, refresh, register) and user routes (/me).
106 lines
2.9 KiB
JavaScript
106 lines
2.9 KiB
JavaScript
const jwt = require("jsonwebtoken")
|
|
const crypto = require("node:crypto")
|
|
const security = require("../modules/security")
|
|
const tokenRepo = require("../repositories/refreshTokensRepo")
|
|
const { DefaultError } = require("../errors/errors")
|
|
|
|
const privateKey = security.readPrivateKey()
|
|
const publicKey = security.readPublicKey()
|
|
|
|
async function signToken(user) {
|
|
try {
|
|
const payload = {
|
|
id: user.id,
|
|
identifier: user.identifier,
|
|
displayName: user.displayName,
|
|
avatarUrl: user.avatarUrl,
|
|
role: user.role
|
|
}
|
|
const token = await jwt.sign(payload, privateKey, {
|
|
algorithm: "RS256",
|
|
issuer: process.env.FQDN,
|
|
expiresIn: parseInt(process.env.ACCESS_TOKEN_EXPIRY)
|
|
})
|
|
return token
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async function verifyAccessToken(token) {
|
|
try {
|
|
const result = jwt.verify(token, publicKey, {
|
|
algorithms: ["RS256"],
|
|
issuer: process.env.FQDN
|
|
})
|
|
return result
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async function signRefreshToken(userId) {
|
|
try {
|
|
const isTokenExisting = await tokenRepo.findByUserId(userId)
|
|
if (!Array.isArray(isTokenExisting)) {
|
|
await tokenRepo.removeByUserId(userId)
|
|
}
|
|
const now = Date.now()
|
|
const expiresIn = parseInt(process.env.REFRESH_TOKEN_EXPIRY)
|
|
const expiresAtInMs = new Date(now + (expiresIn * 1000))
|
|
const token = jwt.sign(
|
|
{ userId },
|
|
privateKey,
|
|
{
|
|
algorithm: "RS256",
|
|
issuer: process.env.FQDN,
|
|
expiresIn: expiresIn
|
|
}
|
|
)
|
|
const hash = crypto.createHash("sha256").update(token).digest("hex")
|
|
await tokenRepo.create(userId, hash, expiresAtInMs)
|
|
return token
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async function revokeRefreshToken(token) {
|
|
try {
|
|
return await tokenRepo.removeByTokenHash(token)
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async function verifyRefreshToken(token) {
|
|
try {
|
|
const result = jwt.verify(token, publicKey, {
|
|
algorithms: ["RS256"],
|
|
issuer: process.env.FQDN
|
|
})
|
|
if (!result) {
|
|
throw new DefaultError(500, "Internal Server Error")
|
|
}
|
|
const hash = crypto.createHash("sha256").update(token).digest("hex")
|
|
const refreshTokenInDb = await tokenRepo.findByTokenHash(hash)
|
|
if (refreshTokenInDb == null) {
|
|
throw new DefaultError(403, "Bad refresh token", "Refresh token doesn't exists")
|
|
}
|
|
return result
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async function verifyAccessTokenFromServer(token) {
|
|
// TO-DO: Integrate server federation
|
|
}
|
|
|
|
module.exports = {
|
|
signToken,
|
|
signRefreshToken,
|
|
verifyAccessToken,
|
|
revokeRefreshToken,
|
|
verifyRefreshToken,
|
|
} |