"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const client_sts_1 = require("@aws-sdk/client-sts");
const axios_1 = __importDefault(require("axios"));
const __1 = require("..");
const methods = ["GET", "DELETE"];
const dataMethods = ["POST", "PATCH", "PUT"];
const region = process.env.AWS_REGION;
const apiGateway = process.env.API_GATEWAY_URL;
const clientRoleArn = process.env.CLIENT_ROLE_ARN;
const assumedClientRoleArn = process.env.ASSUMED_CLIENT_ROLE_ARN;
const service = "execute-api";
let clientCredentials;
beforeAll(() => __awaiter(void 0, void 0, void 0, function* () {
    const sts = new client_sts_1.STSClient({ region });
    const { Credentials: credentials } = yield sts.send(new client_sts_1.AssumeRoleCommand({
        RoleArn: clientRoleArn,
        RoleSessionName: "integration-tests",
    }));
    clientCredentials = {
        accessKeyId: (credentials === null || credentials === void 0 ? void 0 : credentials.AccessKeyId) || "",
        secretAccessKey: (credentials === null || credentials === void 0 ? void 0 : credentials.SecretAccessKey) || "",
        sessionToken: (credentials === null || credentials === void 0 ? void 0 : credentials.SessionToken) || "",
    };
    cleanEnvCredentials();
}));
const setEnvCredentials = () => {
    process.env.AWS_ACCESS_KEY_ID = clientCredentials === null || clientCredentials === void 0 ? void 0 : clientCredentials.accessKeyId;
    process.env.AWS_SECRET_ACCESS_KEY = clientCredentials === null || clientCredentials === void 0 ? void 0 : clientCredentials.secretAccessKey;
    process.env.AWS_SESSION_TOKEN = clientCredentials === null || clientCredentials === void 0 ? void 0 : clientCredentials.sessionToken;
};
const cleanEnvCredentials = () => {
    delete process.env.AWS_PROFILE;
    delete process.env.AWS_ACCESS_KEY_ID;
    delete process.env.AWS_SECRET_ACCESS_KEY;
    delete process.env.AWS_SESSION_TOKEN;
};
describe("check that API is actually protected", () => {
    it.each([...methods, ...dataMethods])("checks that HTTP %s is protected", (method) => __awaiter(void 0, void 0, void 0, function* () {
        yield expect(axios_1.default.request({ url: apiGateway, method })).rejects.toMatchObject({
            response: {
                status: 403,
            },
        });
    }));
});
describe("with credentials from environment variables", () => {
    let client;
    const data = {
        foo: "bar",
    };
    beforeAll(() => {
        setEnvCredentials();
    });
    afterAll(() => {
        cleanEnvCredentials();
    });
    beforeEach(() => {
        client = axios_1.default.create();
        client.interceptors.request.use((0, __1.aws4Interceptor)({ options: { region, service }, instance: client }));
    });
    it.each(methods)("HTTP %s", (method) => __awaiter(void 0, void 0, void 0, function* () {
        let error;
        let result;
        try {
            result = yield client.request({ url: apiGateway, method });
        }
        catch (err) {
            error = (0, __1.getAuthErrorMessage)(err);
        }
        expect(error).toBe(undefined);
        expect(result === null || result === void 0 ? void 0 : result.status).toEqual(200);
        expect(result && result.data.requestContext.http.method).toBe(method);
        expect(result && result.data.requestContext.http.path).toBe("/");
    }));
    it.each(dataMethods)("HTTP %s", (method) => __awaiter(void 0, void 0, void 0, function* () {
        let error;
        let result;
        try {
            result = yield client.request({
                url: apiGateway,
                method,
                data,
                headers: { foo: "bar" },
            });
        }
        catch (err) {
            error = (0, __1.getAuthErrorMessage)(err);
        }
        expect(error).toBe(undefined);
        expect(result === null || result === void 0 ? void 0 : result.status).toEqual(200);
        expect(result === null || result === void 0 ? void 0 : result.data.requestContext.http.method).toBe(method);
        expect(result === null || result === void 0 ? void 0 : result.data.requestContext.http.path).toBe("/");
        expect(result && JSON.parse(result.data.body)).toStrictEqual(data);
        expect(result === null || result === void 0 ? void 0 : result.data.headers.foo).toEqual("bar");
    }));
    it("handles path", () => __awaiter(void 0, void 0, void 0, function* () {
        let error;
        let result;
        try {
            result = yield client.request({
                url: apiGateway + "/some/path",
            });
        }
        catch (err) {
            error = (0, __1.getAuthErrorMessage)(err);
        }
        expect(error).toBe(undefined);
        expect(result === null || result === void 0 ? void 0 : result.status).toEqual(200);
        expect(result && result.data.requestContext.http.path).toBe("/some/path");
    }));
    it("handles query parameters", () => __awaiter(void 0, void 0, void 0, function* () {
        let error;
        let result;
        try {
            result = yield client.request({
                url: apiGateway,
                params: {
                    lorem: 42,
                },
            });
        }
        catch (err) {
            error = (0, __1.getAuthErrorMessage)(err);
        }
        expect(error).toBe(undefined);
        expect(result === null || result === void 0 ? void 0 : result.status).toEqual(200);
        expect(result && result.data.rawQueryString).toBe("lorem=42");
    }));
    it("handles custom headers", () => __awaiter(void 0, void 0, void 0, function* () {
        let error;
        let result;
        try {
            result = yield client.request({
                url: apiGateway,
                method: "POST",
                headers: { "X-Custom-Header": "Baz" },
                data,
            });
        }
        catch (err) {
            error = (0, __1.getAuthErrorMessage)(err);
        }
        expect(error).toBe(undefined);
        expect(result === null || result === void 0 ? void 0 : result.status).toEqual(200);
        expect(result === null || result === void 0 ? void 0 : result.data.headers["x-custom-header"]).toBe("Baz");
    }));
    it("handles custom Content-Type header", () => __awaiter(void 0, void 0, void 0, function* () {
        let error;
        let result;
        try {
            result = yield client.request({
                url: apiGateway,
                method: "POST",
                headers: { "Content-Type": "application/xml" },
                data,
            });
        }
        catch (err) {
            error = (0, __1.getAuthErrorMessage)(err);
        }
        expect(error).toBe(undefined);
        expect(result === null || result === void 0 ? void 0 : result.status).toEqual(200);
        expect(result === null || result === void 0 ? void 0 : result.data.headers["content-type"]).toBe("application/xml");
    }));
    it("sets content type as application/json when the body is an object", () => __awaiter(void 0, void 0, void 0, function* () {
        let error;
        let result;
        try {
            result = yield client.request({
                url: apiGateway,
                method: "POST",
                data,
            });
        }
        catch (err) {
            error = (0, __1.getAuthErrorMessage)(err);
        }
        expect(error).toBe(undefined);
        expect(result === null || result === void 0 ? void 0 : result.status).toEqual(200);
        expect(result === null || result === void 0 ? void 0 : result.data.headers["content-type"]).toBe("application/json");
    }));
});
describe("signQuery", () => {
    beforeAll(() => {
        setEnvCredentials();
    });
    afterAll(() => {
        cleanEnvCredentials();
    });
    it("respects signQuery option", () => __awaiter(void 0, void 0, void 0, function* () {
        const client = axios_1.default.create();
        client.interceptors.request.use((0, __1.aws4Interceptor)({
            instance: client,
            options: {
                region,
                service,
                signQuery: true,
            },
        }));
        const result = yield client.request({
            url: apiGateway + "/some/path",
            method: "GET",
            params: { foo: "bar" },
        });
        expect(result === null || result === void 0 ? void 0 : result.status).toEqual(200);
    }));
});
describe("with role to assume", () => {
    let client;
    const assumedRoleName = assumedClientRoleArn === null || assumedClientRoleArn === void 0 ? void 0 : assumedClientRoleArn.substr(assumedClientRoleArn.indexOf("/") + 1);
    beforeAll(() => {
        setEnvCredentials();
    });
    afterAll(() => {
        cleanEnvCredentials();
    });
    beforeEach(() => {
        client = axios_1.default.create();
        client.interceptors.request.use((0, __1.aws4Interceptor)({
            options: { region, service, assumeRoleArn: assumedClientRoleArn },
            instance: client,
        }));
    });
    it.each([...methods, ...dataMethods])("signs HTTP %s request with assumed role credentials", (method) => __awaiter(void 0, void 0, void 0, function* () {
        const result = yield client.request({ url: apiGateway, method });
        expect(result === null || result === void 0 ? void 0 : result.status).toEqual(200);
        expect(result && result.data.requestContext.authorizer.iam.userArn).toContain("/" + assumedRoleName + "/");
    }));
});
