@sowell/quasar-app-extension-auth 0.3.6 → 0.3.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.
- package/package.json +4 -2
- package/src/assets/Email-sent.svg +32 -0
- package/src/assets/Illustration-password.svg +79 -0
- package/src/assets/Ok-illustration.svg +13 -0
- package/src/assets/Sowell-logo.svg +4 -0
- package/src/assets/User-not-found.svg +23 -0
- package/src/assets/illustration-login.svg +98 -0
- package/src/boot/router-guards.ts +11 -7
- package/src/components/dialogs/Message.vue +47 -23
- package/src/components/dialogs/SendEmail.vue +8 -5
- package/src/components/dialogs/WebSendEmail.vue +108 -0
- package/src/components/dialogs/sw-info-dialog.vue +87 -0
- package/src/components/pages/Auth.vue +36 -157
- package/src/components/pages/ResetPassword.vue +20 -191
- package/src/components/pages/WebAuth.vue +166 -222
- package/src/components/pages/WebResetPassword.vue +128 -0
- package/src/composables/auth.ts +121 -0
- package/src/composables/resetPassword.ts +219 -0
- package/src/index.js +4 -0
- package/src/injects/index.ts +1 -0
- package/src/injects/prompts.ts +3 -1
- package/src/injects/states.ts +58 -0
- package/src/prompts.js +28 -0
- package/src/routes/index.ts +8 -1
- package/tsconfig.json +0 -1
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
class="full-width q-mb-md"
|
|
41
41
|
>
|
|
42
42
|
<template #prepend>
|
|
43
|
-
<q-icon :name="ionLockClosedOutline" />
|
|
43
|
+
<q-icon :name="icons.ionLockClosedOutline" />
|
|
44
44
|
</template>
|
|
45
45
|
</q-input>
|
|
46
46
|
</div>
|
|
@@ -60,7 +60,10 @@
|
|
|
60
60
|
</q-form>
|
|
61
61
|
</div>
|
|
62
62
|
<q-dialog v-model="passwordUpdated" persistent>
|
|
63
|
-
<sowell-message
|
|
63
|
+
<sowell-message
|
|
64
|
+
:passwordUpdated="passwordUpdated"
|
|
65
|
+
@goToLoginPage="goToLoginPage"
|
|
66
|
+
/>
|
|
64
67
|
</q-dialog>
|
|
65
68
|
</q-page>
|
|
66
69
|
</q-layout>
|
|
@@ -68,210 +71,36 @@
|
|
|
68
71
|
|
|
69
72
|
<script lang="ts">
|
|
70
73
|
//@ts-ignore
|
|
71
|
-
import {
|
|
74
|
+
import { defineComponent } from "vue";
|
|
72
75
|
import SowellMessage from "../dialogs/Message.vue";
|
|
73
|
-
import {
|
|
74
|
-
import { useI18n } from "vue-i18n";
|
|
75
|
-
import { $api, $prompts, $router } from "../../injects";
|
|
76
|
-
import jwt from 'jwt-decode'
|
|
77
|
-
import { Buffer } from 'buffer/' // NOTE: the trailing '/' is intentional and required by buffer
|
|
78
|
-
import {
|
|
79
|
-
ionLockClosedOutline,
|
|
80
|
-
ionCloseOutline,
|
|
81
|
-
ionAlertCircleOutline
|
|
82
|
-
} from "@quasar/extras/ionicons-v5";
|
|
83
|
-
|
|
84
|
-
interface DecodedToken { // FIXME: consider to move to its own file
|
|
85
|
-
sub: number,
|
|
86
|
-
email: string,
|
|
87
|
-
token: string
|
|
88
|
-
}
|
|
76
|
+
import { useResetPassword } from "composables/resetPassword";
|
|
89
77
|
|
|
90
78
|
export default defineComponent({
|
|
91
79
|
name: "ResetPassword",
|
|
92
80
|
components: { SowellMessage },
|
|
93
81
|
setup() {
|
|
94
|
-
const { patch, post } = $api();
|
|
95
82
|
const {
|
|
96
|
-
|
|
97
|
-
|
|
83
|
+
password,
|
|
84
|
+
loading,
|
|
85
|
+
passwordUpdated,
|
|
86
|
+
validations,
|
|
98
87
|
LOCAL_LOGIN_ROUTE,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const loading = ref(false);
|
|
105
|
-
const passwordUpdated = ref(false)
|
|
106
|
-
const { t } = useI18n();
|
|
107
|
-
|
|
108
|
-
const token = ref("")
|
|
109
|
-
|
|
110
|
-
const decodedToken = computed(() => {
|
|
111
|
-
if (!token.value) return null
|
|
112
|
-
return jwt(token.value) as DecodedToken
|
|
113
|
-
}) as Ref<DecodedToken | null>
|
|
114
|
-
|
|
115
|
-
const canSubmit = computed(() => {
|
|
116
|
-
return decodedToken.value !== null && password.value.length >= 6
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const validations = {
|
|
120
|
-
passwordRules: [
|
|
121
|
-
(val: string) => !!val || t("auth.passwordPresenceError"),
|
|
122
|
-
(val: string) => val.length >= 6 || t("auth.passwordLengthError")
|
|
123
|
-
],
|
|
124
|
-
passwordConfirmationRules: [
|
|
125
|
-
(val: string) =>
|
|
126
|
-
val === password.value || t("auth.newPasswordConfirmationFailed"),
|
|
127
|
-
(val: string) => !!val || t("auth.passwordPresenceError"),
|
|
128
|
-
(val: string) => val.length >= 6 || t("auth.passwordLengthError"),
|
|
129
|
-
],
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
const decodeKey = (key: string) => {
|
|
133
|
-
try {
|
|
134
|
-
// remove backslash to avoid decoding error
|
|
135
|
-
key = key.replace(/\\n/g, '')
|
|
136
|
-
const decodedKey = Buffer.from(key, 'base64').toString('utf-8').split(',')
|
|
137
|
-
// split instead of JSON.parse as JSON.parse doesn't work
|
|
138
|
-
|
|
139
|
-
if (decodedKey.length !== 2) {
|
|
140
|
-
throw 'Invalid encoded key'
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const email = decodedKey[0].replace('{', '').split(':')[1]
|
|
144
|
-
const tmpToken = decodedKey[1].replace('}', '').split(':')[1]
|
|
145
|
-
return {
|
|
146
|
-
decoded: true,
|
|
147
|
-
email,
|
|
148
|
-
tmpToken
|
|
149
|
-
}
|
|
150
|
-
} catch (err) {
|
|
151
|
-
console.log('decodeKey err', err)
|
|
152
|
-
return {
|
|
153
|
-
decoded: false
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const onSubmit = () => {
|
|
159
|
-
const updatePasswordPayload = {
|
|
160
|
-
data: {
|
|
161
|
-
type: "users",
|
|
162
|
-
id: decodedToken.value.sub,
|
|
163
|
-
attributes:
|
|
164
|
-
{
|
|
165
|
-
password: password.value
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
const updatePasswordHeaders = {
|
|
170
|
-
headers: {
|
|
171
|
-
'Authorization': `Bearer ${token.value}`
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
patch(
|
|
176
|
-
AUTH_SERVER_UPDATE_PASSWORD_ROUTE.replace(':userId', String(decodedToken.value.sub)),
|
|
177
|
-
updatePasswordPayload,
|
|
178
|
-
updatePasswordHeaders
|
|
179
|
-
).then(() => {
|
|
180
|
-
passwordUpdated.value = true;
|
|
181
|
-
}).catch(() => {
|
|
182
|
-
$q.notify({
|
|
183
|
-
message: t("auth.passwordRecoveryFailed"),
|
|
184
|
-
color: "negative",
|
|
185
|
-
icon:ionAlertCircleOutline,
|
|
186
|
-
position: "top",
|
|
187
|
-
actions: [
|
|
188
|
-
{
|
|
189
|
-
color: "white",
|
|
190
|
-
icon: ionCloseOutline,
|
|
191
|
-
},
|
|
192
|
-
],
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
const goToLoginPage = () => {
|
|
198
|
-
router.push(LOCAL_LOGIN_ROUTE);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
onMounted(() => {
|
|
202
|
-
let key = $route.query.key as string
|
|
203
|
-
const { decoded, email, tmpToken } = decodeKey(key)
|
|
204
|
-
|
|
205
|
-
if (!decoded) {
|
|
206
|
-
return $q.notify({
|
|
207
|
-
message: t("auth.passwordRecoveryInvalidLink"),
|
|
208
|
-
color: "negative",
|
|
209
|
-
position: "top",
|
|
210
|
-
icon: ionAlertCircleOutline,
|
|
211
|
-
actions: [
|
|
212
|
-
{
|
|
213
|
-
color: "white",
|
|
214
|
-
icon: ionCloseOutline,
|
|
215
|
-
},
|
|
216
|
-
],
|
|
217
|
-
})
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const tmpAuthPayload = {
|
|
221
|
-
auth: {
|
|
222
|
-
email: email,
|
|
223
|
-
token: tmpToken
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
post(AUTH_SERVER_SIGNING_ROUTE, tmpAuthPayload)
|
|
228
|
-
.then((response) => {
|
|
229
|
-
token.value = response.data.jwt
|
|
230
|
-
if (!token.value) throw 'Error reading the temporary token'
|
|
231
|
-
})
|
|
232
|
-
.catch((error) => {
|
|
233
|
-
if (error.response) {
|
|
234
|
-
// Request made and server responded
|
|
235
|
-
if (error.response.status === 404) {
|
|
236
|
-
return $q.notify({
|
|
237
|
-
message: t("auth.passwordRecoveryExpiredLink"),
|
|
238
|
-
color: "negative",
|
|
239
|
-
icon: ionAlertCircleOutline,
|
|
240
|
-
position: "top",
|
|
241
|
-
actions: [
|
|
242
|
-
{
|
|
243
|
-
color: "white",
|
|
244
|
-
icon: ionCloseOutline,
|
|
245
|
-
},
|
|
246
|
-
],
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
return $q.notify({
|
|
251
|
-
message: t("auth.passwordRecoveryFailed"),
|
|
252
|
-
color: "negative",
|
|
253
|
-
position: "top",
|
|
254
|
-
icon: ionAlertCircleOutline,
|
|
255
|
-
actions: [
|
|
256
|
-
{
|
|
257
|
-
color: "white",
|
|
258
|
-
icon: ionCloseOutline,
|
|
259
|
-
},
|
|
260
|
-
],
|
|
261
|
-
});
|
|
262
|
-
});
|
|
263
|
-
})
|
|
88
|
+
canSubmit,
|
|
89
|
+
onSubmit,
|
|
90
|
+
goToLoginPage,
|
|
91
|
+
icons,
|
|
92
|
+
} = useResetPassword();
|
|
264
93
|
|
|
265
94
|
return {
|
|
266
95
|
password,
|
|
267
|
-
validations,
|
|
268
96
|
loading,
|
|
269
|
-
onSubmit,
|
|
270
97
|
canSubmit,
|
|
271
98
|
passwordUpdated,
|
|
272
99
|
LOCAL_LOGIN_ROUTE,
|
|
273
|
-
|
|
274
|
-
|
|
100
|
+
validations,
|
|
101
|
+
onSubmit,
|
|
102
|
+
goToLoginPage,
|
|
103
|
+
icons
|
|
275
104
|
};
|
|
276
105
|
},
|
|
277
106
|
});
|