var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { AKAPIException } from '../../exceptions/api_exception.js';
import { asyncBlock, method } from '../../observability/tracing.js';
import { AKJwtService } from './jwt_service.js';
export class AKJwtGuard {
    driverName = 'jwt';
    #ctx;
    #jwtService;
    #findUserById;
    #emitter;
    isAuthenticated = false;
    authenticationAttempted = false;
    user;
    jwtPayload;
    authenticateApiException;
    constructor(ctx, jwtService, findUserById, emitter) {
        this.#ctx = ctx;
        this.#jwtService = jwtService;
        this.#findUserById = findUserById;
        this.#emitter = emitter;
    }
    async authenticate() {
        if (this.authenticationAttempted) {
            return this.getUserOrFail();
        }
        this.authenticationAttempted = true;
        await this.#emitter.emit('jwt_auth:authentication_attempted', {
            ctx: this.#ctx,
            guardName: this.driverName,
        });
        const authHeader = this.#ctx.request.header('authorization');
        let token;
        if (authHeader) {
            token = authHeader.split('Bearer ')[1];
        }
        else {
            token = this.#ctx.request.qs()['token'];
            delete this.#ctx.request.qs()['token'];
        }
        if (!token)
            throw AKAPIException.auth.token.missing;
        try {
            this.jwtPayload = await asyncBlock('JwtGuard.authenticate.verify', async () => await this.#jwtService.verify(token));
        }
        catch (e) {
            if (e.name === 'TokenExpiredError') {
                throw AKAPIException.auth.token.expired;
            }
            else {
                throw AKAPIException.auth.token.malformed;
            }
        }
        const expectedTokenType = this.#ctx.containerResolver.hasBinding('auth.jwt.token_type') &&
            (await this.#ctx.containerResolver.make('auth.jwt.token_type'));
        if (expectedTokenType && !AKJwtService.tokenHasType(this.jwtPayload, expectedTokenType))
            throw AKAPIException.auth.token.wrongType;
        const userId = this.jwtPayload.sub;
        if (!userId)
            throw AKAPIException.auth.token.wrongUserId;
        const user = await asyncBlock('JwtGuard.authenticate.findUser', async () => await this.#findUserById(userId));
        if (!user)
            throw AKAPIException.auth.token.wrongUserId;
        if (user.disabledAt)
            throw AKAPIException.auth.userDisabled;
        this.#emitter.emit('jwt_auth:authentication_succeeded', {
            ctx: this.#ctx,
            guardName: this.driverName,
            user,
        });
        const isAdmin = this.#ctx.containerResolver.hasBinding('auth.jwt.is_admin') &&
            (await this.#ctx.containerResolver.make('auth.jwt.is_admin'));
        if (isAdmin && !user.isAdmin)
            throw AKAPIException.notAllowed;
        this.user = user;
        return user;
    }
    async check() {
        try {
            await this.authenticate();
            return true;
        }
        catch (e) {
            if (e instanceof AKAPIException) {
                this.authenticateApiException = e;
            }
            return false;
        }
    }
    getUserOrFail() {
        if (!this.user)
            throw AKAPIException.auth.token.wrongUserId;
        return this.user;
    }
    async authenticateAsClient(user) {
        const token = await this.#jwtService.accessToken(user);
        return {
            headers: {
                authorization: `Bearer ${token}`,
            },
        };
    }
}
__decorate([
    method(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", Promise)
], AKJwtGuard.prototype, "authenticate", null);
//# sourceMappingURL=jwt_guard.js.map