@things-factory/auth-ui 8.0.5 → 9.0.0-beta.12

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.
Files changed (146) hide show
  1. package/dist-client/components/abstract-auth-page.d.ts +1 -1
  2. package/dist-client/components/abstract-auth-page.js +12 -10
  3. package/dist-client/components/abstract-auth-page.js.map +1 -1
  4. package/dist-client/components/abstract-password-reset.d.ts +2 -3
  5. package/dist-client/components/abstract-password-reset.js +10 -17
  6. package/dist-client/components/abstract-password-reset.js.map +1 -1
  7. package/dist-client/components/abstract-sign.js +12 -11
  8. package/dist-client/components/abstract-sign.js.map +1 -1
  9. package/dist-client/components/change-password.js +1 -1
  10. package/dist-client/components/change-password.js.map +1 -1
  11. package/dist-client/components/contact-us.d.ts +1 -1
  12. package/dist-client/components/contact-us.js +10 -7
  13. package/dist-client/components/contact-us.js.map +1 -1
  14. package/dist-client/components/create-user.js +28 -5
  15. package/dist-client/components/create-user.js.map +1 -1
  16. package/dist-client/components/invite-user.d.ts +1 -1
  17. package/dist-client/components/invite-user.js +19 -12
  18. package/dist-client/components/invite-user.js.map +1 -1
  19. package/dist-client/components/ownership-transfer-popup.js +3 -3
  20. package/dist-client/components/ownership-transfer-popup.js.map +1 -1
  21. package/dist-client/components/partner-role-editor.js +1 -1
  22. package/dist-client/components/partner-role-editor.js.map +1 -1
  23. package/dist-client/components/profile-component.d.ts +8 -4
  24. package/dist-client/components/profile-component.js +67 -7
  25. package/dist-client/components/profile-component.js.map +1 -1
  26. package/dist-client/components/role-privilege-editor.js +2 -1
  27. package/dist-client/components/role-privilege-editor.js.map +1 -1
  28. package/dist-client/components/user-role-editor.d.ts +2 -2
  29. package/dist-client/components/user-role-editor.js +20 -20
  30. package/dist-client/components/user-role-editor.js.map +1 -1
  31. package/dist-client/constants/index.d.ts +1 -1
  32. package/dist-client/constants/index.js +1 -1
  33. package/dist-client/constants/index.js.map +1 -1
  34. package/dist-client/entries/auth/activate.d.ts +1 -1
  35. package/dist-client/entries/auth/activate.js +1 -1
  36. package/dist-client/entries/auth/activate.js.map +1 -1
  37. package/dist-client/entries/auth/checkin.js +2 -2
  38. package/dist-client/entries/auth/checkin.js.map +1 -1
  39. package/dist-client/entries/auth/forgot-password.d.ts +2 -2
  40. package/dist-client/entries/auth/forgot-password.js +13 -4
  41. package/dist-client/entries/auth/forgot-password.js.map +1 -1
  42. package/dist-client/entries/auth/reset-password.d.ts +1 -1
  43. package/dist-client/entries/auth/reset-password.js +1 -1
  44. package/dist-client/entries/auth/reset-password.js.map +1 -1
  45. package/dist-client/entries/auth/result.d.ts +1 -1
  46. package/dist-client/entries/auth/result.js +1 -1
  47. package/dist-client/entries/auth/result.js.map +1 -1
  48. package/dist-client/entries/auth/signin.d.ts +1 -1
  49. package/dist-client/entries/auth/signin.js +1 -1
  50. package/dist-client/entries/auth/signin.js.map +1 -1
  51. package/dist-client/entries/auth/signup.d.ts +3 -1
  52. package/dist-client/entries/auth/signup.js +45 -9
  53. package/dist-client/entries/auth/signup.js.map +1 -1
  54. package/dist-client/entries/auth/unlock-user.d.ts +1 -1
  55. package/dist-client/entries/auth/unlock-user.js +1 -1
  56. package/dist-client/entries/auth/unlock-user.js.map +1 -1
  57. package/dist-client/entries/oauth2/oauth2-decision-page.d.ts +1 -1
  58. package/dist-client/entries/oauth2/oauth2-decision-page.js +1 -1
  59. package/dist-client/entries/oauth2/oauth2-decision-page.js.map +1 -1
  60. package/dist-client/entries/public/home.js +2 -2
  61. package/dist-client/entries/public/home.js.map +1 -1
  62. package/dist-client/index.js +1 -1
  63. package/dist-client/index.js.map +1 -1
  64. package/dist-client/pages/application/application.js +1 -1
  65. package/dist-client/pages/application/application.js.map +1 -1
  66. package/dist-client/pages/domain/domain-management.d.ts +1 -1
  67. package/dist-client/pages/domain/domain-management.js +1 -1
  68. package/dist-client/pages/domain/domain-management.js.map +1 -1
  69. package/dist-client/pages/partner/partner-management.d.ts +3 -3
  70. package/dist-client/pages/partner/partner-management.js +3 -3
  71. package/dist-client/pages/partner/partner-management.js.map +1 -1
  72. package/dist-client/pages/profile.d.ts +1 -1
  73. package/dist-client/pages/profile.js +1 -1
  74. package/dist-client/pages/profile.js.map +1 -1
  75. package/dist-client/pages/role/role-management.d.ts +3 -3
  76. package/dist-client/pages/role/role-management.js +3 -3
  77. package/dist-client/pages/role/role-management.js.map +1 -1
  78. package/dist-client/pages/user/user-management.d.ts +9 -5
  79. package/dist-client/pages/user/user-management.js +10 -11
  80. package/dist-client/pages/user/user-management.js.map +1 -1
  81. package/dist-client/tsconfig.tsbuildinfo +1 -1
  82. package/dist-server/tsconfig.tsbuildinfo +1 -1
  83. package/package.json +12 -12
  84. package/translations/en.json +6 -2
  85. package/translations/ja.json +6 -2
  86. package/translations/ko.json +6 -2
  87. package/translations/ms.json +6 -2
  88. package/translations/zh.json +6 -2
  89. package/client/auth-style-sign.ts +0 -194
  90. package/client/bootstrap.ts +0 -51
  91. package/client/components/abstract-auth-page.ts +0 -301
  92. package/client/components/abstract-password-reset.ts +0 -168
  93. package/client/components/abstract-sign.ts +0 -127
  94. package/client/components/change-password.ts +0 -153
  95. package/client/components/contact-us.ts +0 -113
  96. package/client/components/create-domain-popup.ts +0 -141
  97. package/client/components/create-role.ts +0 -123
  98. package/client/components/create-user.ts +0 -95
  99. package/client/components/credential-manager.ts +0 -64
  100. package/client/components/delete-user-popup.ts +0 -117
  101. package/client/components/domain-switch.ts +0 -127
  102. package/client/components/invite-customer.ts +0 -104
  103. package/client/components/invite-user.ts +0 -96
  104. package/client/components/my-login-history.ts +0 -101
  105. package/client/components/ownership-transfer-popup.ts +0 -110
  106. package/client/components/partner-info-card.ts +0 -89
  107. package/client/components/partner-role-editor.ts +0 -153
  108. package/client/components/profile-component.ts +0 -332
  109. package/client/components/role-edit-form.ts +0 -92
  110. package/client/components/role-privilege-editor.ts +0 -267
  111. package/client/components/role-selector.ts +0 -102
  112. package/client/components/user-role-editor.ts +0 -499
  113. package/client/constants/application.ts +0 -9
  114. package/client/constants/index.ts +0 -1
  115. package/client/entries/auth/activate.ts +0 -272
  116. package/client/entries/auth/checkin.ts +0 -190
  117. package/client/entries/auth/forgot-password.ts +0 -103
  118. package/client/entries/auth/reset-password.ts +0 -22
  119. package/client/entries/auth/result.ts +0 -193
  120. package/client/entries/auth/signin.ts +0 -18
  121. package/client/entries/auth/signup.ts +0 -109
  122. package/client/entries/auth/unlock-user.ts +0 -22
  123. package/client/entries/oauth2/oauth2-decision-error-page.ts +0 -50
  124. package/client/entries/oauth2/oauth2-decision-page.ts +0 -196
  125. package/client/entries/public/home.ts +0 -246
  126. package/client/index.ts +0 -124
  127. package/client/pages/app-binding/app-binding.ts +0 -423
  128. package/client/pages/app-binding/app-bindings.ts +0 -171
  129. package/client/pages/appliance/appliance.ts +0 -452
  130. package/client/pages/appliance/home.ts +0 -177
  131. package/client/pages/appliance/register.ts +0 -183
  132. package/client/pages/application/application.ts +0 -428
  133. package/client/pages/application/applications.ts +0 -182
  134. package/client/pages/application/register.ts +0 -211
  135. package/client/pages/attribute/attribute-set-item-list.ts +0 -237
  136. package/client/pages/attribute/attribute-set-management.ts +0 -282
  137. package/client/pages/auth-provider/auth-provider-management.ts +0 -381
  138. package/client/pages/domain/domain-management.ts +0 -410
  139. package/client/pages/partner/partner-management.ts +0 -112
  140. package/client/pages/profile.ts +0 -32
  141. package/client/pages/role/role-management.ts +0 -134
  142. package/client/pages/user/user-management.ts +0 -224
  143. package/client/route.ts +0 -67
  144. package/client/themes/auth-theme.css +0 -65
  145. package/client/utils/password-rule.ts +0 -37
  146. package/server/index.ts +0 -0
