@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
@@ -139,5 +139,5 @@
139
139
  "develop:ce": "STRAPI_DISABLE_EE=true webpack-dev-server --config webpack.config.dev.js",
140
140
  "test": "echo \"no tests yet\""
141
141
  },
142
- "version": "1.2.7"
142
+ "version": "1.2.9"
143
143
  }