@sowell/quasar-app-extension-auth 1.7.0 → 1.7.1
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.
package/package.json
CHANGED
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
margin: 12px 0;
|
|
94
94
|
text-decoration: underline;
|
|
95
95
|
"
|
|
96
|
-
@click="
|
|
96
|
+
@click="forgottenPassword = true"
|
|
97
97
|
data-testid="ask-password-change-btn"
|
|
98
98
|
data-cy="forgot-password">
|
|
99
99
|
{{ $t("auth.forgottenPassword") }}
|
|
@@ -247,8 +247,7 @@ export default defineComponent({
|
|
|
247
247
|
retypeEmail,
|
|
248
248
|
isSubmitBtnDisabled,
|
|
249
249
|
goToOtpValidation,
|
|
250
|
-
goToFirstLogin
|
|
251
|
-
goToForgotPassword
|
|
250
|
+
goToFirstLogin
|
|
252
251
|
} = useAuth()
|
|
253
252
|
|
|
254
253
|
const { localStorage } = useQuasar()
|
|
@@ -336,8 +335,7 @@ export default defineComponent({
|
|
|
336
335
|
handleSubmit,
|
|
337
336
|
resetPassword,
|
|
338
337
|
goToPrivacyPolicy,
|
|
339
|
-
goToFirstLogin
|
|
340
|
-
goToForgotPassword
|
|
338
|
+
goToFirstLogin
|
|
341
339
|
}
|
|
342
340
|
}
|
|
343
341
|
})
|
|
@@ -151,8 +151,7 @@
|
|
|
151
151
|
:loading="loading"
|
|
152
152
|
type="submit"
|
|
153
153
|
class="full-width q-mt-lg submit-button"
|
|
154
|
-
:class="{ 'submit-button--soft':
|
|
155
|
-
:disable="mode === 'otp' ? !canSubmit : false">
|
|
154
|
+
:class="{ 'submit-button--soft': !canSubmit }">
|
|
156
155
|
<q-icon name="lock_open" size="16px" class="q-mr-sm" />
|
|
157
156
|
{{ $t("common.saveNewPassword") }}
|
|
158
157
|
</q-btn>
|
|
@@ -420,18 +419,23 @@ export default defineComponent({
|
|
|
420
419
|
border-radius: 8px;
|
|
421
420
|
padding: 16px;
|
|
422
421
|
display: grid;
|
|
423
|
-
grid-template-columns: repeat(2, 1fr);
|
|
422
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
424
423
|
gap: 10px 16px;
|
|
425
424
|
}
|
|
426
425
|
|
|
427
426
|
.requirement-item {
|
|
428
427
|
display: flex;
|
|
429
428
|
align-items: center;
|
|
429
|
+
min-width: 0;
|
|
430
430
|
font-size: 12px;
|
|
431
431
|
font-weight: 500;
|
|
432
432
|
color: #3e484f;
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
+
.requirement-item span {
|
|
436
|
+
overflow-wrap: anywhere;
|
|
437
|
+
}
|
|
438
|
+
|
|
435
439
|
.requirement-item .q-icon {
|
|
436
440
|
color: #bdc8d1;
|
|
437
441
|
}
|
package/src/composables/auth.ts
CHANGED
|
@@ -61,10 +61,6 @@ export function useAuth() {
|
|
|
61
61
|
push(`${LOCAL_FIRST_LOGIN_ROUTE || "/first-login"}?context=activate`)
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
const goToForgotPassword = () => {
|
|
65
|
-
push(LOCAL_FIRST_LOGIN_ROUTE || "/first-login")
|
|
66
|
-
}
|
|
67
|
-
|
|
68
64
|
const email = ref("")
|
|
69
65
|
const password = ref("")
|
|
70
66
|
const msalToken = ref("")
|
|
@@ -285,7 +281,6 @@ export function useAuth() {
|
|
|
285
281
|
msalAuth,
|
|
286
282
|
goToOtpValidation,
|
|
287
283
|
goToFirstLogin,
|
|
288
|
-
goToForgotPassword,
|
|
289
284
|
onSubmit,
|
|
290
285
|
retypeEmail,
|
|
291
286
|
isSubmitBtnDisabled,
|
|
@@ -34,6 +34,7 @@ export function useResetPassword() {
|
|
|
34
34
|
}
|
|
35
35
|
type ValidatableInput = { resetValidation: () => void }
|
|
36
36
|
const confirmPasswordInput = ref<ValidatableInput | null>(null)
|
|
37
|
+
const highlightInvalidRequirements = ref(false)
|
|
37
38
|
|
|
38
39
|
const { patch, post } = $api()
|
|
39
40
|
const router = $router()
|
|
@@ -71,19 +72,36 @@ export function useResetPassword() {
|
|
|
71
72
|
hasSpecialChar.value
|
|
72
73
|
)
|
|
73
74
|
|
|
74
|
-
// NOTE: `invalid` always false here (highlight-on-invalid-submit is a magiclink-only
|
|
75
|
-
// affordance, see useValidateMagicLink) - kept on every item so ResetPassword.vue can
|
|
76
|
-
// bind the same class regardless of which composable (OTP vs magiclink) it's using.
|
|
77
75
|
const passwordRequirements = computed(() => [
|
|
78
|
-
{
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
{
|
|
77
|
+
label: t("auth.passwordRequirement.minLength"),
|
|
78
|
+
valid: hasMinLength.value,
|
|
79
|
+
invalid: highlightInvalidRequirements.value && !hasMinLength.value
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
label: t("auth.passwordRequirement.uppercase"),
|
|
83
|
+
valid: hasUppercase.value,
|
|
84
|
+
invalid: highlightInvalidRequirements.value && !hasUppercase.value
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
label: t("auth.passwordRequirement.lowercase"),
|
|
88
|
+
valid: hasLowercase.value,
|
|
89
|
+
invalid: highlightInvalidRequirements.value && !hasLowercase.value
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
label: t("auth.passwordRequirement.number"),
|
|
93
|
+
valid: hasNumber.value,
|
|
94
|
+
invalid: highlightInvalidRequirements.value && !hasNumber.value
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
label: t("auth.passwordRequirement.letter"),
|
|
98
|
+
valid: hasLetter.value,
|
|
99
|
+
invalid: highlightInvalidRequirements.value && !hasLetter.value
|
|
100
|
+
},
|
|
83
101
|
{
|
|
84
102
|
label: t("auth.passwordRequirement.specialChar"),
|
|
85
103
|
valid: hasSpecialChar.value,
|
|
86
|
-
invalid:
|
|
104
|
+
invalid: highlightInvalidRequirements.value && !hasSpecialChar.value
|
|
87
105
|
}
|
|
88
106
|
])
|
|
89
107
|
|
|
@@ -162,6 +180,11 @@ export function useResetPassword() {
|
|
|
162
180
|
}
|
|
163
181
|
|
|
164
182
|
const onSubmit = () => {
|
|
183
|
+
if (!canSubmit.value) {
|
|
184
|
+
highlightInvalidRequirements.value = true
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
|
|
165
188
|
let idUser = decodedToken?.value?.sub
|
|
166
189
|
if (isOtp.value && userInfos?.uid) {
|
|
167
190
|
idUser = userInfos?.uid
|
|
@@ -233,14 +256,16 @@ export function useResetPassword() {
|
|
|
233
256
|
router.push(LOCAL_LOGIN_ROUTE)
|
|
234
257
|
}
|
|
235
258
|
|
|
236
|
-
// NOTE: OTP flow never expires this way /
|
|
237
|
-
//
|
|
238
|
-
//
|
|
259
|
+
// NOTE: OTP flow never expires this way / has nowhere to send the user back to
|
|
260
|
+
// "first login" - these are inert magiclink-only affordances, kept here only so
|
|
261
|
+
// ResetPassword.vue has a uniform shape regardless of composable used.
|
|
239
262
|
const linkExpired = ref(false)
|
|
240
263
|
const serverError = ref("")
|
|
241
|
-
const highlightInvalidRequirements = ref(false)
|
|
242
264
|
const goToFirstLogin = goToLoginPage
|
|
243
|
-
|
|
265
|
+
|
|
266
|
+
const handleInvalidSubmit = () => {
|
|
267
|
+
highlightInvalidRequirements.value = true
|
|
268
|
+
}
|
|
244
269
|
|
|
245
270
|
onMounted(() => {
|
|
246
271
|
if (!isOtp.value) {
|
|
@@ -21,7 +21,8 @@ export function useMagicLink() {
|
|
|
21
21
|
const {
|
|
22
22
|
AUTH_SERVER_REQUEST_MAGICLINK_ROUTE,
|
|
23
23
|
LOCAL_SET_PASSWORD_ROUTE,
|
|
24
|
-
LOCAL_LOGIN_ROUTE
|
|
24
|
+
LOCAL_LOGIN_ROUTE,
|
|
25
|
+
APP_SERVER_BASE_URL
|
|
25
26
|
} = $prompts()
|
|
26
27
|
|
|
27
28
|
const email = ref("")
|
|
@@ -61,16 +62,13 @@ export function useMagicLink() {
|
|
|
61
62
|
return true
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
// Built from the configured APP_SERVER_BASE_URL (fixed per app in
|
|
66
|
+
// quasar.extensions.json), never from window.location: in a Capacitor build
|
|
67
|
+
// (APK/IPA) the WebView origin is something like capacitor://localhost, not the
|
|
68
|
+
// app's real public domain, so the magic link would otherwise be unusable once
|
|
69
|
+
// installed as a native app.
|
|
64
70
|
const buildBaseUrl = (): string => {
|
|
65
|
-
|
|
66
|
-
// DEV-ONLY BYPASS: MAGICLINK_ALLOWED_HOSTS rejects a bare "localhost" base_url
|
|
67
|
-
// (422). Substitute localhost.sowell.app (port kept) so the link is accepted -
|
|
68
|
-
// requires the local DNS to resolve localhost.sowell.app -> 127.0.0.1.
|
|
69
|
-
// Never let this reach production (see playbook piège #2).
|
|
70
|
-
const { protocol, hostname, port } = window.location
|
|
71
|
-
const effectiveHostname = hostname === "localhost" ? "localhost.sowell.app" : hostname
|
|
72
|
-
const origin = `${protocol}//${effectiveHostname}${port ? `:${port}` : ""}`
|
|
73
|
-
return `${origin}${LOCAL_SET_PASSWORD_ROUTE || "/set-password"}`
|
|
71
|
+
return `${APP_SERVER_BASE_URL}${LOCAL_SET_PASSWORD_ROUTE || "/set-password"}`
|
|
74
72
|
}
|
|
75
73
|
|
|
76
74
|
const readApiError = (error: unknown): string | undefined => {
|