@punch-in/strapi-admin 1.2.13 → 1.2.15

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.
@@ -1,7 +1,7 @@
1
1
  import styled from 'styled-components';
2
2
 
3
3
  const LeftMenuListLink = styled.div`
4
- height: 300px;
4
+ max-height: 300px;
5
5
  margin-bottom: 19px;
6
6
  overflow-y: hidden;
7
7
  width: 22rem;
@@ -1,5 +1,5 @@
1
1
  import React, { useReducer, useEffect } from 'react';
2
- import { Checkbox, Button, Flex, Padded, Separator } from '@punch-in/buffet-modern-core';
2
+ import { Checkbox, Button, Flex } from '@punch-in/buffet-modern-core';
3
3
  import { LoadingIndicator } from '@punch-in/buffet-modern-styles';
4
4
  import { useIntl } from 'react-intl';
5
5
  import { get } from 'lodash';
@@ -99,31 +99,33 @@ const Login = ({ children, formErrors, modifiedData, onChange, onSubmit, request
99
99
  </form>
100
100
  {children}
101
101
  </Box>
102
- {/* SSO Providers Section */}
103
- {!isLoading && providers.length > 0 && (
104
- <>
105
- <Separator />
106
- <Padded top bottom size="smd">
107
- <BaselineAlignment top size="3px" />
108
- </Padded>
109
- <div style={{
110
- background: '#d2e9fe',
111
- padding: '1.4rem',
112
- boxShadow: 'rgb(221, 221, 221) 12px 12px 9px 0px' }}>
113
- <Flex flexWrap="wrap" justifyContent="center" alignItems="center">
114
- <div>{formatMessage({ id: 'Auth.components.sso.info' })}: </div>
115
- {providers.map(provider => (
116
- <div key={provider.uid} style={{ padding: '5px 4px' }}>
117
- <ProviderButton provider={provider} />
118
- </div>
119
- ))}
120
- </Flex>
121
- </div>
122
- </>
123
- )}
124
102
  </BaselineAlignment>
125
103
  </Section>
104
+ {/* Forgot password link, directly below the login form */}
126
105
  <AuthLink label="Auth.link.forgot-password" to="/auth/forgot-password" />
106
+ {/* SSO Providers Section - pinned to the bottom of the viewport */}
107
+ {!isLoading && providers.length > 0 && (
108
+ <div
109
+ style={{
110
+ position: 'fixed',
111
+ left: 0,
112
+ right: 0,
113
+ bottom: 0,
114
+ background: '#d2e9fe',
115
+ padding: '1.4rem',
116
+ boxShadow: 'rgb(221, 221, 221) 0px -6px 9px 0px',
117
+ }}
118
+ >
119
+ <Flex flexWrap="wrap" justifyContent="center" alignItems="center">
120
+ <div>{formatMessage({ id: 'Auth.components.sso.info' })}: </div>
121
+ {providers.map(provider => (
122
+ <div key={provider.uid} style={{ padding: '5px 4px' }}>
123
+ <ProviderButton provider={provider} />
124
+ </div>
125
+ ))}
126
+ </Flex>
127
+ </div>
128
+ )}
127
129
  </>
128
130
  );
129
131
  };
@@ -167,7 +167,10 @@ module.exports = {
167
167
  return ctx.badRequest('ValidationError', err);
168
168
  }
169
169
 
170
- strapi.admin.services.auth.forgotPassword(input);
170
+ // Awaited: in Lambda, un-awaited async work is frozen once the response
171
+ // returns, so the email send (SES invoke) would often never run. Still
172
+ // 204 whether or not the address matched an account - no existence leak.
173
+ await strapi.admin.services.auth.forgotPassword(input);
171
174
 
172
175
  ctx.status = 204;
173
176
  },
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.13"
142
+ "version": "1.2.15"
143
143
  }
package/services/auth.js CHANGED
@@ -3,6 +3,12 @@
3
3
  const bcrypt = require('bcryptjs');
4
4
  const _ = require('lodash');
5
5
  const { getAbsoluteAdminUrl } = require('strapi-utils');
6
+ const { LambdaClient, InvokeCommand } = require('@aws-sdk/client-lambda');
7
+
8
+ // SDK v3 client-lambda is preinstalled by the Node.js 18+ Lambda managed
9
+ // runtime, so it does not need to be bundled in the strapi-lambda layer.
10
+ // See controllers/authentication.js for the same pattern (SSO providers).
11
+ const lambdaClient = new LambdaClient({});
6
12
 
7
13
  /**
8
14
  * hashes a password
@@ -77,10 +83,26 @@ const forgotPassword = async ({ email } = {}) => {
77
83
  const resetPasswordToken = strapi.admin.services.token.createToken();
78
84
  await strapi.admin.services.user.updateById(user.id, { resetPasswordToken });
79
85
 
80
- // Send an email to the admin.
81
- const url = `${getAbsoluteAdminUrl(
82
- strapi.config
86
+ // getAbsoluteAdminUrl now resolves to the tenant's real admin SPA origin
87
+ // (ADMIN_URL in prod-stack-*.yaml), not localhost.
88
+ const url = `${_.trimEnd(
89
+ getAbsoluteAdminUrl(strapi.config),
90
+ '/'
83
91
  )}/auth/reset-password?code=${resetPasswordToken}`;
92
+
93
+ // ADMIN_EMAIL_MODE=invoke: this Lambda's VPC has no internet route, so the
94
+ // email is sent by the central AdminEmailFunction, reached via a direct SDK
95
+ // invoke (features/API-REDESIGN.md). Anything else keeps the old
96
+ // strapi-plugin-email path for local/dev.
97
+ if (process.env.ADMIN_EMAIL_MODE === 'invoke') {
98
+ return sendAdminEmailViaInvoke({
99
+ kind: 'forgot-password',
100
+ to: user.email,
101
+ firstname: user.firstname,
102
+ url,
103
+ });
104
+ }
105
+
84
106
  return strapi.plugins.email.services.email
85
107
  .sendTemplatedEmail(
86
108
  {
@@ -100,6 +122,42 @@ const forgotPassword = async ({ email } = {}) => {
100
122
  });
101
123
  };
102
124
 
125
+ // Invokes stripe-charge's AdminEmailFunction (see features/API-REDESIGN.md).
126
+ // Errors are logged, never surfaced to the caller - a forgot-password request
127
+ // returns 204 whether or not the email actually went out.
128
+ const sendAdminEmailViaInvoke = async payload => {
129
+ const functionName = process.env.ADMIN_EMAIL_FUNCTION_NAME;
130
+ if (!functionName) {
131
+ strapi.log.error('ADMIN_EMAIL_FUNCTION_NAME is not configured');
132
+ return;
133
+ }
134
+
135
+ try {
136
+ const response = await lambdaClient.send(
137
+ new InvokeCommand({
138
+ FunctionName: functionName,
139
+ InvocationType: 'RequestResponse',
140
+ Payload: Buffer.from(JSON.stringify(payload)),
141
+ })
142
+ );
143
+
144
+ if (response.FunctionError) {
145
+ throw new Error(
146
+ `AdminEmailFunction returned ${response.FunctionError}: ${Buffer.from(
147
+ response.Payload
148
+ ).toString('utf8')}`
149
+ );
150
+ }
151
+
152
+ const result = JSON.parse(Buffer.from(response.Payload).toString('utf8'));
153
+ if (!result.ok) {
154
+ strapi.log.error(`AdminEmailFunction rejected request: ${result.error}`);
155
+ }
156
+ } catch (err) {
157
+ strapi.log.error(`Failed to invoke AdminEmailFunction: ${err.message}`);
158
+ }
159
+ };
160
+
103
161
  /**
104
162
  * Reset a user password
105
163
  * @param {Object} param params