Skip to content

Commit 04f2a19

Browse files
authored
fix: allow admin to communicate with core (#2135)
* fix: allow admin to communicate with core * fix: add a protected endpoint that busts all file caches
1 parent f35e3eb commit 04f2a19

6 files changed

Lines changed: 47 additions & 4 deletions

File tree

src/plugins/meta.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import type { FastifyBaseLogger, FastifySchema } from 'fastify';
66

77
import type { UnionOfConst } from '@graasp/sdk';
88

9+
import { bustFileCache } from '../bustCache';
910
import { resolveDependency } from '../di/utils';
1011
import { db } from '../drizzle/db';
12+
import { authenticateAdminSharedSecret } from '../services/auth/plugins/passport/preHandlers';
1113
import { SearchService } from '../services/item/plugins/publication/published/plugins/search/search.service';
1214
import { assertIsError } from '../utils/assertions';
1315
import {
@@ -110,10 +112,12 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
110112
};
111113
});
112114

113-
fastify.get('/api/version', async (_, reply) => {
114-
// allow request cross origin
115-
reply.header('Access-Control-Allow-Origin', '*');
116-
return `${APP_VERSION} @ ${BUILD_TIMESTAMP}`;
115+
fastify.get('/api/version', async () => {
116+
return { version: APP_VERSION, buildTimestamp: BUILD_TIMESTAMP };
117+
});
118+
119+
fastify.get('/api/bust-cache', { preHandler: authenticateAdminSharedSecret }, async () => {
120+
await bustFileCache();
117121
});
118122
};
119123

src/services/auth/plugins/passport/plugin.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { MemberRepository } from '../../../member/member.repository';
1919
import { MemberPasswordService } from '../password/password.service';
2020
import { SHORT_TOKEN_PARAM } from './constants';
2121
import { PassportStrategy } from './strategies';
22+
import adminSharedSecretStrategy from './strategies/adminSharedSecret';
2223
import emailChangeStrategy from './strategies/emailChange';
2324
import jwtAppsStrategy from './strategies/jwtApps';
2425
import jwtChallengeVerifierStrategy from './strategies/jwtChallengeVerifier';
@@ -57,6 +58,9 @@ const plugin: FastifyPluginAsync = async (fastify: FastifyInstance) => {
5758
//-- Sessions Strategies --//
5859
strictSessionStrategy(fastifyPassport);
5960

61+
//-- Shared Secret Strategy (machine-to-machine) --//
62+
adminSharedSecretStrategy(fastifyPassport);
63+
6064
//-- Password Strategies --//
6165
passwordStrategy(fastifyPassport, memberPasswordService, {
6266
propagateError: true,

src/services/auth/plugins/passport/preHandlers.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ export const guestAuthenticateAppsJWT = fastifyPassport.authenticate(
7474
},
7575
) as RouteShorthandHook<preHandlerHookHandler>;
7676

77+
/**
78+
* Shared secret authentication for machine-to-machine routes.
79+
* Requires `Authorization: Bearer <ADMIN_SHARED_SECRET>` header.
80+
*/
81+
export const authenticateAdminSharedSecret = fastifyPassport.authenticate(
82+
PassportStrategy.AdminSharedSecret,
83+
{ session: false },
84+
) as RouteShorthandHook<preHandlerHookHandler>;
85+
7786
/**
7887
* Pre-handler function that checks if the user meets at least one of the specified access preconditions.
7988
* @param strategies The array of role strategies to check for access.

src/services/auth/plugins/passport/strategies.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,7 @@ export enum PassportStrategy {
1717

1818
//-- From Password --//
1919
Password = 'password',
20+
21+
//-- Shared Secret (machine-to-machine) --//
22+
AdminSharedSecret = 'admin-shared-secret',
2023
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Strategy } from 'passport-custom';
2+
3+
import { Authenticator } from '@fastify/passport';
4+
5+
import { ADMIN_SHARED_SECRET } from '../../../../../utils/config';
6+
import { UnauthorizedMember } from '../../../../../utils/errors';
7+
import { PassportStrategy } from '../strategies';
8+
import type { StrictVerifiedCallback } from '../types';
9+
10+
export default (passport: Authenticator) => {
11+
passport.use(
12+
PassportStrategy.AdminSharedSecret,
13+
new Strategy((req, done: StrictVerifiedCallback) => {
14+
const authHeader = req.headers.authorization;
15+
if (ADMIN_SHARED_SECRET && authHeader === `Bearer ${ADMIN_SHARED_SECRET}`) {
16+
return done(null, {});
17+
}
18+
return done(new UnauthorizedMember(), false);
19+
}),
20+
);
21+
};

src/utils/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ export const LOG_LEVEL: string | undefined = process.env.LOG_LEVEL;
1717
export const APP_VERSION = process.env.APP_VERSION;
1818
export const BUILD_TIMESTAMP = process.env.BUILD_TIMESTAMP;
1919

20+
export const ADMIN_SHARED_SECRET = process.env.ADMIN_SHARED_SECRET;
21+
2022
export const CLIENT_HOST = process.env.CLIENT_HOST ?? 'http://localhost:3114';
2123

2224
export const LIBRARY_HOST = process.env.LIBRARY_CLIENT_HOST ?? CLIENT_HOST;

0 commit comments

Comments
 (0)