@punch-in/strapi-admin 1.2.7 → 1.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,6 +4,16 @@ const passport = require('koa-passport');
|
|
|
4
4
|
const compose = require('koa-compose');
|
|
5
5
|
const crypto = require('crypto');
|
|
6
6
|
const axios = require('axios');
|
|
7
|
+
const { LambdaClient, InvokeCommand } = require('@aws-sdk/client-lambda');
|
|
8
|
+
|
|
9
|
+
// Tenant Lambdas run inside a VPC with no internet route (required for the
|
|
10
|
+
// EFS mount - see CLAUDE.md). Reaching the central stripe-charge Lambda
|
|
11
|
+
// therefore goes through the VPC Interface Endpoint for the Lambda service
|
|
12
|
+
// (infra/shared-networking-stack.yaml) via a direct SDK invoke, not HTTPS.
|
|
13
|
+
// See features/API-REDESIGN.md Phase 1. The SDK v3 client-lambda package is
|
|
14
|
+
// preinstalled by the Node.js 18+ Lambda managed runtime, so it does not
|
|
15
|
+
// need to be bundled in strapi-lambda-layer.
|
|
16
|
+
const lambdaClient = new LambdaClient({});
|
|
7
17
|
|
|
8
18
|
const {
|
|
9
19
|
validateRegistrationInput,
|
|
@@ -190,6 +200,14 @@ module.exports = {
|
|
|
190
200
|
// against *this* tenant's admin_users - never creating one.
|
|
191
201
|
|
|
192
202
|
async ssoProviders(ctx) {
|
|
203
|
+
// SSO_PROVIDERS_MODE=invoke is the new path (see features/API-REDESIGN.md
|
|
204
|
+
// Phase 1); anything else keeps the old HTTPS call so this can be rolled
|
|
205
|
+
// back per-tenant without a redeploy while the invoke path is verified.
|
|
206
|
+
if (process.env.SSO_PROVIDERS_MODE === 'invoke') {
|
|
207
|
+
ctx.body = await fetchSsoProvidersViaInvoke();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
193
211
|
try {
|
|
194
212
|
const { data } = await axios.get(`${getCentralApiBase()}/sso/auth/providers`, {
|
|
195
213
|
timeout: 5000,
|
|
@@ -221,6 +239,14 @@ module.exports = {
|
|
|
221
239
|
// time compare). Read-only: an unmatched or inactive email is rejected,
|
|
222
240
|
// never used to create or activate an admin account.
|
|
223
241
|
async ssoVerify(ctx) {
|
|
242
|
+
// TEMPORARY diagnostic - ssoVerify is returning a bare 403 "Forbidden"
|
|
243
|
+
// (matching isAuthenticatedAdmin's unmessaged strapi.errors.forbidden())
|
|
244
|
+
// in production on every tenant tested, even with a correct X-Sync-Secret,
|
|
245
|
+
// despite this route's routes.json entry having no policies that could
|
|
246
|
+
// produce that. This line proves whether the request even reaches this
|
|
247
|
+
// controller at all - remove once root-caused.
|
|
248
|
+
console.log('[ssoVerify] reached controller, headers:', JSON.stringify(ctx.request.header));
|
|
249
|
+
|
|
224
250
|
const expected = process.env.SYNC_SECRET;
|
|
225
251
|
if (!expected) {
|
|
226
252
|
return ctx.internalServerError('SYNC_SECRET is not configured on this Strapi instance');
|
|
@@ -252,6 +278,38 @@ function getCentralApiBase() {
|
|
|
252
278
|
return (process.env.PUNCHIN_INTEGRATIONS_API_BASE || 'https://api.punch-in.co.uk').replace(/\/$/, '');
|
|
253
279
|
}
|
|
254
280
|
|
|
281
|
+
// SsoProvidersFunction (stripe-charge/template.yaml) is also wired behind
|
|
282
|
+
// API Gateway via sso.js, so its handler returns an API-Gateway-proxy-shaped
|
|
283
|
+
// object ({ statusCode, headers, body: JSON.stringify(...) }) rather than
|
|
284
|
+
// the raw provider array - that shape is unchanged whether API Gateway or a
|
|
285
|
+
// direct InvokeCommand calls it, so it has to be unwrapped here.
|
|
286
|
+
async function fetchSsoProvidersViaInvoke() {
|
|
287
|
+
const functionName = process.env.SSO_PROVIDERS_FUNCTION_NAME;
|
|
288
|
+
if (!functionName) {
|
|
289
|
+
strapi.log.error('SSO_PROVIDERS_FUNCTION_NAME is not configured');
|
|
290
|
+
return [];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
try {
|
|
294
|
+
const response = await lambdaClient.send(
|
|
295
|
+
new InvokeCommand({
|
|
296
|
+
FunctionName: functionName,
|
|
297
|
+
InvocationType: 'RequestResponse',
|
|
298
|
+
})
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
if (response.FunctionError) {
|
|
302
|
+
throw new Error(`SsoProvidersFunction returned ${response.FunctionError}`);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const gatewayResponse = JSON.parse(Buffer.from(response.Payload).toString('utf8'));
|
|
306
|
+
return JSON.parse(gatewayResponse.body);
|
|
307
|
+
} catch (err) {
|
|
308
|
+
strapi.log.error(`Failed to invoke SsoProvidersFunction: ${err.message}`);
|
|
309
|
+
return [];
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
255
313
|
function secretsMatch(provided, expected) {
|
|
256
314
|
if (!provided || !expected) return false;
|
|
257
315
|
const a = Buffer.from(provided);
|
package/package.json
CHANGED