"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JWT = exports.__ΩJwtValidationResult = exports.__ΩInvalidJwtValidationResult = exports.ParsedJwt = exports.__ΩJwtCookieOptions = void 0;
const __ΩRecord = ['K', 'T', 'Record', 'l\'e#"Rb!b"Pde"!N#!w#y'];
const __ΩReturnType = ['T', 'args', '', 'ReturnType', 'l>e"!R"RPde#!P"@2"h"!/#qk#\'QRb!Pde"!p)w$y'];
function __assignType(fn, args) {
    fn.__type = args;
    return fn;
}
const http_1 = require("@deepkit/http");
const crypto_1 = require("crypto");
const fast_jwt_1 = require("fast-jwt");
const resolver_1 = require("../app/resolver");
const __ΩJwtExtras = [() => __ΩRecord, 'JwtExtras', '&"o!#w"y'];
const __ΩBaseJwtOptions = ['issuer', 'audience', 'BaseJwtOptions', 'P&4!8&4"8Mw#y'];
const __ΩJwtCookieOptions = ['secure', "Strict", "Lax", "None", 'sameSite', 'domain', 'JwtCookieOptions', 'P)4!8P.".#.$J4%8&4&8Mw\'y'];
exports.__ΩJwtCookieOptions = __ΩJwtCookieOptions;
const __ΩJwtGenerationOptions = ['T', () => __ΩBaseJwtOptions, 'id', 'subject', 'expiresAt', 'expiryMins', 'payload', 'JwtGenerationOptions', '%c!Pn"&4#8&4$PT\'J4%8\'4&8e"!4\'8Mw(y'];
const __ΩVerifierOptions = [() => __ΩBaseJwtOptions, 'key', 'Algorithm', 'algorithm', 'VerifierOptions', 'Pn!P&!J4""w#4$Mw%y'];
class ParsedJwt {
    constructor() {
        this.isValid = true;
    }
    get issuedAt() {
        return new Date(this.issuedAtMs * 1000);
    }
    get expiresAt() {
        return new Date(this.expiresAtMs * 1000);
    }
}
exports.ParsedJwt = ParsedJwt;
ParsedJwt.__type = ['T', 'isValid', function () { return true; }, 'id', 'issuer', 'audience', 'subject', 'issuedAtMs', 'expiresAtMs', 'payload', () => __ΩRecord, 'rawPayload', 'ParsedJwt', '%c!)3"9>#&3$8&3%&3&8&3\'\'3(!\'3)!e!!3*&"o+#3,5w-'];
const __ΩInvalidJwtValidationResult = [false, 'isValid', 'isDecodable', 'isSignatureValid', 'isPayloadValid', 'isNotExpired', 'InvalidJwtValidationResult', 'P.!4")4#)4$8)4%8)4&8Mw\'y'];
exports.__ΩInvalidJwtValidationResult = __ΩInvalidJwtValidationResult;
const __ΩJwtValidationResult = ['T', () => ParsedJwt, () => __ΩInvalidJwtValidationResult, 'JwtValidationResult', '%c!PPe#!7"n#Jw$y'];
exports.__ΩJwtValidationResult = __ΩJwtValidationResult;
const __ΩJWTState = ['shouldVerify', 'issuerName', 'validityMins', 'cookieName', 'cookieRe', () => fast_jwt_1.SignerSync, 'signer', () => fast_jwt_1.VerifierSync, 'verifier', () => __ΩReturnType, () => fast_jwt_1.createDecoder, 'decoder', 'JWTState', 'P)4!&4"\'4#&4$A4%i&4\'i(4)i+o*"4,Mw-y'];
const TokenErrorClasses = {
    decode: [fast_jwt_1.TokenError.codes.invalidPayload, fast_jwt_1.TokenError.codes.malformed, fast_jwt_1.TokenError.codes.invalidType],
    verify: [fast_jwt_1.TokenError.codes.verifyError, fast_jwt_1.TokenError.codes.invalidSignature, fast_jwt_1.TokenError.codes.invalidAlgorithm],
    payload: [fast_jwt_1.TokenError.codes.invalidClaimType, fast_jwt_1.TokenError.codes.invalidClaimValue, fast_jwt_1.TokenError.codes.missingRequiredClaim],
    expiry: [fast_jwt_1.TokenError.codes.expired, fast_jwt_1.TokenError.codes.inactive]
};
class JWT {
    static get state() {
        const appConfig = (0, resolver_1.getAppConfig)();
        if (appConfig.AUTH_JWT_ENABLE_VERIFY) {
            if (!appConfig.AUTH_JWT_SECRET && !appConfig.AUTH_JWT_SECRET_B64 && !appConfig.AUTH_JWT_ED_SECRET) {
                throw new Error('AUTH_JWT_SECRET/AUTH_JWT_SECRET_B64/AUTH_JWT_ED_SECRET is not configured');
            }
            if (appConfig.AUTH_JWT_SECRET && appConfig.AUTH_JWT_SECRET_B64) {
                throw new Error('AUTH_JWT_SECRET and AUTH_JWT_SECRET_B64 cannot both be configured');
            }
            if ((appConfig.AUTH_JWT_SECRET || appConfig.AUTH_JWT_SECRET_B64) && appConfig.AUTH_JWT_ED_SECRET) {
                throw new Error('AUTH_JWT_SECRET/AUTH_JWT_SECRET_B64 and AUTH_JWT_ED_SECRET cannot both be configured');
            }
        }
        const shouldVerify = appConfig.AUTH_JWT_ENABLE_VERIFY;
        const cookieName = appConfig.AUTH_JWT_COOKIE_NAME ?? 'jwt';
        const cookieRe = new RegExp('(^|;)[ ]*' + cookieName + '=([^;]+)');
        const issuerName = appConfig.AUTH_JWT_ISSUER ?? 'app';
        const validityMins = appConfig.AUTH_JWT_EXPIRATION_MINS ?? 60;
        const getKey = () => appConfig.AUTH_JWT_SECRET_B64 ? Buffer.from(appConfig.AUTH_JWT_SECRET_B64, 'base64') : (appConfig.AUTH_JWT_SECRET ?? '');
        const signer = (0, fast_jwt_1.createSigner)(appConfig.AUTH_JWT_ED_SECRET
            ? { algorithm: 'EdDSA', key: `-----BEGIN PRIVATE KEY-----\n${appConfig.AUTH_JWT_ED_SECRET}\n-----END PRIVATE KEY-----` }
            : { key: getKey() });
        const verifier = (0, fast_jwt_1.createVerifier)({
            cache: true,
            allowedIss: issuerName,
            ...(appConfig.AUTH_JWT_ED_SECRET
                ? { algorithms: ['EdDSA'], key: this.deriveEdPublicKey(appConfig.AUTH_JWT_ED_SECRET) }
                : { key: getKey() })
        });
        const decoder = (0, fast_jwt_1.createDecoder)();
        this._state = { shouldVerify, issuerName, validityMins, cookieName, cookieRe, signer, verifier, decoder };
        Object.defineProperty(this, 'state', { value: this._state });
        return this._state;
    }
    static deriveEdPublicKey(privateKey) {
        const privateKeyObj = (0, crypto_1.createPrivateKey)({
            key: `-----BEGIN PRIVATE KEY-----\n${privateKey}\n-----END PRIVATE KEY-----`,
            format: 'pem',
            type: 'pkcs8'
        });
        const publicKeyObj = (0, crypto_1.createPublicKey)({
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            key: privateKeyObj
        });
        return publicKeyObj.export({ type: 'spki', format: 'pem' });
    }
    static async generate(options) {
        return this.state.signer({
            ...(options.id ? { jti: options.id } : {}),
            iss: options.issuer ?? this.state.issuerName,
            aud: options.audience,
            sub: options.subject,
            exp: this.getExpirationTs(options),
            ...options.payload
        });
        // todo: ID
    }
    static async generateCookie(options, response, cookieOptions) {
        const payload = await this.generate(options);
        response.setHeader('set-cookie', `${this.state.cookieName}=${payload}; ${this.buildCookieAttributes(cookieOptions)}`);
    }
    static async clearCookie(response, cookieOptions) {
        response.setHeader('set-cookie', `${this.state.cookieName}=invalid; Expires=Thu, 01 Jan 1970 00:00:00 GMT; ${this.buildCookieAttributes(cookieOptions)}`);
    }
    static buildCookieAttributes(options) {
        const parts = ['Path=/; HttpOnly'];
        if (options?.secure !== false)
            parts.push('Secure');
        parts.push(`SameSite=${options?.sameSite ?? 'Lax'}`);
        if (options?.domain)
            parts.push(`Domain=${options.domain}`);
        return parts.join('; ');
    }
    static createVerifier(options) {
        const verifier = (0, fast_jwt_1.createVerifier)({
            cache: true,
            allowedIss: options.issuer,
            allowedAud: options.audience,
            algorithms: [options.algorithm],
            key: typeof options.key === 'string' && !options.key.startsWith('-----BEGIN PUBLIC KEY-----') && options.algorithm === 'EdDSA'
                ? `-----BEGIN PUBLIC KEY-----\n${options.key}\n-----END PUBLIC KEY-----`
                : options.key
        });
        return __assignType(async (token) => this.verify(token, verifier), ['token', '', 'P&2!"/"']);
    }
    static async verify(token, verifier) {
        try {
            verifier = verifier ?? this.state.verifier;
            const result = await verifier(token);
            return (this.formatJwtResult.Ω = [[() => __ΩJwtExtras, 'n!']], this.formatJwtResult(result));
        }
        catch (err) {
            return this.formatJwtError(err);
        }
    }
    static async decode(token) {
        try {
            const result = await this.state.decoder(token);
            return (this.formatJwtResult.Ω = [[() => __ΩJwtExtras, 'n!']], this.formatJwtResult(result));
        }
        catch (err) {
            return this.formatJwtError(err);
        }
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    static formatJwtResult(result) {
        const formatted = (ParsedJwt.Ω = [[() => __ΩJwtExtras, 'n!']], new ParsedJwt());
        const { jti, sub, iss, aud, iat, exp, ...payload } = result;
        Object.assign(formatted, {
            id: jti,
            subject: sub,
            issuer: iss,
            audience: aud,
            issuedAtMs: iat,
            expiresAtMs: exp,
            payload,
            rawPayload: result
        });
        return formatted;
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    static formatJwtError(err) {
        if (err instanceof fast_jwt_1.TokenError) {
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            if (TokenErrorClasses.decode.includes(err.code)) {
                return { isValid: false, isDecodable: false };
            }
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            if (TokenErrorClasses.verify.includes(err.code)) {
                return { isValid: false, isDecodable: true, isSignatureValid: false };
            }
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            if (TokenErrorClasses.payload.includes(err.code)) {
                return { isValid: false, isDecodable: true, isSignatureValid: true, isPayloadValid: false };
            }
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            if (TokenErrorClasses.expiry.includes(err.code)) {
                return { isValid: false, isDecodable: true, isSignatureValid: true, isPayloadValid: true, isNotExpired: false };
            }
        }
        throw err;
    }
    static async process(token) {
        return this.state.shouldVerify ? this.verify(token) : this.decode(token);
    }
    static async processWithRequest(request) {
        if (request.headers.authorization) {
            if (request.headers.authorization.startsWith('Bearer ')) {
                const result = await this.process(request.headers.authorization.substring(7));
                if (result.isValid) {
                    return result;
                }
            }
        }
        if (request.headers.cookie) {
            const matches = request.headers.cookie.match(this.state.cookieRe);
            if (matches) {
                const result = await this.process(matches[2]);
                if (result.isValid) {
                    return result;
                }
            }
        }
        return null;
    }
    static getExpirationTs(options) {
        const expiresMsIn = options.expiresAt instanceof Date ? options.expiresAt.getTime() : options.expiresAt;
        const expiresMs = expiresMsIn ?? Date.now() + (options.expiryMins ?? this.state.validityMins) * 60 * 1000;
        return Math.floor(expiresMs / 1000);
    }
}
exports.JWT = JWT;
JWT.__type = [() => __ΩJWTState, '_state', 'privateKey', 'deriveEdPublicKey', () => __ΩJwtGenerationOptions, 'options', 'generate', () => __ΩJwtGenerationOptions, () => http_1.HttpResponse, 'response', () => __ΩJwtCookieOptions, 'cookieOptions', 'generateCookie', () => http_1.HttpResponse, () => __ΩJwtCookieOptions, 'clearCookie', () => __ΩJwtCookieOptions, 'buildCookieAttributes', () => __ΩVerifierOptions, 'token', () => __ΩJwtValidationResult, '', 'createVerifier', () => __ΩJWTState, "verifier", 'verifier', () => __ΩJwtValidationResult, 'verify', () => __ΩJwtValidationResult, 'decode', 'result', () => __ΩJwtValidationResult, 'formatJwtResult', 'err', () => __ΩInvalidJwtValidationResult, 'formatJwtError', 'process', () => http_1.HttpRequest, 'request', () => __ΩJwtValidationResult, 'processWithRequest', () => __ΩJwtGenerationOptions, 'getExpirationTs', 'JWT', 'n!3"8;s!P&2#"0$;sP"o%"2&&`0\'sP"o("2&P7)2*n+2,8"0-sPP7.2*n/2,8"00sPn12&8&02;sPn32&P&24"o5"`/607sP&24n8.9f2:8"o;"`0<sP&24"o="`0>sP"2?"o@"0A;sP"2BnC0D;sP&24"0EsPP7F2GPnH,J`0IsPnJ2&"0K;s5wL'];
//# sourceMappingURL=jwt.js.map