Skip to content

Commit

Permalink
feat: add extra info to /probes if systemkey provided
Browse files Browse the repository at this point in the history
  • Loading branch information
alexey-yarmosh committed Dec 19, 2023
1 parent 0363f42 commit 6c42d17
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 30 deletions.
8 changes: 6 additions & 2 deletions src/adoption-code/route/adoption-code.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import type { Context } from 'koa';
import type Router from '@koa/router';
import createHttpError from 'http-errors';
import type { AdoptionCodeRequest } from '../types.js';
import { bodyParser } from '../../lib/http/middleware/body-parser.js';
import { validate } from '../../lib/http/middleware/validate.js';
import { schema } from '../schema.js';
import { isSystem } from '../../lib/http/middleware/is-system.js';
import { codeSender } from '../sender.js';

const handle = async (ctx: Context): Promise<void> => {
if (!ctx['isSystem']) {
throw createHttpError(403, 'Forbidden', { type: 'access_forbidden' });
}

const request = ctx.request.body as AdoptionCodeRequest;
const socket = await codeSender.sendCode(request);

Expand All @@ -26,5 +30,5 @@ const handle = async (ctx: Context): Promise<void> => {
};

export const registerSendCodeRoute = (router: Router): void => {
router.post('/adoption-code', '/adoption-code', isSystem(), bodyParser(), validate(schema), handle);
router.post('/adoption-code', '/adoption-code', bodyParser(), validate(schema), handle);
};
12 changes: 3 additions & 9 deletions src/lib/http/middleware/is-system.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import type { Middleware } from 'koa';
import createHttpError from 'http-errors';
import config from 'config';

export const isSystem = (): Middleware => async (ctx, next) => {
export const isSystemMw: Middleware = async (ctx, next) => {
const systemKey = config.get<string>('systemApi.key');
const isValid = systemKey.length > 0 && ctx.query['systemkey'] === systemKey;

if (!isValid) {
throw createHttpError(403, 'Forbidden', { type: 'access_forbidden' });
} else {
await next();
}
ctx['isSystem'] = systemKey.length > 0 && ctx.query['systemkey'] === systemKey;
return next();
};
4 changes: 3 additions & 1 deletion src/lib/http/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { defaultJson } from './middleware/default-json.js';
import { errorHandlerMw } from './middleware/error-handler.js';
import { corsHandler } from './middleware/cors.js';
import { isAdminMw } from './middleware/is-admin.js';
import { isSystemMw } from './middleware/is-system.js';
import domainRedirect from './middleware/domain-redirect.js';
import { docsLink } from './middleware/docs-link.js';
import type { CustomContext } from '../../types.js';
Expand All @@ -47,7 +48,8 @@ rootRouter.get<object, CustomContext>('/', '/', (ctx) => {
const apiRouter = new Router({ strict: true, sensitive: true });

apiRouter.prefix('/v1')
.use(isAdminMw);
.use(isAdminMw)
.use(isSystemMw);

// GET /spec.yaml
registerSpecRoute(apiRouter);
Expand Down
8 changes: 4 additions & 4 deletions src/probe/route/get-probes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ import type { RemoteProbeSocket } from '../../lib/ws/server.js';
import { fetchSockets } from '../../lib/ws/fetch-sockets.js';

const handle = async (ctx: ParameterizedContext<DefaultState, DefaultContext & Router.RouterParamContext>): Promise<void> => {
const { isAdmin } = ctx;
const { isAdmin, isSystem } = ctx;
let sockets = await fetchSockets();

if (!isAdmin) {
if (!isAdmin && !isSystem) {
sockets = sockets.filter(socket => socket.data.probe.status === 'ready');
}

ctx.body = sockets.map((socket: RemoteProbeSocket) => ({
status: isAdmin ? socket.data.probe.status : undefined,
status: (isAdmin || isSystem) ? socket.data.probe.status : undefined,
version: socket.data.probe.version,
nodeVersion: isAdmin ? socket.data.probe.nodeVersion : undefined,
uuid: isAdmin ? socket.data.probe.uuid : undefined,
ipAddress: isAdmin ? socket.data.probe.ipAddress : undefined,
ipAddress: (isAdmin || isSystem) ? socket.data.probe.ipAddress : undefined,
location: {
continent: socket.data.probe.location.continent,
region: socket.data.probe.location.region,
Expand Down
2 changes: 1 addition & 1 deletion test/tests/integration/adoption-code.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe('Adoption code', () => {
expect(adoptionCodeStub.args[0]).to.deep.equal([{ code: '123456' }]);
});

it('should return 403 for non-admins', async () => {
it('should return 403 for wrong system key', async () => {
await requestAgent.post('/v1/adoption-code?systemkey=wrongkey')
.send({
ip: '1.2.3.4',
Expand Down
34 changes: 34 additions & 0 deletions test/tests/integration/probes/get-probes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,40 @@ describe('Get Probes', () => {
});
});

it('should add extra info if system key is provided', async () => {
nockGeoIpProviders({ ip2location: 'argentina', ipmap: 'argentina', maxmind: 'argentina', ipinfo: 'argentina', fastly: 'argentina' });

const probe = await addProbe();
probe.emit('probe:status:update', 'ready');

await requestAgent.get('/v1/probes?systemkey=system')
.send()
.expect(200)
.expect((response) => {
expect(response.body[0]).to.deep.equal({
version: '0.14.0',
ipAddress: '1.2.3.4',
location: {
continent: 'SA',
region: 'South America',
country: 'AR',
state: null,
city: 'Buenos Aires',
asn: 61004,
latitude: -34.6131,
longitude: -58.3772,
network: 'InterBS S.R.L. (BAEHOST)',
},
status: 'ready',
tags: [],
resolvers: [],
});

expect(response.body[0].ipAddress).to.be.a('string');
expect(response).to.matchApiSchema();
});
});

it('should add hardware info if admin key is provided and there is hardware info', async () => {
nockGeoIpProviders({ ip2location: 'argentina', ipmap: 'argentina', maxmind: 'argentina', ipinfo: 'argentina', fastly: 'argentina' });

Expand Down
23 changes: 10 additions & 13 deletions test/tests/unit/middleware/is-system.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { Context } from 'koa';
import * as sinon from 'sinon';
import { expect } from 'chai';
import createHttpError from 'http-errors';
import { isSystem } from '../../../../src/lib/http/middleware/is-system.js';
import { isSystemMw } from '../../../../src/lib/http/middleware/is-system.js';

const next = sinon.stub();

Expand All @@ -11,23 +10,21 @@ beforeEach(() => {
});

describe('rate limit middleware', () => {
it('should reject requests without "systemkey" parameter', async () => {
it('should set to "false" for requests without "systemkey" parameter', async () => {
const ctx = { query: {} } as unknown as Context;
const err = await isSystem()(ctx, next).catch((err: unknown) => err);
expect(err).to.deep.equal(createHttpError(403, 'Forbidden', { type: 'access_forbidden' }));
expect(next.callCount).to.equal(0);
await isSystemMw(ctx, next);
expect(ctx['isSystem']).to.equal(false);
});

it('should reject requests with invalid "systemkey" parameter', async () => {
it('should set to "false" for requests with invalid "systemkey" parameter', async () => {
const ctx = { query: { systemkey: 'wrongkey' } } as unknown as Context;
const err = await isSystem()(ctx, next).catch((err: unknown) => err);
expect(err).to.deep.equal(createHttpError(403, 'Forbidden', { type: 'access_forbidden' }));
expect(next.callCount).to.equal(0);
await isSystemMw(ctx, next);
expect(ctx['isSystem']).to.equal(false);
});

it('should accept requests with valid "systemkey" parameter', async () => {
it('should set to "true" for requests with valid "systemkey" parameter', async () => {
const ctx = { query: { systemkey: 'system' } } as unknown as Context;
await isSystem()(ctx, next);
expect(next.callCount).to.equal(1);
await isSystemMw(ctx, next);
expect(ctx['isSystem']).to.equal(true);
});
});
2 changes: 2 additions & 0 deletions wallaby.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export default function wallaby () {
'src/**/*.json',
'config/*',
'public/**/*.yaml',
'seeds/**/*',
'migrations/**/*',
'test/utils/**/*.ts',
'test/mocks/**/*',
'test/plugins/**/*',
Expand Down

0 comments on commit 6c42d17

Please sign in to comment.