"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const sinon = require("sinon");
const errors_1 = require("../src/server/errors");
const profile_1 = require("../src/server/profile");
const shortcode_1 = require("../src/server/shortcode");
const _setup_1 = require("./_setup");
describe('shortcode oauth', () => {
    let requester;
    let clock;
    let oauth;
    beforeEach(() => {
        clock = sinon.useFakeTimers();
        requester = new _setup_1.MockRequester();
        oauth = new shortcode_1.OAuthClient({
            clientId: 'clientId',
            scopes: profile_1.Profile.necessaryScopes,
        }, requester);
    });
    const mockTokenResponse = {
        expires_in: 60000,
        access_token: 'access_token',
        refresh_token: 'refresh_token',
    };
    const expectTokensToBeMadeFromMock = (tokens) => {
        chai_1.expect(tokens.data).to.deep.equal({
            expiresAt: new Date(Date.now() + mockTokenResponse.expires_in * 1000),
            accessToken: 'access_token',
            refreshToken: 'refresh_token',
            scopes: profile_1.Profile.necessaryScopes,
        });
    };
    afterEach(() => {
        clock.restore();
    });
    describe('oauth tokens', () => {
        let tokens;
        beforeEach(() => {
            tokens = _setup_1.createValidOAuthTokens();
        });
        it('detects granted permissions correctly', () => {
            chai_1.expect(tokens.granted([])).to.be.true;
            chai_1.expect(tokens.granted(['interactive:manage:self'])).to.be.true;
            chai_1.expect(tokens.granted(['interactive:manage:self', 'other'])).to.be.false;
            chai_1.expect(tokens.granted(['other'])).to.be.false;
        });
        it('detects expiration correctly', () => {
            chai_1.expect(tokens.expired()).to.be.false;
            clock.tick(tokens.data.expiresAt.getTime() - Date.now() + 1);
            chai_1.expect(tokens.expired()).to.be.true;
        });
        it('creates headers', () => {
            chai_1.expect(tokens.header()).to.deep.equal({ Authorization: 'Bearer access_token' });
        });
    });
    describe('token refresh', () => {
        it('refreshes tokens successfully', () => __awaiter(this, void 0, void 0, function* () {
            requester.json
                .withArgs('post', '/oauth/token', {
                grant_type: 'refresh_token',
                refresh_token: 'expired_refresh_token',
                client_id: 'clientId',
            })
                .resolves({
                json: () => __awaiter(this, void 0, void 0, function* () { return mockTokenResponse; }),
                status: 200,
            });
            const newTokens = yield oauth.refresh(_setup_1.createExpiredOAuthTokens());
            expectTokensToBeMadeFromMock(newTokens);
        }));
    });
    describe('granting', () => {
        const giveStatus = (status) => {
            return requester.json.withArgs('get', '/oauth/shortcode/check/sc_handle').resolves({
                status,
                json: () => __awaiter(this, void 0, void 0, function* () { return ({ code: 'oauth_authorization_code' }); }),
            });
        };
        beforeEach(() => {
            requester.json
                .withArgs('post', '/oauth/token', {
                client_id: 'clientId',
                grant_type: 'authorization_code',
                code: 'oauth_authorization_code',
            })
                .resolves({
                status: 200,
                json: () => __awaiter(this, void 0, void 0, function* () { return mockTokenResponse; }),
            });
            requester.json
                .withArgs('post', '/oauth/shortcode', {
                client_id: 'clientId',
                client_secret: undefined,
                scope: profile_1.Profile.necessaryScopes.join(' '),
            })
                .resolves({
                status: 200,
                json: () => __awaiter(this, void 0, void 0, function* () { return ({ code: 'ABC123', handle: 'sc_handle' }); }),
            });
        });
        it('detects expired handles', () => __awaiter(this, void 0, void 0, function* () {
            const code = yield oauth.getCode();
            chai_1.expect(code.code).to.equal('ABC123');
            giveStatus(404);
            yield chai_1.expect(code.waitForAccept()).to.eventually.be.rejectedWith(errors_1.ShortCodeExpireError);
        }));
        it('detects rejected handles', () => __awaiter(this, void 0, void 0, function* () {
            const code = yield oauth.getCode();
            chai_1.expect(code.code).to.equal('ABC123');
            giveStatus(403);
            yield chai_1.expect(code.waitForAccept()).to.eventually.be.rejectedWith(errors_1.ShortCodeAccessDeniedError);
        }));
        it('loops and eventually resolves otherwise', () => __awaiter(this, void 0, void 0, function* () {
            const code = yield oauth.getCode();
            chai_1.expect(code.code).to.equal('ABC123');
            giveStatus(204).onFirstCall();
            giveStatus(200).onSecondCall();
            expectTokensToBeMadeFromMock(yield code.waitForAccept());
        }));
    });
});
