Move api-keys module to src/lib

This removes circular dependencies between the device-api module and
the compose module, reducing total circular dependencies to 15

Change-type: patch
This commit is contained in:
Felipe Lalanne 2024-05-15 15:39:22 -04:00
parent 48f75e61b8
commit ac2db38742
16 changed files with 171 additions and 178 deletions

View File

@ -20,7 +20,7 @@ import type {
import log from '../lib/supervisor-console';
import * as deviceApi from '../device-api';
import * as apiKeys from '../lib/api-keys';
export function camelCaseConfig(
literalConfig: ConfigMap,
@ -369,7 +369,7 @@ export async function addFeaturesFromLabels(
},
'io.balena.features.supervisor-api': async () => {
// create a app/service specific API secret
const apiSecret = await deviceApi.generateScopedKey(
const apiSecret = await apiKeys.generateScopedKey(
service.appId,
service.serviceName,
);

View File

@ -1,6 +1,6 @@
import _ from 'lodash';
import { getGlobalApiKey, refreshKey } from '.';
import { getGlobalApiKey, refreshKey } from '../lib/api-keys';
import * as messages from './messages';
import * as eventTracker from '../event-tracker';
import * as deviceState from '../device-state';

View File

@ -1,7 +1,7 @@
import express from 'express';
import * as middleware from './middleware';
import * as apiKeys from './api-keys';
import type * as apiKeys from '../lib/api-keys';
import * as actions from './actions';
import log from '../lib/supervisor-console';
@ -15,10 +15,6 @@ interface SupervisorAPIConstructOpts {
// API key methods
// For better black boxing, device-api should serve as the interface
// to the rest of the Supervisor code for accessing API key related methods.
export const getGlobalApiKey = apiKeys.getGlobalApiKey;
export const refreshKey = apiKeys.refreshKey;
export const generateScopedKey = apiKeys.generateScopedKey;
export const getScopesForKey = apiKeys.getScopesForKey;
export class SupervisorAPI {
private routers: express.Router[];

View File

@ -1,4 +1,4 @@
import * as apiKeys from '../api-keys';
import * as apiKeys from '../../lib/api-keys';
import * as config from '../../config';
import type { Request } from 'express';

View File

@ -2,7 +2,7 @@ import express from 'express';
import type { Response } from 'express';
import * as actions from './actions';
import type { AuthorizedRequest } from './api-keys';
import type { AuthorizedRequest } from '../lib/api-keys';
import * as eventTracker from '../event-tracker';
import type * as deviceState from '../device-state';

View File

@ -26,7 +26,7 @@ import {
BadRequestError,
} from '../lib/errors';
import { isVPNActive } from '../network';
import type { AuthorizedRequest } from './api-keys';
import type { AuthorizedRequest } from '../lib/api-keys';
import { fromV2TargetState } from '../lib/legacy';
import * as actions from './actions';
import { v2ServiceEndpointError } from './messages';

View File

@ -25,7 +25,7 @@ import {
import * as updateLock from './lib/update-lock';
import { takeGlobalLockRO, takeGlobalLockRW } from './lib/process-lock';
import * as dbFormat from './device-state/db-format';
import { getGlobalApiKey } from './device-api';
import { getGlobalApiKey } from './lib/api-keys';
import * as sysInfo from './lib/system-info';
import { log } from './lib/supervisor-console';
import { loadTargetFromFile } from './device-state/preload';

View File

@ -1,7 +1,7 @@
import { expect } from 'chai';
import { Service } from '~/src/compose/service';
import * as deviceApi from '~/src/device-api';
import * as apiKeys from '~/lib/api-keys';
describe('compose/service: integration tests', () => {
describe('Feature labels', () => {
@ -41,7 +41,7 @@ describe('compose/service: integration tests', () => {
});
it('sets BALENA_API_KEY env var to the scoped API key value', async () => {
const mykey = await deviceApi.generateScopedKey(123456, 'foobar');
const mykey = await apiKeys.generateScopedKey(123456, 'foobar');
const service = await Service.fromComposeObject(
{

View File

@ -9,7 +9,7 @@ import { testfs } from 'mocha-pod';
import * as deviceState from '~/src/device-state';
import * as config from '~/src/config';
import * as hostConfig from '~/src/host-config';
import * as deviceApi from '~/src/device-api';
import * as apiKeys from '~/lib/api-keys';
import * as actions from '~/src/device-api/actions';
import * as TargetState from '~/src/device-state/target-state';
import * as updateLock from '~/lib/update-lock';
@ -56,10 +56,10 @@ describe('regenerates API keys', () => {
afterEach(() => (deviceState.reportCurrentState as SinonStub).restore());
it("communicates new key to cloud if it's a global key", async () => {
const originalGlobalKey = await deviceApi.getGlobalApiKey();
const originalGlobalKey = await apiKeys.getGlobalApiKey();
const newKey = await actions.regenerateKey(originalGlobalKey);
expect(originalGlobalKey).to.not.equal(newKey);
expect(newKey).to.equal(await deviceApi.getGlobalApiKey());
expect(newKey).to.equal(await apiKeys.getGlobalApiKey());
expect(deviceState.reportCurrentState as SinonStub).to.have.been.calledOnce;
expect(
(deviceState.reportCurrentState as SinonStub).firstCall.args[0],
@ -69,10 +69,10 @@ describe('regenerates API keys', () => {
});
it("doesn't communicate new key if it's a service key", async () => {
const originalScopedKey = await deviceApi.generateScopedKey(111, 'main');
const originalScopedKey = await apiKeys.generateScopedKey(111, 'main');
const newKey = await actions.regenerateKey(originalScopedKey);
expect(originalScopedKey).to.not.equal(newKey);
expect(newKey).to.not.equal(await deviceApi.getGlobalApiKey());
expect(newKey).to.not.equal(await apiKeys.getGlobalApiKey());
expect(deviceState.reportCurrentState as SinonStub).to.not.have.been.called;
});
});

View File

@ -1,6 +1,7 @@
import type * as express from 'express';
import request from 'supertest';
import * as apiKeys from '~/lib/api-keys';
import * as deviceApi from '~/src/device-api';
describe('device-api/index', () => {
@ -22,7 +23,7 @@ describe('device-api/index', () => {
await request(api)
.get('/ping')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
});
});

View File

@ -3,7 +3,7 @@ import request from 'supertest';
import * as config from '~/src/config';
import * as testDb from '~/src/db';
import * as deviceApi from '~/src/device-api';
import * as apiKeys from '~/lib/api-keys';
import * as middleware from '~/src/device-api/middleware';
describe('device-api/middleware', () => {
@ -35,7 +35,7 @@ describe('device-api/middleware', () => {
it('validates API key from request query', async () => {
await request(app)
.get(`/?apikey=${await deviceApi.getGlobalApiKey()}`)
.get(`/?apikey=${await apiKeys.getGlobalApiKey()}`)
.expect(200);
await request(app).get(`/?apikey=${INVALID_KEY}`).expect(401);
@ -44,7 +44,7 @@ describe('device-api/middleware', () => {
const cases = ['ApiKey', 'apiKey', 'APIKEY', 'ApIKeY'];
for (const query of cases) {
await request(app)
.get(`/?${query}=${await deviceApi.getGlobalApiKey()}`)
.get(`/?${query}=${await apiKeys.getGlobalApiKey()}`)
.expect(401);
}
});
@ -55,10 +55,7 @@ describe('device-api/middleware', () => {
for (const scheme of cases) {
await request(app)
.get('/')
.set(
'Authorization',
`${scheme} ${await deviceApi.getGlobalApiKey()}`,
)
.set('Authorization', `${scheme} ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
await request(app)
@ -74,10 +71,7 @@ describe('device-api/middleware', () => {
for (const scheme of cases) {
await request(app)
.get('/')
.set(
'Authorization',
`${scheme} ${await deviceApi.getGlobalApiKey()}`,
)
.set('Authorization', `${scheme} ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
await request(app)

View File

@ -8,6 +8,7 @@ import * as config from '~/src/config';
import * as db from '~/src/db';
import * as hostConfig from '~/src/host-config';
import type { Service } from '~/src/compose/service';
import * as apiKeys from '~/lib/api-keys';
import * as deviceApi from '~/src/device-api';
import * as actions from '~/src/device-api/actions';
import * as v1 from '~/src/device-api/v1';
@ -73,7 +74,7 @@ describe('device-api/v1', () => {
it('responds with 200', async () => {
await request(api)
.post('/v1/blink')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
});
});
@ -84,7 +85,7 @@ describe('device-api/v1', () => {
afterEach(() => (actions.regenerateKey as SinonStub).restore());
it('responds with 200 and valid new API key', async () => {
const oldKey = await deviceApi.getGlobalApiKey();
const oldKey = await apiKeys.getGlobalApiKey();
const newKey = 'my_new_key';
(actions.regenerateKey as SinonStub).resolves(newKey);
@ -98,7 +99,7 @@ describe('device-api/v1', () => {
});
it('responds with 503 if regenerate was unsuccessful', async () => {
const oldKey = await deviceApi.getGlobalApiKey();
const oldKey = await apiKeys.getGlobalApiKey();
(actions.regenerateKey as SinonStub).throws(new Error());
await request(api)
@ -125,7 +126,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/restart')
.send({ appId: 1234567, force: false })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(doRestartStub).to.have.been.calledWith(1234567, false);
doRestartStub.resetHistory();
@ -134,7 +135,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/restart')
.send({ appId: 7654321, force: true })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(doRestartStub).to.have.been.calledWith(7654321, true);
doRestartStub.resetHistory();
@ -143,7 +144,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/restart')
.send({ appId: 7654321 })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(doRestartStub).to.have.been.calledWith(7654321, false);
});
@ -151,12 +152,12 @@ describe('device-api/v1', () => {
it('responds with 400 if appId is missing', async () => {
await request(api)
.post('/v1/restart')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
});
it("responds with 401 if caller's API key is not in scope of appId", async () => {
const scopedKey = await deviceApi.generateScopedKey(1234567, 'main');
const scopedKey = await apiKeys.generateScopedKey(1234567, 'main');
await request(api)
.post('/v1/restart')
.send({ appId: 7654321 })
@ -168,7 +169,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/restart')
.send({ appId: 1234567 })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
});
@ -177,7 +178,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/restart')
.send({ appId: 1234567 })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(423);
});
@ -186,7 +187,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/restart')
.send({ appId: 1234567 })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(503);
});
});
@ -207,7 +208,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/purge')
.send({ appId: 1234567, force: false })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(doPurgeStub).to.have.been.calledWith(1234567, false);
doPurgeStub.resetHistory();
@ -216,7 +217,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/purge')
.send({ appId: 7654321, force: true })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(doPurgeStub).to.have.been.calledWith(7654321, true);
doPurgeStub.resetHistory();
@ -225,7 +226,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/purge')
.send({ appId: 7654321 })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(doPurgeStub).to.have.been.calledWith(7654321, false);
});
@ -233,12 +234,12 @@ describe('device-api/v1', () => {
it('responds with 400 if appId is missing', async () => {
await request(api)
.post('/v1/purge')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
});
it("responds with 401 if caller's API key is not in scope of appId", async () => {
const scopedKey = await deviceApi.generateScopedKey(1234567, 'main');
const scopedKey = await apiKeys.generateScopedKey(1234567, 'main');
await request(api)
.post('/v1/purge')
.send({ appId: 7654321 })
@ -250,7 +251,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/purge')
.send({ appId: 1234567 })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
});
@ -259,7 +260,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/purge')
.send({ appId: 1234567 })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(423);
});
@ -268,7 +269,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/purge')
.send({ appId: 1234567 })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(503);
});
});
@ -297,7 +298,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/apps/1234567/stop')
.send({ force: false })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'stop',
@ -311,7 +312,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/apps/7654321/stop')
.send({ force: true })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'stop',
@ -324,7 +325,7 @@ describe('device-api/v1', () => {
// Defaults to force: false
await request(api)
.post('/v1/apps/7654321/stop')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'stop',
@ -335,7 +336,7 @@ describe('device-api/v1', () => {
});
it("responds with 401 if caller's API key is not in scope of appId", async () => {
const scopedKey = await deviceApi.generateScopedKey(1234567, 'main');
const scopedKey = await apiKeys.generateScopedKey(1234567, 'main');
await request(api)
.post('/v1/apps/7654321/stop')
.set('Authorization', `Bearer ${scopedKey}`)
@ -345,7 +346,7 @@ describe('device-api/v1', () => {
it('responds with 200 and containerId if service stop succeeded if service stop succeeded', async () => {
await request(api)
.post('/v1/apps/1234567/stop')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200, { containerId: 'abcdef' });
});
@ -353,20 +354,20 @@ describe('device-api/v1', () => {
executeServiceActionStub.throws(new NotFoundError());
await request(api)
.post('/v1/apps/1234567/stop')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(404);
});
it('responds with 400 if invalid appId or appId corresponds to a multicontainer release', async () => {
await request(api)
.post('/v1/apps/badAppId/stop')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
executeServiceActionStub.throws(new BadRequestError());
await request(api)
.post('/v1/apps/1234567/stop')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
});
@ -374,7 +375,7 @@ describe('device-api/v1', () => {
executeServiceActionStub.throws(new UpdatesLockedError());
await request(api)
.post('/v1/apps/1234567/stop')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(423);
});
@ -382,7 +383,7 @@ describe('device-api/v1', () => {
executeServiceActionStub.throws(new Error());
await request(api)
.post('/v1/apps/1234567/stop')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(503);
});
});
@ -411,7 +412,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/apps/1234567/start')
.send({ force: false })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'start',
@ -425,7 +426,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/apps/7654321/start')
.send({ force: true })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'start',
@ -438,7 +439,7 @@ describe('device-api/v1', () => {
// Defaults to force: false
await request(api)
.post('/v1/apps/7654321/start')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'start',
@ -449,7 +450,7 @@ describe('device-api/v1', () => {
});
it("responds with 401 if caller's API key is not in scope of appId", async () => {
const scopedKey = await deviceApi.generateScopedKey(1234567, 'main');
const scopedKey = await apiKeys.generateScopedKey(1234567, 'main');
await request(api)
.post('/v1/apps/7654321/start')
.set('Authorization', `Bearer ${scopedKey}`)
@ -459,7 +460,7 @@ describe('device-api/v1', () => {
it('responds with 200 and containerId if service start succeeded', async () => {
await request(api)
.post('/v1/apps/1234567/start')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200, { containerId: 'abcdef' });
});
@ -467,20 +468,20 @@ describe('device-api/v1', () => {
executeServiceActionStub.throws(new NotFoundError());
await request(api)
.post('/v1/apps/1234567/start')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(404);
});
it('responds with 400 if invalid appId or appId corresponds to a multicontainer release', async () => {
await request(api)
.post('/v1/apps/badAppId/start')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
executeServiceActionStub.throws(new BadRequestError());
await request(api)
.post('/v1/apps/1234567/start')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
});
@ -488,7 +489,7 @@ describe('device-api/v1', () => {
executeServiceActionStub.throws(new UpdatesLockedError());
await request(api)
.post('/v1/apps/1234567/start')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(423);
});
@ -496,7 +497,7 @@ describe('device-api/v1', () => {
executeServiceActionStub.throws(new Error());
await request(api)
.post('/v1/apps/1234567/start')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(503);
});
});
@ -513,7 +514,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/reboot')
.send({ force: false })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`);
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`);
expect(executeDeviceActionStub).to.have.been.calledWith(
{
action: 'reboot',
@ -526,7 +527,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/reboot')
.send({ force: true })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`);
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`);
expect(executeDeviceActionStub).to.have.been.calledWith(
{
action: 'reboot',
@ -538,7 +539,7 @@ describe('device-api/v1', () => {
// Defaults to force: false
await request(api)
.post('/v1/reboot')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`);
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`);
expect(executeDeviceActionStub).to.have.been.calledWith(
{
action: 'reboot',
@ -550,7 +551,7 @@ describe('device-api/v1', () => {
it('responds with 202 if request successful', async () => {
await request(api)
.post('/v1/reboot')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(202);
});
@ -558,7 +559,7 @@ describe('device-api/v1', () => {
executeDeviceActionStub.throws(new UpdatesLockedError());
await request(api)
.post('/v1/reboot')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(423);
});
@ -566,7 +567,7 @@ describe('device-api/v1', () => {
executeDeviceActionStub.throws(new Error());
await request(api)
.post('/v1/reboot')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(500);
});
});
@ -583,7 +584,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/shutdown')
.send({ force: false })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`);
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`);
expect(executeDeviceActionStub).to.have.been.calledWith(
{
action: 'shutdown',
@ -596,7 +597,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/shutdown')
.send({ force: true })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`);
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`);
expect(executeDeviceActionStub).to.have.been.calledWith(
{
action: 'shutdown',
@ -608,7 +609,7 @@ describe('device-api/v1', () => {
// Defaults to force: false
await request(api)
.post('/v1/shutdown')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`);
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`);
expect(executeDeviceActionStub).to.have.been.calledWith(
{
action: 'shutdown',
@ -620,7 +621,7 @@ describe('device-api/v1', () => {
it('responds with 202 if request successful', async () => {
await request(api)
.post('/v1/shutdown')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(202);
});
@ -628,7 +629,7 @@ describe('device-api/v1', () => {
executeDeviceActionStub.throws(new UpdatesLockedError());
await request(api)
.post('/v1/shutdown')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(423);
});
@ -636,7 +637,7 @@ describe('device-api/v1', () => {
executeDeviceActionStub.throws(new Error());
await request(api)
.post('/v1/shutdown')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(500);
});
});
@ -653,7 +654,7 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/update')
.send({ force: false })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`);
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`);
expect(updateTargetStub.lastCall.firstArg).to.be.false;
updateTargetStub.resetHistory();
@ -661,14 +662,14 @@ describe('device-api/v1', () => {
await request(api)
.post('/v1/update')
.send({ force: true })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`);
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`);
expect(updateTargetStub.lastCall.firstArg).to.be.true;
updateTargetStub.resetHistory();
// Defaults to force: false
await request(api)
.post('/v1/update')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`);
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`);
expect(updateTargetStub.lastCall.firstArg).to.be.false;
});
@ -676,7 +677,7 @@ describe('device-api/v1', () => {
updateTargetStub.returns(true);
await request(api)
.post('/v1/update')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(204);
});
@ -684,7 +685,7 @@ describe('device-api/v1', () => {
updateTargetStub.returns(false);
await request(api)
.post('/v1/update')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(202);
});
});
@ -706,21 +707,21 @@ describe('device-api/v1', () => {
it('validates data from request body', async () => {
await request(api)
.get('/v1/apps/1234567')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`);
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`);
expect(getSingleContainerAppStub).to.have.been.calledWith(1234567);
});
it('responds with 200 if request successful', async () => {
await request(api)
.get('/v1/apps/1234567')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200, {});
});
it('responds with 400 if invalid appId parameter', async () => {
await request(api)
.get('/v1/apps/badAppId')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
});
@ -728,12 +729,12 @@ describe('device-api/v1', () => {
getSingleContainerAppStub.throws(new BadRequestError());
await request(api)
.get('/v1/apps/1234567')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
});
it("responds with 401 if caller's API key is not in scope of appId", async () => {
const scopedKey = await deviceApi.generateScopedKey(7654321, 'main');
const scopedKey = await apiKeys.generateScopedKey(7654321, 'main');
await request(api)
.get('/v1/apps/1234567')
.set('Authorization', `Bearer ${scopedKey}`)
@ -744,7 +745,7 @@ describe('device-api/v1', () => {
getSingleContainerAppStub.throws(new Error());
await request(api)
.get('/v1/apps/1234567')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(503);
});
});
@ -760,7 +761,7 @@ describe('device-api/v1', () => {
getLegacyDeviceStateStub.resolves({ test_state: 'Success' });
await request(api)
.get('/v1/device')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200, { test_state: 'Success' });
});
@ -768,7 +769,7 @@ describe('device-api/v1', () => {
getLegacyDeviceStateStub.throws(new Error());
await request(api)
.get('/v1/device')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(503);
});
});
@ -787,7 +788,7 @@ describe('device-api/v1', () => {
getHostConfigStub.resolves({ network: { hostname: 'deadbeef' } });
await request(api)
.get('/v1/device/host-config')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200, { network: { hostname: 'deadbeef' } });
});
@ -795,7 +796,7 @@ describe('device-api/v1', () => {
getHostConfigStub.throws(new Error());
await request(api)
.get('/v1/device/host-config')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(503);
});
});
@ -824,7 +825,7 @@ describe('device-api/v1', () => {
for (const key of Object.keys(invalidProxyReqs)) {
await request(api)
.patch('/v1/device/host-config')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.send({ network: { proxy: { [key]: invalidProxyReqs[key] } } })
.expect(200)
.then(() => {
@ -852,7 +853,7 @@ describe('device-api/v1', () => {
await request(api)
.patch('/v1/device/host-config')
.send({})
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200)
.then(() => {
expect(log.warn as SinonStub).to.have.been.calledWith(

View File

@ -6,6 +6,7 @@ import request from 'supertest';
import * as config from '~/src/config';
import * as db from '~/src/db';
import * as apiKeys from '~/lib/api-keys';
import * as deviceApi from '~/src/device-api';
import * as actions from '~/src/device-api/actions';
import * as v2 from '~/src/device-api/v2';
@ -50,7 +51,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/restart')
.send({ force: false })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(doRestartStub).to.have.been.calledWith(1234567, false);
doRestartStub.resetHistory();
@ -59,7 +60,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/restart')
.send({ force: true })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(doRestartStub).to.have.been.calledWith(7654321, true);
doRestartStub.resetHistory();
@ -67,7 +68,7 @@ describe('device-api/v2', () => {
// Defaults to force: false
await request(api)
.post('/v2/applications/7654321/restart')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(doRestartStub).to.have.been.calledWith(7654321, false);
});
@ -75,12 +76,12 @@ describe('device-api/v2', () => {
it('responds with 400 if appId is missing', async () => {
await request(api)
.post('/v2/applications/badAppId/restart')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
});
it("responds with 401 if caller's API key is not in scope of appId", async () => {
const scopedKey = await deviceApi.generateScopedKey(1234567, 'main');
const scopedKey = await apiKeys.generateScopedKey(1234567, 'main');
await request(api)
.post('/v2/applications/7654321/restart')
.set('Authorization', `Bearer ${scopedKey}`)
@ -90,7 +91,7 @@ describe('device-api/v2', () => {
it('responds with 200 if restart succeeded', async () => {
await request(api)
.post('/v2/applications/1234567/restart')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
});
@ -98,7 +99,7 @@ describe('device-api/v2', () => {
doRestartStub.throws(new UpdatesLockedError());
await request(api)
.post('/v2/applications/1234567/restart')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(423);
});
@ -106,7 +107,7 @@ describe('device-api/v2', () => {
doRestartStub.throws(new Error());
await request(api)
.post('/v2/applications/7654321/restart')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(503);
});
});
@ -128,7 +129,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/purge')
.send({ force: false })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(doPurgeStub).to.have.been.calledWith(1234567, false);
doPurgeStub.resetHistory();
@ -137,7 +138,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/purge')
.send({ force: true })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(doPurgeStub).to.have.been.calledWith(7654321, true);
doPurgeStub.resetHistory();
@ -145,7 +146,7 @@ describe('device-api/v2', () => {
// Defaults to force: false
await request(api)
.post('/v2/applications/7654321/purge')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(doPurgeStub).to.have.been.calledWith(7654321, false);
});
@ -153,12 +154,12 @@ describe('device-api/v2', () => {
it('responds with 400 if appId is missing', async () => {
await request(api)
.post('/v2/applications/badAppId/purge')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
});
it("responds with 401 if caller's API key is not in scope of appId", async () => {
const scopedKey = await deviceApi.generateScopedKey(1234567, 'main');
const scopedKey = await apiKeys.generateScopedKey(1234567, 'main');
await request(api)
.post('/v2/applications/7654321/purge')
.set('Authorization', `Bearer ${scopedKey}`)
@ -168,7 +169,7 @@ describe('device-api/v2', () => {
it('responds with 200 if purge succeeded', async () => {
await request(api)
.post('/v2/applications/1234567/purge')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
});
@ -176,7 +177,7 @@ describe('device-api/v2', () => {
doPurgeStub.throws(new UpdatesLockedError());
await request(api)
.post('/v2/applications/1234567/purge')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(423);
});
@ -184,7 +185,7 @@ describe('device-api/v2', () => {
doPurgeStub.throws(new Error());
await request(api)
.post('/v2/applications/7654321/purge')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(503);
});
});
@ -209,7 +210,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/stop-service')
.send({ force: false, serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'stop',
@ -224,7 +225,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/stop-service')
.send({ force: true, serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'stop',
@ -239,7 +240,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/stop-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'stop',
@ -254,7 +255,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/stop-service')
.send({ imageId: 111 })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'stop',
@ -269,7 +270,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/stop-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'stop',
@ -281,7 +282,7 @@ describe('device-api/v2', () => {
});
it("responds with 401 if caller's API key is not in scope of appId", async () => {
const scopedKey = await deviceApi.generateScopedKey(1234567, 'main');
const scopedKey = await apiKeys.generateScopedKey(1234567, 'main');
await request(api)
.post('/v2/applications/7654321/stop-service')
.send({ serviceName: 'test' })
@ -293,7 +294,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/stop-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
});
@ -302,21 +303,21 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/stop-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(404);
});
it('responds with 400 if invalid appId or missing serviceName/imageId from request body', async () => {
await request(api)
.post('/v2/applications/badAppId/stop-service')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
executeServiceActionStub.throws(new BadRequestError());
await request(api)
.post('/v2/applications/1234567/stop-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
});
@ -325,7 +326,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/stop-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(423);
});
@ -334,7 +335,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/stop-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(503);
});
});
@ -359,7 +360,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/start-service')
.send({ force: false, serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'start',
@ -374,7 +375,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/start-service')
.send({ force: true, serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'start',
@ -389,7 +390,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/start-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'start',
@ -404,7 +405,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/start-service')
.send({ imageId: 111 })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'start',
@ -419,7 +420,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/start-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'start',
@ -431,7 +432,7 @@ describe('device-api/v2', () => {
});
it("responds with 401 if caller's API key is not in scope of appId", async () => {
const scopedKey = await deviceApi.generateScopedKey(1234567, 'main');
const scopedKey = await apiKeys.generateScopedKey(1234567, 'main');
await request(api)
.post('/v2/applications/7654321/start-service')
.send({ serviceName: 'test' })
@ -443,7 +444,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/start-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
});
@ -452,21 +453,21 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/start-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(404);
});
it('responds with 400 if invalid appId or missing serviceName/imageId from request body', async () => {
await request(api)
.post('/v2/applications/badAppId/start-service')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
executeServiceActionStub.throws(new BadRequestError());
await request(api)
.post('/v2/applications/1234567/start-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
});
@ -475,7 +476,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/start-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(423);
});
@ -484,7 +485,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/start-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(503);
});
});
@ -509,7 +510,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/restart-service')
.send({ force: false, serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'restart',
@ -524,7 +525,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/restart-service')
.send({ force: true, serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'restart',
@ -539,7 +540,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/restart-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'restart',
@ -554,7 +555,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/restart-service')
.send({ imageId: 111 })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'restart',
@ -569,7 +570,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/restart-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
expect(executeServiceActionStub).to.have.been.calledWith({
action: 'restart',
@ -581,7 +582,7 @@ describe('device-api/v2', () => {
});
it("responds with 401 if caller's API key is not in scope of appId", async () => {
const scopedKey = await deviceApi.generateScopedKey(1234567, 'main');
const scopedKey = await apiKeys.generateScopedKey(1234567, 'main');
await request(api)
.post('/v2/applications/7654321/restart-service')
.send({ serviceName: 'test' })
@ -593,7 +594,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/restart-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
});
@ -602,21 +603,21 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/restart-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(404);
});
it('responds with 400 if invalid appId or missing serviceName/imageId from request body', async () => {
await request(api)
.post('/v2/applications/badAppId/restart-service')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
executeServiceActionStub.throws(new BadRequestError());
await request(api)
.post('/v2/applications/1234567/restart-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(400);
});
@ -625,7 +626,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/1234567/restart-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(423);
});
@ -634,7 +635,7 @@ describe('device-api/v2', () => {
await request(api)
.post('/v2/applications/7654321/restart-service')
.send({ serviceName: 'test' })
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(503);
});
});

View File

@ -8,7 +8,7 @@ import mockedAPI = require('~/test-lib/mocked-device-api');
import * as apiBinder from '~/src/api-binder';
import * as deviceState from '~/src/device-state';
import type SupervisorAPI from '~/src/device-api';
import * as deviceApi from '~/src/device-api';
import * as apiKeys from '~/lib/api-keys';
import * as serviceManager from '~/src/compose/service-manager';
import * as images from '~/src/compose/images';
import * as config from '~/src/config';
@ -78,7 +78,7 @@ describe('SupervisorAPI [V2 Endpoints]', () => {
await request
.get('/v2/device/vpn')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect('Content-Type', /json/)
.expect(sampleResponses.V2.GET['/device/vpn'].statusCode)
.then((response) => {
@ -94,7 +94,7 @@ describe('SupervisorAPI [V2 Endpoints]', () => {
await request
.get('/v2/applications/1/state')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(sampleResponses.V2.GET['/applications/1/state'].statusCode)
.expect('Content-Type', /json/)
.then((response) => {
@ -108,7 +108,7 @@ describe('SupervisorAPI [V2 Endpoints]', () => {
await request
.get('/v2/applications/123invalid/state')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect('Content-Type', /json/)
.expect(
sampleResponses.V2.GET['/applications/123invalid/state'].statusCode,
@ -124,7 +124,7 @@ describe('SupervisorAPI [V2 Endpoints]', () => {
await request
.get('/v2/applications/9000/state')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(sampleResponses.V2.GET['/applications/9000/state'].statusCode)
.then((response) => {
expect(response.body).to.deep.equal(
@ -135,7 +135,7 @@ describe('SupervisorAPI [V2 Endpoints]', () => {
describe('Scoped API Keys', () => {
it('returns 409 because app is out of scope of the key', async () => {
const apiKey = await deviceApi.generateScopedKey(3, 'main');
const apiKey = await apiKeys.generateScopedKey(3, 'main');
await request
.get('/v2/applications/2/state')
.set('Accept', 'application/json')
@ -157,7 +157,7 @@ describe('SupervisorAPI [V2 Endpoints]', () => {
it('should return scoped application', async () => {
// Create scoped key for application
const appScopedKey = await deviceApi.generateScopedKey(1658654, 'main');
const appScopedKey = await apiKeys.generateScopedKey(1658654, 'main');
// Setup device conditions
serviceManagerMock.resolves([mockedAPI.mockService({ appId: 1658654 })]);
imagesMock.resolves([mockedAPI.mockImage({ appId: 1658654 })]);
@ -181,7 +181,7 @@ describe('SupervisorAPI [V2 Endpoints]', () => {
it('should return no application info due to lack of scope', async () => {
// Create scoped key for wrong application
const appScopedKey = await deviceApi.generateScopedKey(1, 'main');
const appScopedKey = await apiKeys.generateScopedKey(1, 'main');
// Setup device conditions
serviceManagerMock.resolves([mockedAPI.mockService({ appId: 1658654 })]);
imagesMock.resolves([mockedAPI.mockImage({ appId: 1658654 })]);
@ -204,7 +204,7 @@ describe('SupervisorAPI [V2 Endpoints]', () => {
it('should return success when device has no applications', async () => {
// Create scoped key for any application
const appScopedKey = await deviceApi.generateScopedKey(1658654, 'main');
const appScopedKey = await apiKeys.generateScopedKey(1658654, 'main');
// Setup device conditions
serviceManagerMock.resolves([]);
imagesMock.resolves([]);
@ -227,7 +227,7 @@ describe('SupervisorAPI [V2 Endpoints]', () => {
it('should only return 1 application when N > 1 applications on device', async () => {
// Create scoped key for application
const appScopedKey = await deviceApi.generateScopedKey(1658654, 'main');
const appScopedKey = await apiKeys.generateScopedKey(1658654, 'main');
// Setup device conditions
serviceManagerMock.resolves([
mockedAPI.mockService({ appId: 1658654 }),

View File

@ -4,9 +4,9 @@ import { expect } from 'chai';
import * as config from '~/src/config';
import * as testDb from '~/src/db';
import * as deviceApi from '~/src/device-api';
import * as apiKeys from '~/lib/api-keys';
import * as middleware from '~/src/device-api/middleware';
import type { AuthorizedRequest } from '~/src/device-api/api-keys';
import type { AuthorizedRequest } from '~/lib/api-keys';
describe('device-api/api-keys', () => {
let app: express.Application;
@ -30,8 +30,8 @@ describe('device-api/api-keys', () => {
});
it('should generate a key which is scoped for a single application', async () => {
const appOneKey = await deviceApi.generateScopedKey(111, 'one');
const appTwoKey = await deviceApi.generateScopedKey(222, 'two');
const appOneKey = await apiKeys.generateScopedKey(111, 'one');
const appTwoKey = await apiKeys.generateScopedKey(222, 'two');
await request(app)
.get('/test/111')
@ -55,7 +55,7 @@ describe('device-api/api-keys', () => {
});
it('should generate a key which is scoped for multiple applications', async () => {
const multiAppKey = await deviceApi.generateScopedKey(111, 'three', {
const multiAppKey = await apiKeys.generateScopedKey(111, 'three', {
scopes: [111, 222].map((appId) => ({ type: 'app', appId })),
});
@ -73,54 +73,54 @@ describe('device-api/api-keys', () => {
it('should generate a key which is scoped for all applications', async () => {
await request(app)
.get('/test/111')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
await request(app)
.get('/test/222')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.set('Authorization', `Bearer ${await apiKeys.getGlobalApiKey()}`)
.expect(200);
});
it('should have a cached lookup of key scopes', async () => {
const globalScopes = await deviceApi.getScopesForKey(
await deviceApi.getGlobalApiKey(),
const globalScopes = await apiKeys.getScopesForKey(
await apiKeys.getGlobalApiKey(),
);
const key = 'my-new-key';
await testDb
.models('apiSecret')
.where({ key: await deviceApi.getGlobalApiKey() })
.where({ key: await apiKeys.getGlobalApiKey() })
.update({ key });
// Key has been changed, but cache should retain the old key
expect(
await deviceApi.getScopesForKey(await deviceApi.getGlobalApiKey()),
await apiKeys.getScopesForKey(await apiKeys.getGlobalApiKey()),
).to.deep.equal(globalScopes);
// Bust the cache and generate a new global API key
const refreshedKey = await deviceApi.refreshKey(
await deviceApi.getGlobalApiKey(),
const refreshedKey = await apiKeys.refreshKey(
await apiKeys.getGlobalApiKey(),
);
// Key that we changed in db is no longer valid
expect(await deviceApi.getScopesForKey(key)).to.be.null;
expect(await apiKeys.getScopesForKey(key)).to.be.null;
// Refreshed key should have the global scopes
expect(await deviceApi.getScopesForKey(refreshedKey)).to.deep.equal(
expect(await apiKeys.getScopesForKey(refreshedKey)).to.deep.equal(
globalScopes,
);
});
it('should regenerate a key and invalidate the old one', async () => {
const appScopedKey = await deviceApi.generateScopedKey(111, 'four');
const appScopedKey = await apiKeys.generateScopedKey(111, 'four');
await request(app)
.get('/test/111')
.set('Authorization', `Bearer ${appScopedKey}`)
.expect(200);
const newScopedKey = await deviceApi.refreshKey(appScopedKey);
const newScopedKey = await apiKeys.refreshKey(appScopedKey);
await request(app)
.get('/test/111')