"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.__tsfTypeAliases = void 0;
exports.getJwtFromRequest = getJwtFromRequest;
exports.getSubjectFromRequestJwt = getSubjectFromRequestJwt;
exports.resolveEntityFromRequestJwt = resolveEntityFromRequestJwt;
exports.createAuthMiddleware = createAuthMiddleware;
const tslib_1 = require("tslib");
const _a = tslib_1.__importStar(require("@zyno-io/ts-server-foundation/type-metadata-runtime"));
const jwt_1 = require("../auth/jwt");
const database_1 = require("../database");
const errors_1 = require("./errors");
const request_1 = require("./request");
const store_1 = require("./store");
const ParsedJwtSymbol = Symbol('ParsedJwt');
async function getJwtFromRequest(request) {
    return (0, store_1.getOrCacheValue)(request, ParsedJwtSymbol, async () => {
        const jwt = await jwt_1.JWT.processWithRequest(request);
        if (!jwt)
            return undefined;
        if (!jwt.isValid) {
            if (!jwt.isSignatureValid)
                throw new errors_1.HttpUnauthorizedError('Invalid JWT signature');
            if (!jwt.isNotExpired)
                throw new errors_1.HttpUnauthorizedError('Expired JWT');
            throw new errors_1.HttpUnauthorizedError('Invalid JWT');
        }
        return jwt;
    });
}
async function getSubjectFromRequestJwt(request) {
    const jwt = await getJwtFromRequest(request);
    return jwt?.subject;
}
async function resolveEntityFromRequestJwt(contextOrRequest, EntityClass) {
    const requestOnly = contextOrRequest instanceof request_1.HttpRequest;
    const request = requestOnly ? contextOrRequest : contextOrRequest.request;
    const entityId = await getSubjectFromRequestJwt(request);
    const entity = entityId === undefined ? undefined : await (0, database_1.getEntityOrUndefined)(EntityClass, entityId);
    if (!entity && !requestOnly && contextOrRequest.type?.isOptional?.() !== true)
        throw new errors_1.HttpUnauthorizedError();
    return entity;
}
function createAuthMiddleware(EntityClass) {
    const entityIdCacheKey = { kind: 'auth-entity-id', EntityClass };
    const entityCacheKey = { kind: 'auth-entity', EntityClass };
    return class AuthMiddleware {
        async handle(request) {
            const entityId = await (0, store_1.getOrCacheValue)(request, entityIdCacheKey, () => this.getEntityIdFromRequest(request));
            await this.loadAndValidateEntity(request, entityId);
        }
        async getEntityIdFromRequest(request) {
            const id = await getSubjectFromRequestJwt(request);
            if (!id)
                throw new errors_1.HttpUnauthorizedError();
            return id;
        }
        async loadAndValidateEntity(request, id) {
            const validate = this.validateEntity;
            if (!validate)
                return;
            const entity = await (0, store_1.getOrCacheValue)(request, entityCacheKey, () => (0, database_1.getEntityOrUndefined)(EntityClass, id));
            if (!entity)
                throw new errors_1.HttpUnauthorizedError();
            await validate.call(this, request, entity);
        }
    };
}
exports.__tsfTypeAliases = _a.decodeCompactMetadataV1("[1,{\"EntityValidator\":{\"kind\":18,\"typeName\":\"EntityValidator\",\"types\":[]}}]", []);
//# sourceMappingURL=auth.js.map