"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const api_token_service_1 = require("./api-token-service");
const test_config_1 = require("../../test/config/test-config");
const api_token_1 = require("../types/models/api-token");
const fake_api_token_store_1 = __importDefault(require("../../test/fixtures/fake-api-token-store"));
const fake_environment_store_1 = __importDefault(require("../features/project-environments/fake-environment-store"));
const fake_event_store_1 = __importDefault(require("../../test/fixtures/fake-event-store"));
const types_1 = require("../types");
const date_fns_1 = require("date-fns");
const event_service_1 = __importDefault(require("../features/events/event-service"));
const fake_feature_tag_store_1 = __importDefault(require("../../test/fixtures/fake-feature-tag-store"));
const features_1 = require("../../lib/features");
const util_1 = require("../util");
test('Should init api token', async () => {
    const token = {
        environment: '*',
        project: '*',
        secret: '*:*:some-random-string',
        type: api_token_1.ApiTokenType.ADMIN,
        tokenName: 'admin',
    };
    const config = (0, test_config_1.createTestConfig)({
        authentication: {
            initApiTokens: [token],
        },
        experimental: {
            flags: {
                useMemoizedActiveTokens: true,
            },
        },
    });
    const apiTokenStore = new fake_api_token_store_1.default();
    const environmentStore = new fake_environment_store_1.default();
    const insertCalled = new Promise((resolve) => {
        apiTokenStore.on('insert', resolve);
    });
    const eventService = (0, features_1.createFakeEventsService)(config);
    new api_token_service_1.ApiTokenService({ apiTokenStore, environmentStore }, config, eventService);
    await insertCalled;
    const tokens = await apiTokenStore.getAll();
    expect(tokens).toHaveLength(1);
});
test("Shouldn't return frontend token when secret is undefined", async () => {
    const token = {
        environment: 'default',
        projects: ['*'],
        secret: '*:*:some-random-string',
        type: api_token_1.ApiTokenType.FRONTEND,
        tokenName: 'front',
        expiresAt: undefined,
    };
    const config = (0, test_config_1.createTestConfig)({});
    const apiTokenStore = new fake_api_token_store_1.default();
    const environmentStore = new fake_environment_store_1.default();
    const eventService = new event_service_1.default({
        eventStore: new fake_event_store_1.default(),
        featureTagStore: new fake_feature_tag_store_1.default(),
    }, config);
    await environmentStore.create({
        name: 'default',
        enabled: true,
        protected: true,
        type: 'test',
        sortOrder: 1,
    });
    const apiTokenService = new api_token_service_1.ApiTokenService({ apiTokenStore, environmentStore }, config, eventService);
    await apiTokenService.createApiTokenWithProjects(token);
    await apiTokenService.fetchActiveTokens();
    expect(await apiTokenService.getUserForToken('')).toEqual(undefined);
});
test('Api token operations should all have events attached', async () => {
    const token = {
        environment: 'default',
        projects: ['*'],
        secret: '*:*:some-random-string',
        type: api_token_1.ApiTokenType.FRONTEND,
        tokenName: 'front',
        expiresAt: undefined,
    };
    const config = (0, test_config_1.createTestConfig)({});
    const apiTokenStore = new fake_api_token_store_1.default();
    const environmentStore = new fake_environment_store_1.default();
    const eventService = new event_service_1.default({
        eventStore: new fake_event_store_1.default(),
        featureTagStore: new fake_feature_tag_store_1.default(),
    }, config);
    await environmentStore.create({
        name: 'default',
        enabled: true,
        protected: true,
        type: 'test',
        sortOrder: 1,
    });
    const apiTokenService = new api_token_service_1.ApiTokenService({ apiTokenStore, environmentStore }, config, eventService);
    const saved = await apiTokenService.createApiTokenWithProjects(token);
    const newExpiry = (0, date_fns_1.addDays)(new Date(), 30);
    await apiTokenService.updateExpiry(saved.secret, newExpiry, types_1.TEST_AUDIT_USER);
    await apiTokenService.delete(saved.secret, types_1.TEST_AUDIT_USER);
    const { events } = await eventService.getEvents();
    const createdApiTokenEvents = events.filter((e) => e.type === types_1.API_TOKEN_CREATED);
    expect(createdApiTokenEvents).toHaveLength(1);
    expect(createdApiTokenEvents[0].preData).toBeUndefined();
    expect(createdApiTokenEvents[0].data.secret).toBeUndefined();
    const updatedApiTokenEvents = events.filter((e) => e.type === types_1.API_TOKEN_UPDATED);
    expect(updatedApiTokenEvents).toHaveLength(1);
    expect(updatedApiTokenEvents[0].preData.expiresAt).toBeDefined();
    expect(updatedApiTokenEvents[0].preData.secret).toBeUndefined();
    expect(updatedApiTokenEvents[0].data.secret).toBeUndefined();
    expect(updatedApiTokenEvents[0].data.expiresAt).toBe(newExpiry);
    const deletedApiTokenEvents = events.filter((e) => e.type === types_1.API_TOKEN_DELETED);
    expect(deletedApiTokenEvents).toHaveLength(1);
    expect(deletedApiTokenEvents[0].data).toBeUndefined();
    expect(deletedApiTokenEvents[0].preData).toBeDefined();
    expect(deletedApiTokenEvents[0].preData.secret).toBeUndefined();
});
test('getUserForToken should get a user with admin token user id and token name', async () => {
    const config = (0, test_config_1.createTestConfig)();
    const apiTokenStore = new fake_api_token_store_1.default();
    const environmentStore = new fake_environment_store_1.default();
    const eventService = (0, features_1.createFakeEventsService)(config);
    const tokenService = new api_token_service_1.ApiTokenService({ apiTokenStore, environmentStore }, config, eventService);
    const token = await tokenService.createApiTokenWithProjects({
        environment: '*',
        projects: ['*'],
        type: api_token_1.ApiTokenType.ADMIN,
        tokenName: 'admin.token',
    }, (0, util_1.extractAuditInfoFromUser)(types_1.ADMIN_TOKEN_USER));
    const user = await tokenService.getUserForToken(token.secret);
    expect(user).toBeDefined();
    expect(user.username).toBe(token.tokenName);
    expect(user.internalAdminTokenUserId).toBe(types_1.ADMIN_TOKEN_USER.id);
});
describe('API token getTokenWithCache', () => {
    const token = {
        environment: 'default',
        projects: ['*'],
        secret: '*:*:some-random-string',
        type: api_token_1.ApiTokenType.CLIENT,
        tokenName: 'new-token-by-another-instance',
        expiresAt: undefined,
    };
    const setup = (options) => {
        const config = (0, test_config_1.createTestConfig)(options);
        const apiTokenStore = new fake_api_token_store_1.default();
        const environmentStore = new fake_environment_store_1.default();
        const apiTokenService = new api_token_service_1.ApiTokenService({ apiTokenStore, environmentStore }, config, (0, features_1.createFakeEventsService)(config));
        return {
            apiTokenService,
            apiTokenStore,
        };
    };
    test('should return the token and perform only one db query', async () => {
        const { apiTokenService, apiTokenStore } = setup();
        const apiTokenStoreGet = jest.spyOn(apiTokenStore, 'get');
        // valid token not present in cache (could be inserted by another instance)
        apiTokenStore.insert(token);
        for (let i = 0; i < 5; i++) {
            const found = await apiTokenService.getTokenWithCache(token.secret);
            expect(found).toBeDefined();
            expect(found?.tokenName).toBe(token.tokenName);
            expect(found?.createdAt).toBeDefined();
        }
        expect(apiTokenStoreGet).toHaveBeenCalledTimes(1);
    });
    test('should query the db only once for invalid tokens', async () => {
        jest.useFakeTimers();
        const { apiTokenService, apiTokenStore } = setup();
        const apiTokenStoreGet = jest.spyOn(apiTokenStore, 'get');
        const invalidToken = 'invalid-token';
        for (let i = 0; i < 5; i++) {
            expect(await apiTokenService.getTokenWithCache(invalidToken)).toBeUndefined();
        }
        expect(apiTokenStoreGet).toHaveBeenCalledTimes(1);
        // after more than 5 minutes we should be able to query again
        jest.advanceTimersByTime((0, date_fns_1.minutesToMilliseconds)(6));
        for (let i = 0; i < 5; i++) {
            expect(await apiTokenService.getTokenWithCache(invalidToken)).toBeUndefined();
        }
        expect(apiTokenStoreGet).toHaveBeenCalledTimes(2);
    });
    test('should not return the token if it has expired and shoud perform only one db query', async () => {
        const { apiTokenService, apiTokenStore } = setup();
        const apiTokenStoreGet = jest.spyOn(apiTokenStore, 'get');
        // valid token not present in cache but expired
        apiTokenStore.insert({ ...token, expiresAt: (0, date_fns_1.subDays)(new Date(), 1) });
        for (let i = 0; i < 5; i++) {
            const found = await apiTokenService.getTokenWithCache(token.secret);
            expect(found).toBeUndefined();
        }
        expect(apiTokenStoreGet).toHaveBeenCalledTimes(1);
    });
});
//# sourceMappingURL=api-token-service.test.js.map