<commit_before>const errors = require('@tryghost/errors');
const jwt = require('jsonwebtoken');
const should = require('should');
const sinon = require('sinon');
const apiKeyAuth = require('../../../../../../core/server/services/auth/api-key');
const models = require('../../../../../../core/server/models');

describe('Admin API Key Auth', function () {
    const ADMIN_API_URL = '/ghost/api/v4/admin/';
    const ADMIN_API_URL_NON_VERSIONED = '/ghost/api/admin/';

    before(models.init);

    beforeEach(function () {
        const fakeApiKey = {
            id: '1234',
            type: 'admin',
            secret: Buffer.from('testing').toString('hex'),
            get(prop) {
                return this[prop];
            }
        };
        this.fakeApiKey = fakeApiKey;
        this.secret = Buffer.from(fakeApiKey.secret, 'hex');

        this.apiKeyStub = sinon.stub(models.ApiKey, 'findOne');
        this.apiKeyStub.resolves();
        this.apiKeyStub.withArgs({id: fakeApiKey.id}).resolves(fakeApiKey);
    });

    afterEach(function () {
        sinon.restore();
    });

    it('should authenticate known+valid v4 API key', function (done) {
        const token = jwt.sign({
        }, this.secret, {
            keyid: this.fakeApiKey.id,
            algorithm: 'HS256',
            expiresIn: '5m',
            audience: '/v4/admin/',
            issuer: this.fakeApiKey.id
        });

        const req = {
            originalUrl: ADMIN_API_URL,
            headers: {
                authorization: `Ghost ${token}`
            }
        };
        const res = {};

        apiKeyAuth.admin.authenticate(req, res, (err) => {
            should.not.exist(err);
            req.api_key.should.eql(this.fakeApiKey);
            done();
        });
    });

    it('should authenticate known+valid non-versioned API key', function (done) {
        const token = jwt.sign({
        }, this.secret, {
            keyid: this.fakeApiKey.id,
            algorithm: 'HS256',
            expiresIn: '5m',
            audience: '/admin/',
            issuer: this.fakeApiKey.id
        });

        const req = {
            originalUrl: `${ADMIN_API_URL_NON_VERSIONED}session/`,
            headers: {
                authorization: `Ghost ${token}`
            }
        };
        const res = {};

        apiKeyAuth.admin.authenticate(req, res, (err) => {
            should.not.exist(err);
            req.api_key.should.eql(this.fakeApiKey);
            done();
        });
    });

    it('shouldn\'t authenticate with missing Ghost token', function (done) {
        const token = '';
        const req = {
            headers: {
                authorization: `Ghost ${token}`
            }
        };
        const res = {};

        apiKeyAuth.admin.authenticate(req, res, function next(err) {
            should.exist(err);
            should.equal(err instanceof errors.UnauthorizedError, true);
            err.code.should.eql('INVALID_AUTH_HEADER');<commit_msg>Added test coverage proving token back compatibility<commit_after>const errors = require('@tryghost/errors');
const jwt = require('jsonwebtoken');
const should = require('should');
const sinon = require('sinon');
const apiKeyAuth = require('../../../../../../core/server/services/auth/api-key');
const models = require('../../../../../../core/server/models');

describe('Admin API Key Auth', function () {
    const ADMIN_API_URL = '/ghost/api/v4/admin/';
    const ADMIN_API_URL_NON_VERSIONED = '/ghost/api/admin/';

    before(models.init);

    beforeEach(function () {
        const fakeApiKey = {
            id: '1234',
            type: 'admin',
            secret: Buffer.from('testing').toString('hex'),
            get(prop) {
                return this[prop];
            }
        };
        this.fakeApiKey = fakeApiKey;
        this.secret = Buffer.from(fakeApiKey.secret, 'hex');

        this.apiKeyStub = sinon.stub(models.ApiKey, 'findOne');
        this.apiKeyStub.resolves();
        this.apiKeyStub.withArgs({id: fakeApiKey.id}).resolves(fakeApiKey);
    });

    afterEach(function () {
        sinon.restore();
    });

    it('should authenticate known+valid v4 API key', function (done) {
        const token = jwt.sign({
        }, this.secret, {
            keyid: this.fakeApiKey.id,
            algorithm: 'HS256',
            expiresIn: '5m',
            audience: '/v4/admin/',
            issuer: this.fakeApiKey.id
        });

        const req = {
            originalUrl: ADMIN_API_URL,
            headers: {
                authorization: `Ghost ${token}`
            }
        };
        const res = {};

        apiKeyAuth.admin.authenticate(req, res, (err) => {
            should.not.exist(err);
            req.api_key.should.eql(this.fakeApiKey);
            done();
        });
    });

    it('should authenticate known+valid non-versioned API key', function (done) {
        const token = jwt.sign({
        }, this.secret, {
            keyid: this.fakeApiKey.id,
            algorithm: 'HS256',
            expiresIn: '5m',
            audience: '/admin/',
            issuer: this.fakeApiKey.id
        });

        const req = {
            originalUrl: `${ADMIN_API_URL_NON_VERSIONED}session/`,
            headers: {
                authorization: `Ghost ${token}`
            }
        };
        const res = {};

        apiKeyAuth.admin.authenticate(req, res, (err) => {
            should.not.exist(err);
            req.api_key.should.eql(this.fakeApiKey);
            done();
        });
    });

    it('should authenticate known+valid non-versioned API key with a token created for versioned API', function (done) {
        const token = jwt.sign({
        }, this.secret, {
            keyid: this.fakeApiKey.id,
            algorithm: 'HS256',
            expiresIn: '5m',
            audience: 'v4/admin/',
            issuer: this.fakeApiKey.id
        });

        const req = {
            originalUrl: `${ADMIN_API_URL_NON_VERSIONED}session/`,
            headers: {
                authorization: `Ghost ${token}`
            }
        };
        const res = {};

        apiKeyAuth.admin.authenticate(req, res, (err) => {
            should.not.exist(err);
            req.api_key.should.eql(this.fakeApiKey);
            done();
        });
    });

    it('should NOT authenticate known+valid versioned API key with a token created for non-versioned API', function (done) {
        const token = jwt.sign({
        }, this.secret, {
            keyid: this.fakeApiKey.id,
            algorithm: 'HS256',
            expiresIn: '5m',
            audience: 'admin/',
            issuer: this.fakeApiKey.id
        });

        const req = {
            originalUrl: `${ADMIN_API_URL}session/`,
            headers: {
                authorization: `Ghost ${token}`
            }
        };
        const res = {};

        apiKeyAuth.admin.authenticate(req, res, (err) => {
            should.exist(err);
            should.equal(err instanceof errors.UnauthorizedError, true);
            err.code.should.eql('INVALID_JWT');
            should.not.exist(req.api_key);
            done();
        });
    });

    it('shouldn\'t authenticate with missing Ghost token', function (done) {
        const token = '';
        const req = {
            headers: {
                authorization: `Ghost ${token}`
            }
        };
        const res = {};

        apiKeyAuth.admin.authenticate(req, res, function next(err) {
            should.exist(err);
            should.equal(err instanceof errors.UnauthorizedError, true);
            err.code.should.eql('INVALID_AUTH_HEADER');
{'fraction_non_alphanumeric': 0.1439780306002354, 'fraction_numerical': 0.0051000392310710085, 'mean_word_length': 1.7285051730288976, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1558268', 'n_tokens_mistral': 2264, 'n_tokens_neox': 2206, 'n_words': 419}