import * as __typia_transform__assertGuard from "typia/lib/internal/_assertGuard.js";
import * as __typia_transform__accessExpressionAsString from "typia/lib/internal/_accessExpressionAsString.js";
import { KeetaAnchorUserError } from "../error.js";
import { KeetaNet } from "../../client/index.js";
import { assertAccountCertificateChain } from "../utils/certificate-network.js";
import { createAssertEquals } from "typia";
import { VerifySignedData } from "../utils/signing.js";
export const assertHTTPSignedField = (() => { const _io0 = (input, _exceptionable = true) => "string" === typeof input.nonce && "string" === typeof input.timestamp && "string" === typeof input.signature && (3 === Object.keys(input).length || Object.keys(input).every(key => {
    if (["nonce", "timestamp", "signature"].some(prop => key === prop))
        return true;
    const value = input[key];
    if (undefined === value)
        return true;
    return false;
})); const _ao0 = (input, _path, _exceptionable = true) => ("string" === typeof input.nonce || __typia_transform__assertGuard._assertGuard(_exceptionable, {
    method: "createAssertEquals",
    path: _path + ".nonce",
    expected: "string",
    value: input.nonce
}, _errorFactory)) && ("string" === typeof input.timestamp || __typia_transform__assertGuard._assertGuard(_exceptionable, {
    method: "createAssertEquals",
    path: _path + ".timestamp",
    expected: "string",
    value: input.timestamp
}, _errorFactory)) && ("string" === typeof input.signature || __typia_transform__assertGuard._assertGuard(_exceptionable, {
    method: "createAssertEquals",
    path: _path + ".signature",
    expected: "string",
    value: input.signature
}, _errorFactory)) && (3 === Object.keys(input).length || (false === _exceptionable || Object.keys(input).every(key => {
    if (["nonce", "timestamp", "signature"].some(prop => key === prop))
        return true;
    const value = input[key];
    if (undefined === value)
        return true;
    return __typia_transform__assertGuard._assertGuard(_exceptionable, {
        method: "createAssertEquals",
        path: _path + __typia_transform__accessExpressionAsString._accessExpressionAsString(key),
        expected: "undefined",
        value: value
    }, _errorFactory);
}))); const __is = (input, _exceptionable = true) => "object" === typeof input && null !== input && _io0(input, true); let _errorFactory; return (input, errorFactory) => {
    if (false === __is(input)) {
        _errorFactory = errorFactory;
        ((input, _path, _exceptionable = true) => ("object" === typeof input && null !== input || __typia_transform__assertGuard._assertGuard(true, {
            method: "createAssertEquals",
            path: _path + "",
            expected: "HTTPSignedField",
            value: input
        }, _errorFactory)) && _ao0(input, _path + "", true) || __typia_transform__assertGuard._assertGuard(true, {
            method: "createAssertEquals",
            path: _path + "",
            expected: "HTTPSignedField",
            value: input
        }, _errorFactory))(input, "$input", true);
    }
    return input;
}; })();
export function addSignatureToURL(input, data) {
    let url;
    if (typeof input === 'string') {
        url = new URL(input);
    }
    else {
        url = new URL(input.toString());
    }
    for (const key of ['nonce', 'timestamp', 'signature']) {
        const searchKey = `signed.${key}`;
        if (url.searchParams.has(searchKey)) {
            throw (new KeetaAnchorUserError(`URL already has signed field parameter: ${searchKey}`));
        }
        url.searchParams.set(`signed.${key}`, data.signedField[key]);
    }
    url.searchParams.set('account', data.account.publicKeyString.get());
    return (url);
}
export function parseSignatureFromURL(input) {
    let url;
    if (typeof input === 'string') {
        url = new URL(input);
    }
    else {
        url = new URL(input.toString());
    }
    const retVal = {};
    const signedField = (() => {
        const nonce = url.searchParams.get('signed.nonce');
        const timestamp = url.searchParams.get('signed.timestamp');
        const signature = url.searchParams.get('signed.signature');
        if (!nonce && !timestamp && !signature) {
            return (undefined);
        }
        if (!nonce || !timestamp || !signature) {
            throw (new KeetaAnchorUserError('Incomplete signature fields in URL'));
        }
        return ({ nonce, timestamp, signature });
    })();
    if (signedField) {
        retVal.signedField = signedField;
    }
    const account = (() => {
        const accountParam = url.searchParams.get('account');
        if (!accountParam) {
            return (undefined);
        }
        return (KeetaNet.lib.Account.fromPublicKeyString(accountParam).assertAccount());
    })();
    if (account) {
        retVal.account = account;
    }
    return (retVal);
}
/**
 * Verify a signed body, then enforce the cert-chain gate. Returns the
 * authenticated account. Throws `KeetaAnchorUserError` on missing or
 * invalid auth, and `KeetaAnchorCertificateRequiredError` when the
 * caller's on-chain cert chain doesn't satisfy `certificateChain`.
 */
export async function verifyBodyAuth(request, getSigningData, certificateChain) {
    if (!request.account || !request.signed) {
        throw (new KeetaAnchorUserError('Authentication required'));
    }
    const account = KeetaNet.lib.Account.fromPublicKeyString(request.account).assertAccount();
    const signable = getSigningData(request);
    const signed = assertHTTPSignedField(request.signed);
    const valid = await VerifySignedData(account, signable, signed);
    if (!valid) {
        throw (new KeetaAnchorUserError('Invalid signature'));
    }
    await assertAccountCertificateChain(account, certificateChain);
    return (account);
}
/**
 * Verify a URL-signed request, then enforce the cert-chain gate. Returns
 * the authenticated account. The signable is built by the caller from a
 * request derived from the URL-bound account public key.
 */
export async function verifyURLAuth(url, getSigningData, certificateChain) {
    let urlString;
    if (typeof url === 'string') {
        urlString = url;
    }
    else {
        urlString = url.href;
    }
    const parsed = parseSignatureFromURL(urlString);
    if (!parsed.account || !parsed.signedField) {
        throw (new KeetaAnchorUserError('Authentication required'));
    }
    const signable = getSigningData(parsed.account);
    const valid = await VerifySignedData(parsed.account, signable, parsed.signedField);
    if (!valid) {
        throw (new KeetaAnchorUserError('Invalid signature'));
    }
    await assertAccountCertificateChain(parsed.account, certificateChain);
    return (parsed.account);
}
//# sourceMappingURL=common.js.map