test_astro_hardhat/src/libs/validateAuth.ts
Florian Bouillon 9530be5c43 feat: continue work
Signed-off-by: Avior <github@avior.me>
2023-06-28 01:15:56 +02:00

124 lines
3.8 KiB
TypeScript

import DaoFactory from '../models/DaoFactory'
import CookieManager from './CookieManager'
import { buildRFC7807 } from './RFCs/RFC7807'
export interface Permission {
name: string
/**
* if set it will be usable by users
*
* else only users with the `admin.` prefix in the key can run it
*/
api: boolean
/**
* if set to true it will pass if a cookie authenticate a valid user
*/
cookie: boolean
}
/**
* validate the authentification
* @param request the request
* @param permission the permission to validate
* @returns a Response if the request is invalid, null otherwise
*
* TODO: implement rate limiting
* http/2.0 429 TOO MANY REQUESTS
* Content-Type: application/json+problem
* X-RateLimit-Limit: 1000 // number of request you cn make until hitting the rate limit
* X-RateLimit-Remaining: 0 // number of request remaining until the rate limit is atteined
* X-RateLimit-Reset: 123456789 // EPOCH time when the rate limit reset
* X-RateLimit-Reset-After: 9 // Number of seconds before the remaining Rate reset
*/
export async function validateAuth(request: Request, permission: Permission): Promise<Response | string> {
const apiKeyHeader = request.headers.get('Authorization')
const cookieHeader = request.headers.get('Cookie')
if (apiKeyHeader) {
const apiKey = apiKeyHeader.slice(apiKeyHeader.lastIndexOf(' ') + 1)
const dao = await DaoFactory.get('apiKey').findOne({
key: apiKey
})
const perm = permission.name.split('.')
const match = dao?.permissions.find((it) => {
const itSplit = it.split('.')
if (itSplit[0] === 'admin') {
itSplit.shift()
}
for (let idx = 0; idx < itSplit.length; idx++) {
const permissionLayer = itSplit[idx]
const requestPermissionLayer = perm[idx]
if (permissionLayer === '*') {
return true
} else if (permissionLayer !== requestPermissionLayer) {
return false
}
}
return itSplit.length === perm.length
// return it.endsWith(permission.name)
})
if (match && (permission.api || match.startsWith('admin.'))) {
return apiKey
} else if (permission.api) {
return buildRFC7807({
type: '/docs/errors/unauthorized-access',
status: 401,
title: 'Unauthorized access',
details: `you are missing the permission "${permission.name}" or is not an admin`
})
}
} else if (permission.api && !permission.cookie) {
return buildRFC7807({
type: '/docs/errors/unauthorized-access',
status: 401,
title: 'Unauthorized access',
details: `You MUST define an API key fo use this endpoint`
})
}
if (cookieHeader && permission.cookie) {
// TODO: make a better cookie implementation
const cookies = new CookieManager(cookieHeader)
const userCookie = cookies.get('userId')
if (!userCookie) {
return buildRFC7807({
type: '/docs/errors/unauthorized-access',
status: 401,
title: 'Unauthorized access',
details: `you must be connected to use this endpoint (missing the userId cookie)`
})
}
const dao = await DaoFactory.get('user').get(userCookie)
if (!dao) {
return buildRFC7807({
type: '/docs/errors/unauthorized-access',
status: 401,
title: 'Unauthorized access',
details: `the user does not exists`
})
}
return userCookie
} else if (!permission.api && permission.cookie) {
return buildRFC7807({
type: '/docs/errors/unauthorized-access',
status: 401,
title: 'Unauthorized access',
details: `You MUST be connected to your account to use this endpoint`
})
} else if (permission.api && permission.cookie) {
return buildRFC7807({
type: '/docs/errors/unauthorized-access',
status: 401,
title: 'Unauthorized access',
details: `You must be connected or use an API key to access this endpoint`
})
}
return buildRFC7807({
type: '/docs/errors/page-not-found',
status: 404,
title: 'Page not found',
details: `the following endpoint does not exists`
})
}