Compare commits
No commits in common. "edee8d6bc4309dedc6b179a32011cddce1f9bd72" and "28139f70e997d2735a640b03523e4b00cf2daf84" have entirely different histories.
edee8d6bc4
...
28139f70e9
3 changed files with 9 additions and 60 deletions
|
@ -1,5 +1,4 @@
|
||||||
const { jwtVerify } = require("jose")
|
const { jwtVerify } = require("jose")
|
||||||
const jwtDecode = require("jwt-decode")
|
|
||||||
const getHasuraClaimsFromJWT = require("@modjo/hasura/utils/jwt/get-hasura-claims-from-jwt")
|
const getHasuraClaimsFromJWT = require("@modjo/hasura/utils/jwt/get-hasura-claims-from-jwt")
|
||||||
const { ctx } = require("@modjo/core")
|
const { ctx } = require("@modjo/core")
|
||||||
const { reqCtx } = require("@modjo/express/ctx")
|
const { reqCtx } = require("@modjo/express/ctx")
|
||||||
|
@ -19,58 +18,23 @@ module.exports = function () {
|
||||||
|
|
||||||
function isScopeAllowed(session, scopes) {
|
function isScopeAllowed(session, scopes) {
|
||||||
const { allowedRoles } = session
|
const { allowedRoles } = session
|
||||||
return scopes
|
return scopes.some((scope) => allowedRoles.includes(scope))
|
||||||
.filter((scope) => !scope.startsWith("meta."))
|
|
||||||
.some((scope) => {
|
|
||||||
return allowedRoles.includes(scope)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return async function auth(jwt, scopes) {
|
return async function auth(jwt, scopes) {
|
||||||
const hasMetaExpUser = scopes.includes("meta.exp-user")
|
|
||||||
let jwtVerified = false
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!jwt) {
|
if (!jwt || !(await jwtVerify(jwt, JWKSet))) {
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
jwtVerified = await jwtVerify(jwt, JWKSet)
|
|
||||||
if (!jwtVerified) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const logger = ctx.require("logger")
|
const logger = ctx.require("logger")
|
||||||
|
logger.error({ error: err }, "jwVerify failed")
|
||||||
// Allow expired JWT only if meta.exp-user scope is present
|
return false
|
||||||
if (hasMetaExpUser && err.code === "ERR_JWT_EXPIRED") {
|
|
||||||
logger.debug(
|
|
||||||
{ error: err },
|
|
||||||
"Allowing expired JWT for meta.exp-user scope"
|
|
||||||
)
|
|
||||||
// Continue processing with expired JWT
|
|
||||||
} else {
|
|
||||||
logger.error({ error: err }, "jwVerify failed")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const claims = getHasuraClaimsFromJWT(jwt, claimsNamespace)
|
const claims = getHasuraClaimsFromJWT(jwt, claimsNamespace)
|
||||||
const session = sessionVarsFromClaims(claims)
|
const session = sessionVarsFromClaims(claims)
|
||||||
|
|
||||||
// Add exp claim to session if meta.exp-user scope is present
|
|
||||||
if (hasMetaExpUser) {
|
|
||||||
try {
|
|
||||||
const payload = jwtDecode(jwt)
|
|
||||||
if (payload && payload.exp) {
|
|
||||||
session.exp = payload.exp
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
const logger = ctx.require("logger")
|
|
||||||
logger.error({ error: err }, "Failed to decode JWT for exp claim")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isScopeAllowed(session, scopes)) {
|
if (!isScopeAllowed(session, scopes)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
const async = require("async")
|
const async = require("async")
|
||||||
const httpError = require("http-errors")
|
|
||||||
const { ctx } = require("@modjo/core")
|
const { ctx } = require("@modjo/core")
|
||||||
const { reqCtx } = require("@modjo/express/ctx")
|
const { reqCtx } = require("@modjo/express/ctx")
|
||||||
|
|
||||||
|
@ -29,19 +28,6 @@ module.exports = function () {
|
||||||
|
|
||||||
const { deviceId } = session
|
const { deviceId } = session
|
||||||
|
|
||||||
// Check JWT expiration sequence to prevent replay attacks
|
|
||||||
if (session.exp) {
|
|
||||||
const deviceExpKey = `device:${deviceId}:last_exp`
|
|
||||||
const storedLastExp = await redis.get(deviceExpKey)
|
|
||||||
|
|
||||||
if (storedLastExp && session.exp <= parseInt(storedLastExp, 10)) {
|
|
||||||
throw httpError(401, "not the latest jwt")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the new expiration date
|
|
||||||
await redis.set(deviceExpKey, session.exp, "EX", 30 * 24 * 60 * 60) // 30 days TTL
|
|
||||||
}
|
|
||||||
|
|
||||||
const { userId } = session
|
const { userId } = session
|
||||||
|
|
||||||
logger.debug({ action: "geoloc-sync", userId, deviceId })
|
logger.debug({ action: "geoloc-sync", userId, deviceId })
|
||||||
|
@ -50,11 +36,10 @@ module.exports = function () {
|
||||||
|
|
||||||
await async.parallel([
|
await async.parallel([
|
||||||
async () => {
|
async () => {
|
||||||
// const transaction = redis.multi()
|
const transaction = redis.multi()
|
||||||
// transaction.geoadd("device", longitude, latitude, deviceId)
|
transaction.geoadd("device", longitude, latitude, deviceId)
|
||||||
// transaction.publish("deviceSet", deviceId)
|
transaction.publish("deviceSet", deviceId)
|
||||||
// await transaction.exec()
|
await transaction.exec()
|
||||||
await redis.geoadd("device", longitude, latitude, deviceId)
|
|
||||||
|
|
||||||
await addTask(tasks.GEOCODE_MOVE, { deviceId, userId, coordinates })
|
await addTask(tasks.GEOCODE_MOVE, { deviceId, userId, coordinates })
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# description:
|
# description:
|
||||||
x-security:
|
x-security:
|
||||||
- auth: ["user", "meta.exp-user"]
|
- auth: ["user"]
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
|
|
Loading…
Add table
Reference in a new issue