@sowell/quasar-app-extension-auth 1.0.1 → 1.1.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 +3 -1
- package/src/boot/axios.ts +0 -1
- package/src/boot/register.ts +0 -1
- package/src/boot/router.ts +0 -1
- package/src/boot/store.ts +0 -1
- package/src/components/pages/AdminAuth.vue +0 -2
- package/src/components/pages/Auth.vue +0 -6
- package/src/components/pages/AuthReporter.vue +0 -4
- package/src/components/pages/OtpValidation.vue +0 -2
- package/src/components/pages/ResetPassword.vue +0 -2
- package/src/components/pages/WebAuth.vue +42 -43
- package/src/composables/auth.ts +22 -13
- package/src/routes/index.ts +0 -4
- package/src/utils/encryption.ts +9 -0
- package/src/utils/index.ts +1 -0
- package/tsconfig.json +4 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sowell/quasar-app-extension-auth",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "A Quasar app extension to manage Authentication",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"repository": "https://github.com/sowell-ai/quasar.extension.auth",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"yarn": ">= 1.6.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
+
"@quasar/app-webpack": "^4.0.0-beta.16",
|
|
24
25
|
"@quasar/cli": "^2.2.3",
|
|
25
26
|
"@types/node": "^16.9.1",
|
|
26
27
|
"@types/validator": "^13.6.3",
|
|
@@ -42,6 +43,7 @@
|
|
|
42
43
|
"@quasar/extras": "^1.15.2",
|
|
43
44
|
"axios": "^0.21.1",
|
|
44
45
|
"buffer": "^6.0.3",
|
|
46
|
+
"crypto-js": "^4.2.0",
|
|
45
47
|
"pinia": "^2.0.12",
|
|
46
48
|
"qs": "^6.10.1",
|
|
47
49
|
"validator": "^13.6.0",
|
package/src/boot/axios.ts
CHANGED
package/src/boot/register.ts
CHANGED
package/src/boot/router.ts
CHANGED
package/src/boot/store.ts
CHANGED
|
@@ -119,8 +119,6 @@
|
|
|
119
119
|
</template>
|
|
120
120
|
|
|
121
121
|
<script lang="ts">
|
|
122
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
123
|
-
//@ts-ignore
|
|
124
122
|
import { defineComponent, ref, computed } from "vue"
|
|
125
123
|
import { useI18n } from "vue-i18n"
|
|
126
124
|
import isEmail from "validator/es/lib/isEmail"
|
|
@@ -154,17 +154,11 @@
|
|
|
154
154
|
</template>
|
|
155
155
|
|
|
156
156
|
<script lang="ts">
|
|
157
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
158
|
-
//@ts-ignore
|
|
159
157
|
import { defineComponent, reactive, onMounted } from "vue"
|
|
160
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
161
|
-
//@ts-ignore
|
|
162
158
|
import * as packageInfo from "app/package.json"
|
|
163
159
|
|
|
164
160
|
import SendEmail from "../dialogs/SendEmail.vue"
|
|
165
161
|
import SowellMessage from "../dialogs/Message.vue"
|
|
166
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
167
|
-
//@ts-ignore
|
|
168
162
|
import MicrosoftLogo from "../../assets/logo-microsoft.svg"
|
|
169
163
|
|
|
170
164
|
import { useAuth } from "composables/auth"
|
|
@@ -159,11 +159,7 @@
|
|
|
159
159
|
</template>
|
|
160
160
|
|
|
161
161
|
<script lang="ts">
|
|
162
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
163
|
-
//@ts-ignore
|
|
164
162
|
import { defineComponent, reactive, onMounted, computed } from "vue"
|
|
165
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
166
|
-
//@ts-ignore
|
|
167
163
|
import * as packageInfo from "app/package.json"
|
|
168
164
|
import SendEmail from "../dialogs/SendEmail.vue"
|
|
169
165
|
import SowellMessage from "../dialogs/Message.vue"
|
|
@@ -77,8 +77,6 @@
|
|
|
77
77
|
</template>
|
|
78
78
|
|
|
79
79
|
<script lang="ts">
|
|
80
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
81
|
-
//@ts-ignore
|
|
82
80
|
import { defineComponent } from "vue"
|
|
83
81
|
import SowellMessage from "../dialogs/Message.vue"
|
|
84
82
|
import { useResetPassword } from "composables/resetPassword"
|
|
@@ -22,24 +22,21 @@
|
|
|
22
22
|
:icon="`img:${MicrosoftLogo}`"
|
|
23
23
|
class="full-width q-mt-lg"
|
|
24
24
|
@click="msalAuth"
|
|
25
|
-
outline
|
|
26
|
-
/>
|
|
25
|
+
outline />
|
|
27
26
|
<div
|
|
28
27
|
style="
|
|
29
28
|
display: flex;
|
|
30
29
|
justify-content: center;
|
|
31
30
|
align-items: center;
|
|
32
31
|
margin-top: 16px;
|
|
33
|
-
"
|
|
34
|
-
>
|
|
32
|
+
">
|
|
35
33
|
<div
|
|
36
34
|
style="
|
|
37
35
|
width: 20%;
|
|
38
36
|
border: 1px solid #bcc3c7;
|
|
39
37
|
height: 1px;
|
|
40
38
|
margin-right: 16px;
|
|
41
|
-
"
|
|
42
|
-
></div>
|
|
39
|
+
"></div>
|
|
43
40
|
<div class="text-weight-bold">{{ $t("common.or") }}</div>
|
|
44
41
|
<div
|
|
45
42
|
style="
|
|
@@ -47,8 +44,7 @@
|
|
|
47
44
|
border: 1px solid #bcc3c7;
|
|
48
45
|
height: 1px;
|
|
49
46
|
margin-left: 16px;
|
|
50
|
-
"
|
|
51
|
-
></div>
|
|
47
|
+
"></div>
|
|
52
48
|
</div>
|
|
53
49
|
</div>
|
|
54
50
|
<q-form @submit="handleSubmit">
|
|
@@ -64,8 +60,7 @@
|
|
|
64
60
|
data-cy="email"
|
|
65
61
|
dense
|
|
66
62
|
outlined
|
|
67
|
-
input-class="text-subtitle2 text-weight-medium"
|
|
68
|
-
/>
|
|
63
|
+
input-class="text-subtitle2 text-weight-medium" />
|
|
69
64
|
<div class="q-ml-xs q-mb-xs text-subtitle2 text-weight-bold">
|
|
70
65
|
{{ $t("auth.password") }}
|
|
71
66
|
</div>
|
|
@@ -77,16 +72,14 @@
|
|
|
77
72
|
lazy-rules
|
|
78
73
|
dense
|
|
79
74
|
outlined
|
|
80
|
-
input-class="text-subtitle2 text-weight-bold"
|
|
81
|
-
>
|
|
75
|
+
input-class="text-subtitle2 text-weight-bold">
|
|
82
76
|
<template #append>
|
|
83
77
|
<q-icon
|
|
84
78
|
:name="
|
|
85
79
|
showPassword ? icons.ionEyeOffSharp : icons.ionEyeSharp
|
|
86
80
|
"
|
|
87
81
|
class="cursor-pointer q-mr-sm lightenDark"
|
|
88
|
-
@click="showPassword = !showPassword"
|
|
89
|
-
/>
|
|
82
|
+
@click="showPassword = !showPassword" />
|
|
90
83
|
</template>
|
|
91
84
|
</q-input>
|
|
92
85
|
</div>
|
|
@@ -101,14 +94,12 @@
|
|
|
101
94
|
:loading="loading"
|
|
102
95
|
type="submit"
|
|
103
96
|
:disable="isSubmitBtnDisabled() || loading || msalLoading"
|
|
104
|
-
class="submitBtn text-subtitle2 text-weight-bold"
|
|
105
|
-
/>
|
|
97
|
+
class="submitBtn text-subtitle2 text-weight-bold" />
|
|
106
98
|
<div
|
|
107
99
|
class="cursor-pointer text-primary text-subtitle2"
|
|
108
100
|
data-testid="ask-password-change-btn"
|
|
109
101
|
data-cy="forgot-password"
|
|
110
|
-
@click="forgottenPassword = true"
|
|
111
|
-
>
|
|
102
|
+
@click="forgottenPassword = true">
|
|
112
103
|
{{ $t("auth.forgottenPassword") }}
|
|
113
104
|
</div>
|
|
114
105
|
</div>
|
|
@@ -119,18 +110,15 @@
|
|
|
119
110
|
<div
|
|
120
111
|
class="column col justify-center content-center mobile"
|
|
121
112
|
:style="IS_MANAGER ? 'background: #eef8fd' : ''"
|
|
122
|
-
:class="!IS_MANAGER ? 'bgBlue' : ''"
|
|
123
|
-
>
|
|
113
|
+
:class="!IS_MANAGER ? 'bgBlue' : ''">
|
|
124
114
|
<img
|
|
125
115
|
v-if="IS_MANAGER"
|
|
126
116
|
src="../../assets/illustration-login.svg"
|
|
127
|
-
class="q-pl-md q-pr-md logoWhite"
|
|
128
|
-
/>
|
|
117
|
+
class="q-pl-md q-pr-md logoWhite" />
|
|
129
118
|
<img
|
|
130
119
|
v-else
|
|
131
120
|
src="../../assets/SowellWhite.svg"
|
|
132
|
-
class="q-pl-md q-pr-md logoWhite"
|
|
133
|
-
/>
|
|
121
|
+
class="q-pl-md q-pr-md logoWhite" />
|
|
134
122
|
</div>
|
|
135
123
|
</div>
|
|
136
124
|
<div>
|
|
@@ -141,9 +129,10 @@
|
|
|
141
129
|
transition-show="fade"
|
|
142
130
|
transition-hide="fade"
|
|
143
131
|
persistent
|
|
144
|
-
data-testid="ask-password-change-modal"
|
|
145
|
-
|
|
146
|
-
|
|
132
|
+
data-testid="ask-password-change-modal">
|
|
133
|
+
<web-send-email
|
|
134
|
+
@resetPassword="resetPassword"
|
|
135
|
+
@close="() => (forgottenPassword = false)" />
|
|
147
136
|
</q-dialog>
|
|
148
137
|
<q-dialog v-model="isNotification" persistent>
|
|
149
138
|
<sw-info-dialog
|
|
@@ -151,8 +140,7 @@
|
|
|
151
140
|
:content="infoDialog.content"
|
|
152
141
|
:image="infoDialog.image"
|
|
153
142
|
:isOtp="isOtp"
|
|
154
|
-
@close="() => isNotification = false"
|
|
155
|
-
>
|
|
143
|
+
@close="() => (isNotification = false)">
|
|
156
144
|
<q-btn
|
|
157
145
|
:data-testid="infoDialog.canGoNext ? 'next-btn' : 'close-btn'"
|
|
158
146
|
v-if="isOtp"
|
|
@@ -163,8 +151,7 @@
|
|
|
163
151
|
:label="infoDialog.canGoNext ? $t('auth.next') : $t('auth.close')"
|
|
164
152
|
color="primary"
|
|
165
153
|
@click="handleInfoDialog"
|
|
166
|
-
v-close-popup
|
|
167
|
-
/>
|
|
154
|
+
v-close-popup />
|
|
168
155
|
</sw-info-dialog>
|
|
169
156
|
</q-dialog>
|
|
170
157
|
</div>
|
|
@@ -181,6 +168,7 @@ import WebSendEmail from "../dialogs/WebSendEmail.vue"
|
|
|
181
168
|
|
|
182
169
|
import { useAuth } from "composables/auth"
|
|
183
170
|
import MicrosoftLogo from "../../assets/logo-microsoft.svg"
|
|
171
|
+
import { AxiosError } from "axios"
|
|
184
172
|
|
|
185
173
|
export default defineComponent({
|
|
186
174
|
name: "Auth",
|
|
@@ -212,9 +200,12 @@ export default defineComponent({
|
|
|
212
200
|
msalAuth
|
|
213
201
|
} = useAuth()
|
|
214
202
|
|
|
215
|
-
const IS_MANAGER = [
|
|
216
|
-
|
|
217
|
-
|
|
203
|
+
const IS_MANAGER = [
|
|
204
|
+
"manager",
|
|
205
|
+
"clean_manager",
|
|
206
|
+
"incivility_manager",
|
|
207
|
+
"admin"
|
|
208
|
+
].includes(X_REQUESTED_ROLES)
|
|
218
209
|
const isNotification = ref(false)
|
|
219
210
|
const infoDialog = ref({
|
|
220
211
|
title: "",
|
|
@@ -237,7 +228,7 @@ export default defineComponent({
|
|
|
237
228
|
const data = {
|
|
238
229
|
auth: {
|
|
239
230
|
email,
|
|
240
|
-
base: APP_SERVER_BASE_URL
|
|
231
|
+
base: APP_SERVER_BASE_URL
|
|
241
232
|
}
|
|
242
233
|
}
|
|
243
234
|
try {
|
|
@@ -255,14 +246,22 @@ export default defineComponent({
|
|
|
255
246
|
forgottenPassword.value = false
|
|
256
247
|
isNotification.value = true
|
|
257
248
|
})
|
|
258
|
-
} catch {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
249
|
+
} catch (error) {
|
|
250
|
+
if ((error as AxiosError).response?.status === 403) {
|
|
251
|
+
// NOTE: 403 is returned when the user is not allowed to reset the password
|
|
252
|
+
infoDialog.value = {
|
|
253
|
+
canGoNext: false,
|
|
254
|
+
title: t("auth.forbidden.title"),
|
|
255
|
+
content: t("auth.forbidden.subtitle"),
|
|
256
|
+
image: "userNotFound"
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
infoDialog.value = {
|
|
260
|
+
canGoNext: false,
|
|
261
|
+
title: t("auth.userNotFoundTitle"),
|
|
262
|
+
content: t("auth.userNotFoundSubtitle"),
|
|
263
|
+
image: "userNotFound"
|
|
264
|
+
}
|
|
266
265
|
}
|
|
267
266
|
|
|
268
267
|
isNotification.value = true
|
package/src/composables/auth.ts
CHANGED
|
@@ -9,7 +9,9 @@ import {
|
|
|
9
9
|
ionEyeSharp,
|
|
10
10
|
ionEyeOffSharp,
|
|
11
11
|
} from "@quasar/extras/ionicons-v5"
|
|
12
|
-
import { Platform } from "quasar"
|
|
12
|
+
import { Platform, useQuasar } from "quasar"
|
|
13
|
+
|
|
14
|
+
import { encrypt, decrypt } from "../utils/encryption"
|
|
13
15
|
|
|
14
16
|
import {
|
|
15
17
|
$prompts,
|
|
@@ -37,6 +39,7 @@ export function useAuth() {
|
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
const { t } = useI18n()
|
|
42
|
+
const { localStorage } = useQuasar()
|
|
40
43
|
const {
|
|
41
44
|
LOCAL_SUCCESS_REDIRECTION_ROUTE,
|
|
42
45
|
APP_SERVER_BASE_URL,
|
|
@@ -142,11 +145,9 @@ export function useAuth() {
|
|
|
142
145
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
143
146
|
// @ts-ignore
|
|
144
147
|
if (!window.Cypress) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
JSON.stringify({ ...data.auth, provider: provider })
|
|
149
|
-
)
|
|
148
|
+
|
|
149
|
+
data.auth.password = encrypt(password.value);
|
|
150
|
+
localStorage.set("credentials",{ ...data.auth, provider: provider })
|
|
150
151
|
}
|
|
151
152
|
push(LOCAL_SUCCESS_REDIRECTION_ROUTE)
|
|
152
153
|
} catch (err) {
|
|
@@ -166,13 +167,20 @@ export function useAuth() {
|
|
|
166
167
|
}
|
|
167
168
|
|
|
168
169
|
const deviceReady = () => {
|
|
169
|
-
if (localStorage.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
170
|
+
if (localStorage.has("credentials")) {
|
|
171
|
+
const credentials = localStorage.getItem("credentials")
|
|
172
|
+
email.value = credentials.email
|
|
173
|
+
password.value = credentials.password
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const tryAutoLogin = async () => {
|
|
178
|
+
if (localStorage.has("credentials")) {
|
|
179
|
+
const credentials = localStorage.getItem("credentials")
|
|
180
|
+
const decryptedPassword = decrypt(credentials.password);
|
|
181
|
+
email.value = credentials.email
|
|
182
|
+
password.value = decryptedPassword
|
|
183
|
+
await onSubmit()
|
|
176
184
|
}
|
|
177
185
|
}
|
|
178
186
|
|
|
@@ -204,6 +212,7 @@ export function useAuth() {
|
|
|
204
212
|
if (Platform.is.capacitor) {
|
|
205
213
|
deviceReady()
|
|
206
214
|
}
|
|
215
|
+
tryAutoLogin()
|
|
207
216
|
})
|
|
208
217
|
|
|
209
218
|
return {
|
package/src/routes/index.ts
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import CryptoJS from "crypto-js";
|
|
2
|
+
|
|
3
|
+
export function encrypt(password: string): string {
|
|
4
|
+
return CryptoJS.AES.encrypt(password, process.env.ENCRYPTION_KEY).toString()
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function decrypt(encryptedPassword: string): string {
|
|
8
|
+
return CryptoJS.AES.decrypt(encryptedPassword, process.env.ENCRYPTION_KEY).toString(CryptoJS.enc.Utf8)
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { encrypt, decrypt } from "./encryption"
|
package/tsconfig.json
CHANGED