@@ -1,51 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
- import '@operato/i18n/ox-i18n.js'
3
- import '@operato/attribute/grist-editor' /* for register data-grist editor type 'attributes' */
4
-
5
- import { html } from 'lit-html'
6
-
7
- import { navigate, store } from '@operato/shell'
8
- import { TOOL_POSITION } from '@operato/layout'
9
- import { OxGristEditorPrivilege } from '@operato/app/grist-editor/ox-grist-editor-privilege.js'
10
- import { registerEditor as registerGristEditor, registerRenderer as registerGristRenderer, OxGristRendererJson5 } from '@operato/data-grist'
11
-
12
- import { auth } from '@things-factory/auth-base/dist-client/auth.js'
13
- import { ADD_MORENDA } from '@things-factory/more-base/client'
14
-
15
- export default function bootstrap() {
16
- registerGristEditor('privilege', OxGristEditorPrivilege)
17
- registerGristRenderer('privilege', OxGristRendererJson5)
18
-
19
- /* add user profile morenda */
20
- store.dispatch({
21
- type: ADD_MORENDA,
22
- morenda: {
23
- icon: html` <md-icon>account_circle</md-icon> `,
24
- name: html` <ox-i18n msgid="text.auth profile"></ox-i18n> `,
25
- position: TOOL_POSITION.FRONT_END,
26
- action: () => {
27
- navigate('profile')
28
- }
29
- }
30
- })
31
-
32
- /* add sign-out morenda */
33
- store.dispatch({
34
- type: ADD_MORENDA,
35
- morenda: {
36
- icon: html` <md-icon>exit_to_app</md-icon> `,
37
- name: html` <ox-i18n msgid="field.sign out"></ox-i18n> `,
38
- position: TOOL_POSITION.FRONT_END,
39
- action: () => {
40
- auth.signout()
41
- }
42
- }
43
- })
44
-
45
- /*
46
- Get user profile information from server.
47
- As soon as response received, auth.on('profile', ...) handlers start to work.
48
- It's very important point to build UI for the user.
49
- */
50
- auth.profile()
51
- }
@@ -1,301 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
- import '@material/web/button/elevated-button.js'
3
- import '@material/web/button/text-button.js'
4
- import '@material/web/textfield/filled-text-field.js'
5
-
6
- import '@operato/lottie-player'
7
- import '@operato/i18n/ox-i18n.js'
8
- import '@operato/i18n/ox-i18n-selector.js'
9
- import '@operato/layout/ox-snack-bar.js'
10
-
11
- import { css, html, LitElement, nothing } from 'lit'
12
- import { property, query, state } from 'lit/decorators.js'
13
-
14
- import { i18next, localize } from '@operato/i18n'
15
- import { ScrollbarStyles } from '@operato/styles'
16
- import { isSafari } from '@operato/utils'
17
-
18
- import { AUTH_STYLE_SIGN } from '../auth-style-sign.js'
19
-
20
- export abstract class AbstractAuthPage extends localize(i18next)(LitElement) {
21
- static styles = [
22
- ScrollbarStyles,
23
- css`
24
- :host {
25
- position: relative;
26
- overflow: hidden;
27
-
28
- display: flex;
29
- flex-direction: row;
30
-
31
- width: 100vw;
32
- height: 100vh;
33
- height: 100dvh;
34
- }
35
-
36
- .content {
37
- flex: 1;
38
- overflow: auto;
39
- }
40
-
41
- .home {
42
- position: absolute;
43
- padding: var(--padding-dufault, 9px);
44
- left: 20px;
45
- top: 10px;
46
- color: var(--md-sys-color-on-primary);
47
- }
48
-
49
- div.field {
50
- margin-bottom: var(--spacing-medium);
51
- }
52
-
53
- [hidden] {
54
- display: none;
55
- }
56
-
57
- #snackbar {
58
- width: 100%;
59
- z-index: 10;
60
- }
61
-
62
- @media print {
63
- :host {
64
- width: 100%;
65
- height: 100%;
66
- min-height: 100vh;
67
- min-height: 100dvh;
68
- }
69
- }
70
- `,
71
- AUTH_STYLE_SIGN
72
- ]
73
-
74
- @property({ type: Object }) data: any
75
- @property({ type: String }) message?: string
76
- @property({ type: Object }) detail: any
77
- @property({ type: String }) redirectTo?: string
78
-
79
- @query('#form') formEl!: HTMLFormElement
80
-
81
- private _applicationMeta?: {
82
- icon: string
83
- title: string
84
- description: string
85
- }
86
-
87
- get autocompletable() {
88
- return false
89
- }
90
-
91
- render() {
92
- const { disableUserFavoredLanguage, languages } = this.data || {}
93
- var { icon, title, description } = this.applicationMeta
94
-
95
- return html`
96
- <div class="content md-typescale-display-medium">
97
- <div class="wrap">
98
- <div class="auth-brand">
99
- <img src=${icon} />
100
- <strong class="name">${title}</strong>
101
- <span class="welcome-msg">${description}</span>
102
- </div>
103
-
104
- <div class="auth-form">
105
- <h3><ox-i18n msgid="title.${this.pageName}"></ox-i18n></h3>
106
-
107
- <form
108
- id="form"
109
- action="${this.actionUrl}"
110
- method="post"
111
- autocomplete=${this.autocompletable ? 'on' : 'off'}
112
- @keypress=${e => {
113
- if (e.key == 'Enter') this._onSubmit(e)
114
- }}
115
- >
116
- ${this.formfields}
117
- </form>
118
- ${this.links}
119
- ${!disableUserFavoredLanguage
120
- ? html` <div id="locale-area">
121
- <label for="locale-selector"><md-icon>language</md-icon></label>
122
- <ox-i18n-selector
123
- id="locale-selector"
124
- value=${i18next.language || 'en-US'}
125
- .languages=${languages}
126
- @change=${e => {
127
- var locale = e.detail
128
- if (!locale) return
129
-
130
- i18next.changeLanguage(locale)
131
- }}
132
- ></ox-i18n-selector>
133
- </div>`
134
- : nothing}
135
- </div>
136
- </div>
137
-
138
- <md-icon-button class="home" @click=${e => (window.location.href = '/')}
139
- ><md-icon>home</md-icon></md-icon-button
140
- >
141
- <ox-snack-bar id="snackbar" level="error" .message=${this.message}></ox-snack-bar>
142
-
143
- ${isSafari()
144
- ? html``
145
- : html`
146
- <div class="lottie-container">
147
- <lottie-player autoplay loop src="../../assets/images/background-animation.json"></lottie-player>
148
- </div>
149
- `}
150
- </div>
151
- `
152
- }
153
-
154
- firstUpdated() {
155
- setTimeout(() => {
156
- ;(this.renderRoot.querySelector('md-filled-text-field') as any).focus()
157
- }, 100)
158
-
159
- this.formEl.reset = () => {
160
- this.formElements.filter(el => !(el.hidden || el.type == 'hidden')).forEach(el => (el.value = ''))
161
- }
162
- }
163
-
164
- updated(changed) {
165
- if (changed.has('data') && this.data) {
166
- this.message = this.data.message
167
- this.redirectTo = this.data.redirectTo
168
- }
169
- }
170
-
171
- abstract get pageName(): string
172
- abstract get actionUrl(): string
173
-
174
- get formElements(): HTMLInputElement[] {
175
- return Array.from(this.formEl.querySelectorAll('[name]'))
176
- }
177
-
178
- get formfields() {
179
- const email = this.data?.email || ''
180
- // .validationMessage=${String(i18next.t('text.invalid-email'))}
181
-
182
- return html`
183
- <input id="redirectTo" type="hidden" name="redirectTo" .value=${this.redirectTo || '/'} />
184
-
185
- <div class="field">
186
- <md-filled-text-field
187
- name="email"
188
- type="email"
189
- label=${String(i18next.t('field.email'))}
190
- required
191
- .value=${email}
192
- autocomplete="off"
193
- autocapitalize="off"
194
- ><md-icon slot="leading-icon">mail</md-icon></md-filled-text-field
195
- >
196
- </div>
197
- <div class="field">
198
- <md-filled-text-field
199
- name="password"
200
- type="password"
201
- label=${String(i18next.t('field.password'))}
202
- autocomplete="off"
203
- required
204
- ><md-icon slot="leading-icon">vpn_key</md-icon></md-filled-text-field
205
- >
206
- </div>
207
-
208
- <md-elevated-button class="ui" type="submit" raised @click=${e => this._onSubmit(e)}>
209
- <ox-i18n msgid="field.${this.pageName}"> </ox-i18n>
210
- </md-elevated-button>
211
- `
212
- }
213
-
214
- get links() {
215
- const { disableUserSignupProcess, ssoLinks = [] } = this.data || {}
216
-
217
- return html`
218
- ${!disableUserSignupProcess
219
- ? html`
220
- <a class="link" href="/auth/signup">
221
- <md-text-button>
222
- <md-icon slot="icon">add_task</md-icon>
223
- <ox-i18n msgid="field.sign up"></ox-i18n>
224
- </md-text-button>
225
- </a>
226
- <a class="link" href="/auth/forgot-password">
227
- <md-text-button>
228
- <md-icon slot="icon">lock_open</md-icon>
229
- <ox-i18n msgid="field.forgot-password"></ox-i18n>
230
- </md-text-button>
231
- </a>
232
- `
233
- : nothing}
234
- ${ssoLinks.map(
235
- sso => html`
236
- <a class="link" href=${sso.link}>
237
- <md-text-button>
238
- <md-icon slot="icon">badge</md-icon>
239
- ${i18next.t('label.signin with', { title: sso.title })}
240
- </md-text-button>
241
- </a>
242
- `
243
- )}
244
- `
245
- }
246
-
247
- async _onSubmit(e) {
248
- if (this.checkValidity()) {
249
- this.submit()
250
- }
251
- }
252
-
253
- checkValidity() {
254
- return this.formElements.every(el => el.checkValidity())
255
- }
256
-
257
- abstract submit()
258
-
259
- showSnackbar({ level, message, timer = 3000 }: { level?: string; message?: string; timer?: number } = {}) {
260
- const snackbar = this.renderRoot.querySelector('#snackbar') as HTMLElement & {
261
- level: string
262
- message: string
263
- active: boolean
264
- }
265
-
266
- if (level) snackbar.level = level
267
- if (message) snackbar.message = message
268
- snackbar.active = true
269
-
270
- if (timer > -1)
271
- setTimeout(() => {
272
- this.hideSnackbar()
273
- }, timer)
274
- }
275
-
276
- hideSnackbar() {
277
- const snackbar = this.renderRoot.querySelector('#snackbar') as HTMLElement & {
278
- level: string
279
- message: string
280
- active: boolean
281
- }
282
-
283
- snackbar.active = false
284
- }
285
-
286
- get applicationMeta() {
287
- if (!this._applicationMeta) {
288
- var iconLink: HTMLLinkElement | null = document.querySelector('link[rel="application-icon"]')
289
- var titleMeta: HTMLMetaElement | null = document.querySelector('meta[name="application-name"]')
290
- var descriptionMeta: HTMLMetaElement | null = document.querySelector('meta[name="application-description"]')
291
-
292
- this._applicationMeta = {
293
- icon: iconLink?.href || '',
294
- title: titleMeta?.content || 'Things Factory',
295
- description: descriptionMeta?.content || 'Reimagining Software'
296
- }
297
- }
298
-
299
- return this._applicationMeta
300
- }
301
- }
@@ -1,168 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
- import '@material/web/button/elevated-button.js'
3
- import '@material/web/textfield/filled-text-field.js'
4
-
5
- import '@operato/lottie-player'
6
- import '../components/profile-component'
7
- import '@operato/i18n/ox-i18n.js'
8
- import '@operato/i18n/ox-i18n-selector.js'
9
- import '@operato/layout/ox-snack-bar.js'
10
-
11
- import { css, html, nothing } from 'lit'
12
- import { property, query } from 'lit/decorators.js'
13
-
14
- import { i18next } from '@operato/i18n'
15
- import { isSafari } from '@operato/utils'
16
-
17
- import { AUTH_STYLE_SIGN } from '../auth-style-sign'
18
- import { generatePasswordPatternHelp, generatePasswordPatternRegExp } from '../utils/password-rule'
19
- import { AbstractAuthPage } from './abstract-auth-page'
20
-
21
- export abstract class AbstractPasswordReset extends AbstractAuthPage {
22
- static styles = [
23
- css`
24
- :host {
25
- position: relative;
26
- overflow: hidden;
27
-
28
- display: flex;
29
- flex-direction: row;
30
-
31
- width: 100vw;
32
- height: 100vh;
33
- height: 100dvh;
34
- }
35
-
36
- @media print {
37
- :host {
38
- width: 100%;
39
- height: 100%;
40
- min-height: 100vh;
41
- min-height: 100dvh;
42
- }
43
- }
44
- `,
45
- AUTH_STYLE_SIGN
46
- ]
47
-
48
- @property({ type: Object }) data: any
49
- @property({ type: String }) token?: string
50
-
51
- @query('#confirm-password') confirmPass!: HTMLElement
52
-
53
- private passwordPattern: string = ''
54
- private passwordHelp: string = ''
55
-
56
- abstract get submitButtonLabel(): string
57
-
58
- render() {
59
- var { icon, title, description } = this.applicationMeta
60
- const { disableUserFavoredLanguage, languages } = this.data || {}
61
-
62
- return html`
63
- <div class="wrap">
64
- <div class="auth-brand">
65
- <img src=${icon} />
66
- <strong class="name">${title}</strong>
67
- <span class="welcome-msg">${description}</span>
68
- </div>
69
-
70
- <div class="auth-form">
71
- <h3><ox-i18n msgid="title.${this.title}"></ox-i18n></h3>
72
- <form
73
- id="form"
74
- action="${this.actionUrl}"
75
- method="post"
76
- @keypress=${e => {
77
- if (e.key == 'Enter') this._onSubmit(e)
78
- }}
79
- >
80
- <input name="token" type="hidden" .value=${this.token || ''} required />
81
- <div class="field">
82
- <md-filled-text-field
83
- name="password"
84
- type="password"
85
- label=${String(i18next.t('label.password'))}
86
- pattern=${this.passwordPattern || ''}
87
- supporting-text=${this.passwordHelp}
88
- autocomplete="off"
89
- @input=${e => {
90
- var val = e.target.value
91
- this.confirmPass.setAttribute('pattern', val.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '[$&]'))
92
- }}
93
- required
94
- ></md-filled-text-field>
95
- </div>
96
-
97
- <div class="field">
98
- <md-filled-text-field
99
- id="confirm-password"
100
- name="confirm-password"
101
- type="password"
102
- label=${String(i18next.t('field.confirm password'))}
103
- autocomplete="off"
104
- required
105
- ></md-filled-text-field>
106
- </div>
107
-
108
- <md-elevated-button id="submit-button" type="submit" @click=${e => this._onSubmit(e)}>
109
- <ox-i18n msgid="${this.submitButtonLabel}"></ox-i18n>
110
- </md-elevated-button>
111
-
112
- ${!disableUserFavoredLanguage
113
- ? html` <div id="locale-area">
114
- <label for="locale-selector"><md-icon>language</md-icon></label>
115
- <ox-i18n-selector
116
- id="locale-selector"
117
- value=${i18next.language || 'en-US'}
118
- .languages=${languages}
119
- @change=${e => {
120
- var locale = e.detail
121
- if (!locale) return
122
-
123
- i18next.changeLanguage(locale)
124
- }}
125
- ></ox-i18n-selector>
126
- </div>`
127
- : nothing}
128
- </form>
129
- </div>
130
- </div>
131
- <ox-snack-bar id="snackbar" level="error" .message=${this.message}></ox-snack-bar>
132
-
133
- ${isSafari()
134
- ? html``
135
- : html`
136
- <div class="lottie-container">
137
- <lottie-player autoplay loop src="../../assets/images/background-animation.json"></lottie-player>
138
- </div>
139
- `}
140
- `
141
- }
142
-
143
- updated(changed) {
144
- super.updated(changed)
145
- if (changed.has('data')) {
146
- this.token = this.data.token
147
- }
148
-
149
- if (changed.has('message')) {
150
- if (!this.message) {
151
- this.hideSnackbar()
152
- } else {
153
- this.showSnackbar({
154
- timer: -1
155
- })
156
- }
157
- }
158
- }
159
-
160
- languageUpdated() {
161
- this.passwordPattern = generatePasswordPatternRegExp(this.data.passwordRule).source
162
- this.passwordHelp = generatePasswordPatternHelp(this.data.passwordRule)
163
- }
164
-
165
- async submit() {
166
- this.formEl.submit()
167
- }
168
- }
@@ -1,127 +0,0 @@
1
- import '@operato/i18n/ox-i18n.js'
2
-
3
- import { html, nothing } from 'lit'
4
- import { startAuthentication } from '@simplewebauthn/browser'
5
-
6
- import { i18next } from '@operato/i18n'
7
- import { notify } from '@operato/layout'
8
-
9
- import { AbstractAuthPage } from './abstract-auth-page.js'
10
-
11
- const isAvailableWebauthn = 'PublicKeyCredential' in window
12
-
13
- interface AssertionResponse {
14
- id: string
15
- rawId?: number[]
16
- response: {
17
- authenticatorData: string
18
- clientDataJSON: string
19
- signature: string
20
- userHandle: string | null
21
- }
22
- type: PublicKeyCredentialType
23
- authenticatorAttachment?: AuthenticatorAttachment
24
- }
25
-
26
- export abstract class AbstractSign extends AbstractAuthPage {
27
- async submit() {
28
- this.formEl.submit()
29
- }
30
-
31
- updated(changed) {
32
- super.updated(changed)
33
-
34
- if (changed.has('message')) {
35
- if (!this.message) {
36
- this.hideSnackbar()
37
- } else {
38
- this.showSnackbar({
39
- level: 'error',
40
- timer: -1
41
- })
42
- }
43
- }
44
- }
45
-
46
- get formfields() {
47
- const email = this.data?.email || ''
48
- const autocompletable = this.autocompletable
49
-
50
- return html`
51
- <input id="redirectTo" type="hidden" name="redirectTo" .value=${this.redirectTo || '/'} />
52
-
53
- <div class="field">
54
- <md-filled-text-field
55
- name="email"
56
- type="email"
57
- label=${String(i18next.t('field.email'))}
58
- required
59
- .value=${email}
60
- autocomplete=${autocompletable ? "username" : "off"}
61
- autocapitalize="off"
62
- @input=${(e: Event) => {
63
- const target = e.target as HTMLInputElement
64
- if (target.validity.typeMismatch) {
65
- target.setCustomValidity(i18next.t('text.invalid-email'))
66
- } else {
67
- target.setCustomValidity('')
68
- }
69
- }}
70
- ><md-icon slot="leading-icon">mail</md-icon></md-filled-text-field
71
- >
72
- </div>
73
- <div class="field">
74
- <md-filled-text-field
75
- name="password"
76
- type="password"
77
- label=${String(i18next.t('field.password'))}
78
- autocomplete=${autocompletable ? "current-password" : "off"}
79
- required
80
- ><md-icon slot="leading-icon">vpn_key</md-icon></md-filled-text-field
81
- >
82
- </div>
83
-
84
- <div class="submit-buttons-container">
85
- <md-elevated-button class="submit-button" type="submit" raised @click=${e => this._onSubmit(e)}>
86
- <ox-i18n msgid="field.${this.pageName}"> </ox-i18n>
87
- </md-elevated-button>
88
- ${isAvailableWebauthn
89
- ? html` <md-icon class="fingerprint" raised @click=${e => this.authenticateUser()}> fingerprint </md-icon>`
90
- : nothing}
91
- </div>
92
- `
93
- }
94
-
95
- async authenticateUser() {
96
- try {
97
- const options = await fetch('/auth/signin-webauthn/challenge').then(res => res.json())
98
- const assertionResp = await startAuthentication(options)
99
- const verification = await fetch('/auth/signin-webauthn', {
100
- method: 'POST',
101
- headers: {
102
- 'Content-Type': 'application/json'
103
- },
104
- body: JSON.stringify(assertionResp)
105
- }).then(res => res.json())
106
-
107
- if (verification.verified) {
108
- const { redirectURL } = verification
109
-
110
- if (redirectURL) {
111
- window.location.href = redirectURL
112
- }
113
- } else {
114
- notify({
115
- level: 'error',
116
- message: verification.message
117
- })
118
- }
119
-
120
- } catch (error) {
121
- notify({
122
- level: 'error',
123
- message: i18next.t('error.authn verification failed')
124
- })
125
- }
126
- }
127
- }