@sowell/quasar-app-extension-auth 1.1.1 → 1.2.0

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sowell/quasar-app-extension-auth",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
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",
@@ -23,6 +23,7 @@
23
23
  "devDependencies": {
24
24
  "@quasar/app-webpack": "^4.0.0-beta.16",
25
25
  "@quasar/cli": "^2.2.3",
26
+ "@types/crypto-js": "^4.2.2",
26
27
  "@types/node": "^16.9.1",
27
28
  "@types/validator": "^13.6.3",
28
29
  "@typescript-eslint/eslint-plugin": "^5.10.0",
@@ -1,21 +1,20 @@
1
1
  <template>
2
- <q-card style="max-width: 343px; border-radius: 10px; background: #f4f5f6" data-testid="feedback-dialog">
2
+ <q-card
3
+ style="max-width: 343px; border-radius: 10px; background: #f4f5f6"
4
+ data-testid="feedback-dialog">
3
5
  <q-card-section class="text-center q-mt-lg">
4
6
  <img
5
7
  v-if="emailSended"
6
8
  src="../../assets/mailbox.svg"
7
- style="width: 175px; height: 150px"
8
- />
9
+ style="width: 175px; height: 150px" />
9
10
  <img
10
11
  v-if="passwordUpdated"
11
12
  src="../../assets/success.svg"
12
- style="width: 100px; height: 80px"
13
- />
13
+ style="width: 100px; height: 80px" />
14
14
  <img
15
15
  v-if="emailNotSend"
16
16
  src="../../assets/error.svg"
17
- style="width: 100px; height: 80px"
18
- />
17
+ style="width: 100px; height: 80px" />
19
18
  </q-card-section>
20
19
 
21
20
  <q-card-section class="q-pt-none q-pl-lg q-pr-lg">
@@ -23,29 +22,26 @@
23
22
  class="text-subtitle1 q-mt-sm q-mb-md text-center text-dark"
24
23
  style="font-size: 24px; font-weight: 600"
25
24
  data-cy="resetErrorMessage"
26
- data-testid="header-dialog"
27
- >
25
+ data-testid="header-dialog">
28
26
  {{ messageTitle }}
29
27
  </div>
30
28
  <div
31
29
  data-cy="resetMessage"
32
30
  data-testid="message-dialog"
33
31
  class="text-subtitle1 q-mt-sm text-center"
34
- style="font-size: 16px; font-weight: 400"
35
- >
32
+ style="font-size: 16px; font-weight: 400">
36
33
  {{ messageSubtitle }}
37
34
  </div>
38
35
  <div
39
36
  class="q-mt-sm text-center q-mb-xl"
40
37
  style="font-size: 15px; color: #737676"
41
- v-if="sendEmailSuccess"
42
- >
38
+ v-if="sendEmailCode === 200">
43
39
  {{ emailResetPassword }}
44
40
  </div>
45
41
  </q-card-section>
46
42
  <q-card-actions class="q-ml-lg q-mr-lg q-mb-lg">
47
43
  <q-btn
48
- v-if="emailNotSend"
44
+ v-if="emailNotSend && sendEmailCode !== 403"
49
45
  data-cy="submit-login"
50
46
  :label="$t('auth.reSend')"
51
47
  color="primary"
@@ -55,8 +51,7 @@
55
51
  unelevated
56
52
  type="submit"
57
53
  @click="retypeEmail"
58
- class="full-width"
59
- />
54
+ class="full-width" />
60
55
  <slot>
61
56
  <q-btn
62
57
  data-testid="close-btn"
@@ -68,24 +63,23 @@
68
63
  no-caps
69
64
  :label="$t('auth.close')"
70
65
  color="dark"
71
- v-close-popup
72
- />
66
+ v-close-popup />
73
67
  </slot>
74
68
  </q-card-actions>
75
69
  </q-card>
76
70
  </template>
77
71
 
78
72
  <script lang="ts">
79
- import { defineComponent, computed } from "vue";
80
- import { useI18n } from "vue-i18n";
73
+ import { defineComponent, computed } from "vue"
74
+ import { useI18n } from "vue-i18n"
81
75
 
82
76
  export default defineComponent({
83
77
  props: {
84
78
  emailResetPassword: {
85
79
  type: String
86
80
  },
87
- sendEmailSuccess: {
88
- type: Boolean
81
+ sendEmailCode: {
82
+ type: Number
89
83
  },
90
84
  loading: {
91
85
  type: Boolean
@@ -98,34 +92,40 @@ export default defineComponent({
98
92
  setup(props: any, { emit }: any) {
99
93
  const { t } = useI18n()
100
94
 
101
- const messageSubtitle = computed(() =>
102
- props.sendEmailSuccess
95
+ const messageSubtitle = computed(() => {
96
+ if (props.sendEmailCode === 403) {
97
+ return t("auth.forbidden.subtitle")
98
+ }
99
+ return props.sendEmailCode === 200
103
100
  ? t("auth.emailSent")
104
101
  : !props.passwordUpdated
105
102
  ? t("auth.emailNotRecognize")
106
103
  : t("auth.passwordUpdated")
107
- )
108
- const messageTitle = computed(() =>
109
- props.sendEmailSuccess
104
+ })
105
+ const messageTitle = computed(() => {
106
+ if (props.sendEmailCode === 403) {
107
+ return t("auth.forbidden.title")
108
+ }
109
+ return props.sendEmailCode === 200
110
110
  ? t("auth.emailVerification")
111
111
  : !props.passwordUpdated
112
112
  ? t("auth.loginFailed")
113
113
  : t("auth.passwordChanged")
114
- )
114
+ })
115
115
 
116
116
  const emailNotSend = computed(
117
- () => !props.sendEmailSuccess && !props.passwordUpdated
117
+ () => props.sendEmailCode !== 200 && !props.passwordUpdated
118
118
  )
119
119
  const emailSended = computed(
120
- () => props.sendEmailSuccess && !props.passwordUpdated
120
+ () => props.sendEmailCode === 200 && !props.passwordUpdated
121
121
  )
122
122
 
123
123
  const retypeEmail = () => {
124
124
  emit("retypeEmail")
125
125
  }
126
126
 
127
- const handlePasswordUpdate = () =>{
128
- if(props.passwordUpdated){
127
+ const handlePasswordUpdate = () => {
128
+ if (props.passwordUpdated) {
129
129
  emit("goToLoginPage")
130
130
  } else {
131
131
  emit("close")
@@ -134,7 +134,7 @@
134
134
  <q-dialog v-model="isReset" persistent>
135
135
  <sowell-message
136
136
  :emailResetPassword="emailResetPassword"
137
- :sendEmailSuccess="sendEmailSuccess"
137
+ :sendEmailCode="sendEmailCode"
138
138
  :loading="loading"
139
139
  @retypeEmail="retypeEmail"
140
140
  @close="() => isReset= false"/>
@@ -177,7 +177,7 @@ export default defineComponent({
177
177
  forgottenPassword,
178
178
  emailResetPassword,
179
179
  isReset,
180
- sendEmailSuccess,
180
+ sendEmailCode,
181
181
  authState,
182
182
  APP_SERVER_BASE_URL,
183
183
  icons,
@@ -201,11 +201,11 @@ export default defineComponent({
201
201
  try {
202
202
  forgottenPassword.value = false
203
203
  await authState.resetPassword(data).then(() => {
204
- sendEmailSuccess.value = true
204
+ sendEmailCode.value = 200
205
205
  isReset.value = true
206
206
  })
207
207
  } catch {
208
- sendEmailSuccess.value = false
208
+ sendEmailCode.value = 404
209
209
  isReset.value = true
210
210
  }
211
211
  }
@@ -228,7 +228,7 @@ export default defineComponent({
228
228
  forgottenPassword,
229
229
  emailResetPassword,
230
230
  isReset,
231
- sendEmailSuccess,
231
+ sendEmailCode,
232
232
  icons,
233
233
  appVersion,
234
234
  USE_SSO,
@@ -7,13 +7,11 @@
7
7
  <img
8
8
  src="../../assets/Logo.svg"
9
9
  class="q-mb-sm q-mr-md"
10
- style="width: 27px; height: 47px"
11
- />
10
+ style="width: 27px; height: 47px" />
12
11
  <img
13
12
  src="../../assets/Sowell.svg"
14
13
  class="q-mb-sm"
15
- style="width: 146px; height: 38px"
16
- />
14
+ style="width: 146px; height: 38px" />
17
15
  </div>
18
16
  </div>
19
17
  <div class="login-page">
@@ -21,8 +19,7 @@
21
19
  <div>
22
20
  <div
23
21
  class="q-ml-xs q-mb-xs"
24
- style="font-size: 14px; font-weight: 600"
25
- >
22
+ style="font-size: 14px; font-weight: 600">
26
23
  {{ $t("auth.email") }}
27
24
  </div>
28
25
  <q-input
@@ -32,8 +29,7 @@
32
29
  borderless
33
30
  :rules="validations['email']"
34
31
  lazy-rules
35
- :input-style="{ fontSize: '14px', fontWeight: '500' }"
36
- >
32
+ :input-style="{ fontSize: '14px', fontWeight: '500' }">
37
33
  <template #prepend>
38
34
  <q-icon :name="icons.ionMailOutline" />
39
35
  </template>
@@ -42,8 +38,7 @@
42
38
  <div>
43
39
  <div
44
40
  class="q-ml-xs q-mb-xs"
45
- style="font-size: 14px; font-weight: 600"
46
- >
41
+ style="font-size: 14px; font-weight: 600">
47
42
  {{ $t("auth.password") }}
48
43
  </div>
49
44
  <q-input
@@ -54,8 +49,7 @@
54
49
  lazy-rules
55
50
  borderless
56
51
  dense
57
- :input-style="{ fontSize: '14px', fontWeight: '600' }"
58
- >
52
+ :input-style="{ fontSize: '14px', fontWeight: '600' }">
59
53
  <template #prepend>
60
54
  <q-icon :name="icons.ionLockClosedOutline" />
61
55
  </template>
@@ -67,15 +61,13 @@
67
61
  : icons.ionEyeOutline
68
62
  "
69
63
  class="cursor-pointer q-mr-sm"
70
- @click="showPassword = !showPassword"
71
- />
64
+ @click="showPassword = !showPassword" />
72
65
  </template>
73
66
  </q-input>
74
67
  </div>
75
68
  <div
76
69
  v-if="errorEmailMessage || errorPasswordMessage"
77
- class="q-pl-sm text-red column justify-center error_input"
78
- >
70
+ class="q-pl-sm text-red column justify-center error_input">
79
71
  <div>{{ errorEmailMessage }}</div>
80
72
  <div>{{ errorPasswordMessage }}</div>
81
73
  </div>
@@ -89,8 +81,7 @@
89
81
  :loading="loading"
90
82
  type="submit"
91
83
  class="full-width q-mt-lg"
92
- :disable="isSubmitBtnDisabled()"
93
- >
84
+ :disable="isSubmitBtnDisabled()">
94
85
  <div style="font-weight: 600; font-size: 16px">
95
86
  {{ $t("auth.login") }}
96
87
  </div>
@@ -101,10 +92,44 @@
101
92
  @click="forgottenPassword = true"
102
93
  data-testid="ask-password-change-btn"
103
94
  data-cy="forgot-password"
104
- style="font-size: 14px; cursor: pointer; width: 350px"
105
- >
95
+ style="font-size: 14px; cursor: pointer; width: 350px">
106
96
  {{ $t("auth.forgottenPassword") }}
107
97
  </div>
98
+ <div v-if="USE_SSO">
99
+ <div
100
+ style="
101
+ display: flex;
102
+ justify-content: space-between;
103
+ align-items: center;
104
+ ">
105
+ <div
106
+ style="
107
+ width: 35%;
108
+ border: 1px solid #bcc3c7;
109
+ height: 1px;
110
+ "></div>
111
+ <div class="text-weight-bold">{{ $t("common.or") }}</div>
112
+ <div
113
+ style="
114
+ width: 35%;
115
+ border: 1px solid #bcc3c7;
116
+ height: 1px;
117
+ "></div>
118
+ </div>
119
+ <q-btn
120
+ data-cy="submit-sso-login"
121
+ :label="$t('auth.msalLogin')"
122
+ color="primary"
123
+ no-caps
124
+ unelevated
125
+ text-color="black"
126
+ :loading="msalLoading"
127
+ :disable="msalLoading || loading"
128
+ :icon="`img:${MicrosoftLogo}`"
129
+ class="full-width q-mt-lg"
130
+ @click="msalAuth"
131
+ outline />
132
+ </div>
108
133
  </div>
109
134
  </q-form>
110
135
  </div>
@@ -117,20 +142,20 @@
117
142
  transition-show="fade"
118
143
  transition-hide="fade"
119
144
  persistent
120
- data-testid="ask-password-change-modal"
121
- >
122
- <send-email @resetPassword="resetPassword" @close="() => forgottenPassword = false" />
145
+ data-testid="ask-password-change-modal">
146
+ <send-email
147
+ @resetPassword="resetPassword"
148
+ @close="() => (forgottenPassword = false)" />
123
149
  </q-dialog>
124
150
  <q-dialog v-model="isReset" persistent>
125
151
  <sowell-message
126
152
  :emailResetPassword="emailResetPassword"
127
- :sendEmailSuccess="sendEmailSuccess"
153
+ :sendEmailCode="sendEmailCode"
128
154
  :loading="loading"
129
155
  @retypeEmail="retypeEmail"
130
- @close="() => isReset = false"
131
- >
156
+ @close="() => (isReset = false)">
132
157
  <q-btn
133
- v-if="sendEmailSuccess && isOtp"
158
+ v-if="sendEmailCode === 200 && isOtp"
134
159
  data-testid="next-btn"
135
160
  class="q-mt-md full-width"
136
161
  unelevated
@@ -140,8 +165,7 @@
140
165
  no-caps
141
166
  :label="$t('auth.next')"
142
167
  color="dark"
143
- v-close-popup
144
- />
168
+ v-close-popup />
145
169
  </sowell-message>
146
170
  </q-dialog>
147
171
  </div>
@@ -164,6 +188,8 @@ import * as packageInfo from "app/package.json"
164
188
  import SendEmail from "../dialogs/SendEmail.vue"
165
189
  import SowellMessage from "../dialogs/Message.vue"
166
190
  import { useAuth } from "composables/auth"
191
+ import { AxiosError } from "axios"
192
+ import MicrosoftLogo from "../../assets/logo-microsoft.svg"
167
193
 
168
194
  export default defineComponent({
169
195
  name: "Auth",
@@ -180,11 +206,14 @@ export default defineComponent({
180
206
  forgottenPassword,
181
207
  emailResetPassword,
182
208
  isReset,
183
- sendEmailSuccess,
209
+ sendEmailCode,
184
210
  authState,
185
211
  APP_SERVER_BASE_URL,
186
212
  IS_OTP,
187
213
  icons,
214
+ USE_SSO,
215
+ msalAuth,
216
+ msalLoading,
188
217
  onSubmit,
189
218
  retypeEmail,
190
219
  isSubmitBtnDisabled,
@@ -206,20 +235,25 @@ export default defineComponent({
206
235
  auth: {
207
236
  email,
208
237
  base: APP_SERVER_BASE_URL
209
- },
238
+ }
210
239
  }
211
240
  try {
212
241
  forgottenPassword.value = false
213
242
  await authState.resetPassword(data).then(() => {
214
243
  localStorage.setItem("emailResetPassword", email)
215
- sendEmailSuccess.value = true
244
+ sendEmailCode.value = 200
216
245
  isReset.value = true
217
246
  })
218
- } catch {
219
- sendEmailSuccess.value = false
247
+ } catch (error) {
248
+ if ((error as AxiosError).response?.status === 403) {
249
+ // NOTE: 403 is returned when the user is not allowed to reset the password
250
+ sendEmailCode.value = 403
251
+ } else {
252
+ sendEmailCode.value = 404
253
+ }
220
254
  isReset.value = true
221
255
  }
222
- };
256
+ }
223
257
 
224
258
  onMounted(() => {
225
259
  appVersion.versionNumber = packageInfo.version
@@ -236,13 +270,17 @@ export default defineComponent({
236
270
  forgottenPassword,
237
271
  emailResetPassword,
238
272
  isReset,
239
- sendEmailSuccess,
273
+ sendEmailCode,
240
274
  icons,
241
275
  appVersion,
242
276
  isOtp,
243
277
  goToOtpValidation,
244
278
  isSubmitBtnDisabled,
245
279
  retypeEmail,
280
+ msalLoading,
281
+ USE_SSO,
282
+ msalAuth,
283
+ MicrosoftLogo,
246
284
  handleSubmit,
247
285
  resetPassword
248
286
  }
@@ -264,4 +302,3 @@ export default defineComponent({
264
302
  display: none;
265
303
  }
266
304
  </style>
267
-
@@ -61,7 +61,7 @@ export function useAuth() {
61
61
  const showPassword = ref(false)
62
62
  const forgottenPassword = ref(false)
63
63
  const isReset = ref(false)
64
- const sendEmailSuccess = ref(false)
64
+ const sendEmailCode = ref(0)
65
65
  const emailResetPassword = ref("")
66
66
  const errorEmailMessage = ref("")
67
67
  const errorPasswordMessage = ref("")
@@ -227,7 +227,7 @@ export function useAuth() {
227
227
  forgottenPassword,
228
228
  emailResetPassword,
229
229
  isReset,
230
- sendEmailSuccess,
230
+ sendEmailCode,
231
231
  authState,
232
232
  APP_SERVER_BASE_URL,
233
233
  WELCOME_TITLE,