@things-factory/auth-ui 7.0.1-alpha.88 → 7.0.1-alpha.90
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/client/auth-style-sign.ts +29 -18
- package/client/components/abstract-auth-page.ts +41 -22
- package/client/components/abstract-password-reset.ts +11 -9
- package/client/components/abstract-sign.ts +138 -0
- package/client/components/change-password.ts +2 -2
- package/client/components/contact-us.ts +18 -16
- package/client/components/create-domain-popup.ts +11 -7
- package/client/components/create-role.ts +8 -20
- package/client/components/create-user.ts +8 -16
- package/client/components/credential-manager.ts +64 -0
- package/client/components/invite-customer.ts +7 -12
- package/client/components/invite-user.ts +2 -7
- package/client/components/ownership-transfer-popup.ts +3 -3
- package/client/components/partner-role-editor.ts +9 -15
- package/client/components/profile-component.ts +124 -7
- package/client/components/role-privilege-editor.ts +10 -17
- package/client/components/user-role-editor.ts +27 -38
- package/client/entries/auth/activate.ts +17 -17
- package/client/entries/auth/checkin.ts +15 -19
- package/client/entries/auth/forgot-password.ts +8 -6
- package/client/entries/auth/result.ts +13 -12
- package/client/entries/auth/signup.ts +20 -24
- package/client/entries/oauth2/oauth2-decision-error-page.ts +2 -2
- package/client/entries/oauth2/oauth2-decision-page.ts +60 -55
- package/client/entries/public/home.ts +40 -18
- package/client/pages/app-binding/app-binding.ts +5 -9
- package/client/pages/app-binding/app-bindings.ts +2 -2
- package/client/pages/appliance/appliance.ts +6 -9
- package/client/pages/appliance/home.ts +3 -3
- package/client/pages/appliance/register.ts +1 -1
- package/client/pages/application/application.ts +30 -14
- package/client/pages/application/applications.ts +4 -12
- package/client/pages/application/register.ts +1 -1
- package/client/pages/attribute/attribute-set-management.ts +2 -0
- package/client/pages/auth-provider/auth-provider-management.ts +2 -0
- package/client/pages/domain/domain-management.ts +2 -0
- package/client/pages/user/user-management.ts +5 -5
- package/dist-client/auth-style-sign.js +29 -18
- package/dist-client/auth-style-sign.js.map +1 -1
- package/dist-client/components/abstract-auth-page.d.ts +4 -4
- package/dist-client/components/abstract-auth-page.js +40 -22
- package/dist-client/components/abstract-auth-page.js.map +1 -1
- package/dist-client/components/abstract-password-reset.d.ts +3 -2
- package/dist-client/components/abstract-password-reset.js +10 -9
- package/dist-client/components/abstract-password-reset.js.map +1 -1
- package/dist-client/components/abstract-sign.d.ts +3 -0
- package/dist-client/components/abstract-sign.js +110 -0
- package/dist-client/components/abstract-sign.js.map +1 -1
- package/dist-client/components/change-password.js +2 -2
- package/dist-client/components/change-password.js.map +1 -1
- package/dist-client/components/contact-us.d.ts +4 -4
- package/dist-client/components/contact-us.js +17 -16
- package/dist-client/components/contact-us.js.map +1 -1
- package/dist-client/components/create-domain-popup.d.ts +1 -1
- package/dist-client/components/create-domain-popup.js +11 -7
- package/dist-client/components/create-domain-popup.js.map +1 -1
- package/dist-client/components/create-role.d.ts +1 -1
- package/dist-client/components/create-role.js +7 -19
- package/dist-client/components/create-role.js.map +1 -1
- package/dist-client/components/create-user.js +6 -14
- package/dist-client/components/create-user.js.map +1 -1
- package/dist-client/components/credential-manager.d.ts +11 -0
- package/dist-client/components/credential-manager.js +64 -0
- package/dist-client/components/credential-manager.js.map +1 -0
- package/dist-client/components/invite-customer.js +5 -7
- package/dist-client/components/invite-customer.js.map +1 -1
- package/dist-client/components/invite-user.js +2 -7
- package/dist-client/components/invite-user.js.map +1 -1
- package/dist-client/components/ownership-transfer-popup.d.ts +1 -1
- package/dist-client/components/ownership-transfer-popup.js +3 -3
- package/dist-client/components/ownership-transfer-popup.js.map +1 -1
- package/dist-client/components/partner-role-editor.js +9 -15
- package/dist-client/components/partner-role-editor.js.map +1 -1
- package/dist-client/components/profile-component.d.ts +6 -0
- package/dist-client/components/profile-component.js +111 -7
- package/dist-client/components/profile-component.js.map +1 -1
- package/dist-client/components/role-privilege-editor.js +10 -17
- package/dist-client/components/role-privilege-editor.js.map +1 -1
- package/dist-client/components/user-role-editor.d.ts +2 -0
- package/dist-client/components/user-role-editor.js +26 -37
- package/dist-client/components/user-role-editor.js.map +1 -1
- package/dist-client/entries/auth/activate.d.ts +2 -1
- package/dist-client/entries/auth/activate.js +16 -17
- package/dist-client/entries/auth/activate.js.map +1 -1
- package/dist-client/entries/auth/checkin.d.ts +2 -2
- package/dist-client/entries/auth/checkin.js +13 -16
- package/dist-client/entries/auth/checkin.js.map +1 -1
- package/dist-client/entries/auth/forgot-password.d.ts +2 -1
- package/dist-client/entries/auth/forgot-password.js +7 -6
- package/dist-client/entries/auth/forgot-password.js.map +1 -1
- package/dist-client/entries/auth/result.d.ts +2 -2
- package/dist-client/entries/auth/result.js +12 -12
- package/dist-client/entries/auth/result.js.map +1 -1
- package/dist-client/entries/auth/signup.js +19 -24
- package/dist-client/entries/auth/signup.js.map +1 -1
- package/dist-client/entries/oauth2/oauth2-decision-error-page.d.ts +1 -1
- package/dist-client/entries/oauth2/oauth2-decision-error-page.js +2 -2
- package/dist-client/entries/oauth2/oauth2-decision-error-page.js.map +1 -1
- package/dist-client/entries/oauth2/oauth2-decision-page.d.ts +1 -1
- package/dist-client/entries/oauth2/oauth2-decision-page.js +59 -54
- package/dist-client/entries/oauth2/oauth2-decision-page.js.map +1 -1
- package/dist-client/entries/public/home.d.ts +3 -2
- package/dist-client/entries/public/home.js +40 -18
- package/dist-client/entries/public/home.js.map +1 -1
- package/dist-client/pages/app-binding/app-binding.d.ts +1 -1
- package/dist-client/pages/app-binding/app-binding.js +4 -9
- package/dist-client/pages/app-binding/app-binding.js.map +1 -1
- package/dist-client/pages/app-binding/app-bindings.js +2 -2
- package/dist-client/pages/app-binding/app-bindings.js.map +1 -1
- package/dist-client/pages/appliance/appliance.d.ts +1 -1
- package/dist-client/pages/appliance/appliance.js +5 -9
- package/dist-client/pages/appliance/appliance.js.map +1 -1
- package/dist-client/pages/appliance/home.js +3 -3
- package/dist-client/pages/appliance/home.js.map +1 -1
- package/dist-client/pages/appliance/register.js +1 -1
- package/dist-client/pages/appliance/register.js.map +1 -1
- package/dist-client/pages/application/application.js +26 -13
- package/dist-client/pages/application/application.js.map +1 -1
- package/dist-client/pages/application/applications.js +4 -12
- package/dist-client/pages/application/applications.js.map +1 -1
- package/dist-client/pages/application/register.js +1 -1
- package/dist-client/pages/application/register.js.map +1 -1
- package/dist-client/pages/attribute/attribute-set-management.d.ts +1 -0
- package/dist-client/pages/attribute/attribute-set-management.js +1 -0
- package/dist-client/pages/attribute/attribute-set-management.js.map +1 -1
- package/dist-client/pages/auth-provider/auth-provider-management.d.ts +1 -0
- package/dist-client/pages/auth-provider/auth-provider-management.js +1 -0
- package/dist-client/pages/auth-provider/auth-provider-management.js.map +1 -1
- package/dist-client/pages/domain/domain-management.d.ts +1 -0
- package/dist-client/pages/domain/domain-management.js +1 -0
- package/dist-client/pages/domain/domain-management.js.map +1 -1
- package/dist-client/pages/user/user-management.d.ts +1 -0
- package/dist-client/pages/user/user-management.js +4 -5
- package/dist-client/pages/user/user-management.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -10
- package/translations/en.json +1 -0
- package/translations/ja.json +1 -0
- package/translations/ko.json +1 -0
- package/translations/ms.json +1 -0
- package/translations/zh.json +1 -0
- package/views/auth-page.html +2 -2
- package/views/oauth2-page.html +3 -3
|
@@ -7,7 +7,7 @@ import { i18next } from '@operato/i18n'
|
|
|
7
7
|
class CreateUser extends LitElement {
|
|
8
8
|
static styles = css`
|
|
9
9
|
:host {
|
|
10
|
-
--
|
|
10
|
+
--md-text-field-fill-color: var(--theme-white-color);
|
|
11
11
|
background-color: var(--theme-white-color);
|
|
12
12
|
margin: var(--margin-wide) 0;
|
|
13
13
|
padding: var(--padding-wide);
|
|
@@ -23,7 +23,7 @@ class CreateUser extends LitElement {
|
|
|
23
23
|
align-items: center;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
md-outlined-button {
|
|
27
27
|
margin: var(--input-margin);
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -32,7 +32,7 @@ class CreateUser extends LitElement {
|
|
|
32
32
|
grid-template-columns: 1fr 1fr;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
md-outlined-button {
|
|
36
36
|
grid-column: span 2;
|
|
37
37
|
|
|
38
38
|
margin: var(--input-margin);
|
|
@@ -45,19 +45,11 @@ class CreateUser extends LitElement {
|
|
|
45
45
|
|
|
46
46
|
render() {
|
|
47
47
|
return html`
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
<mwc-textfield type="email" name="email" label=${String(i18next.t('field.email'))}></mwc-textfield>
|
|
55
|
-
|
|
56
|
-
<mwc-button
|
|
57
|
-
@click=${this.onCreateUser.bind(this)}
|
|
58
|
-
outlined
|
|
59
|
-
label=${String(i18next.t('button.create'))}
|
|
60
|
-
></mwc-button>
|
|
48
|
+
<md-outlined-text-field type="text" name="name" label=${String(i18next.t('label.x name', { x: i18next.t('label.user') }))}></md-outlined-text-field>
|
|
49
|
+
|
|
50
|
+
<md-outlined-text-field type="email" name="email" label=${String(i18next.t('field.email'))}></md-outlined-text-field>
|
|
51
|
+
|
|
52
|
+
<md-outlined-button @click=${this.onCreateUser.bind(this)}>${String(i18next.t('button.create'))}</md-outlined-button>
|
|
61
53
|
`
|
|
62
54
|
}
|
|
63
55
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import gql from 'graphql-tag'
|
|
2
|
+
import { LitElement, html, css } from 'lit'
|
|
3
|
+
import { customElement, property } from 'lit/decorators.js'
|
|
4
|
+
|
|
5
|
+
import { client } from '@operato/graphql'
|
|
6
|
+
|
|
7
|
+
@customElement('credential-manager')
|
|
8
|
+
export class CredentialManager extends LitElement {
|
|
9
|
+
@property({ type: Array }) credentials: {
|
|
10
|
+
credentialId: string
|
|
11
|
+
}[] = []
|
|
12
|
+
|
|
13
|
+
static styles = css`
|
|
14
|
+
div {
|
|
15
|
+
margin: 20px;
|
|
16
|
+
}
|
|
17
|
+
button {
|
|
18
|
+
margin: 5px;
|
|
19
|
+
}
|
|
20
|
+
`
|
|
21
|
+
|
|
22
|
+
connectedCallback() {
|
|
23
|
+
super.connectedCallback()
|
|
24
|
+
this.fetchCredentials()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async fetchCredentials() {
|
|
28
|
+
const response = await fetch('/auth/credentials', {
|
|
29
|
+
method: 'GET',
|
|
30
|
+
credentials: 'include'
|
|
31
|
+
})
|
|
32
|
+
this.credentials = await response.json()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async deleteCredential(credentialId: string) {
|
|
36
|
+
const response = await fetch(`/credentials/${credentialId}`, {
|
|
37
|
+
method: 'DELETE',
|
|
38
|
+
credentials: 'include'
|
|
39
|
+
})
|
|
40
|
+
if (response.ok) {
|
|
41
|
+
this.fetchCredentials()
|
|
42
|
+
} else {
|
|
43
|
+
console.error('Failed to delete credential')
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
render() {
|
|
48
|
+
return html`
|
|
49
|
+
<div>
|
|
50
|
+
<h2>Manage Your WebAuthn Credentials</h2>
|
|
51
|
+
<ul>
|
|
52
|
+
${this.credentials.map(
|
|
53
|
+
credential => html`
|
|
54
|
+
<li>
|
|
55
|
+
${credential.credentialId}
|
|
56
|
+
<button @click=${() => this.deleteCredential(credential.credentialId)}>Delete</button>
|
|
57
|
+
</li>
|
|
58
|
+
`
|
|
59
|
+
)}
|
|
60
|
+
</ul>
|
|
61
|
+
</div>
|
|
62
|
+
`
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -18,7 +18,7 @@ class InviteCustomer extends localize(i18next)(LitElement) {
|
|
|
18
18
|
min-width: 250px;
|
|
19
19
|
font: var(--input-font);
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
md-outlined-button {
|
|
22
22
|
margin: var(--input-margin);
|
|
23
23
|
}
|
|
24
24
|
@media screen and (max-width: 480px) {
|
|
@@ -37,25 +37,20 @@ class InviteCustomer extends localize(i18next)(LitElement) {
|
|
|
37
37
|
return html`
|
|
38
38
|
<div>
|
|
39
39
|
<input id="customer-name" required />
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
label=${String(i18next.t('label.invite customer'))}
|
|
45
|
-
></mwc-button>
|
|
40
|
+
<md-outlined-button @click=${this.invite.bind(this)}>
|
|
41
|
+
<md-icon slot="icon">group_add</md-icon>
|
|
42
|
+
${String(i18next.t('label.invite customer'))}
|
|
43
|
+
</md-outlined-button>
|
|
46
44
|
</div>
|
|
47
45
|
`
|
|
48
46
|
}
|
|
49
47
|
|
|
50
48
|
async invite() {
|
|
51
49
|
try {
|
|
52
|
-
if (!this.customerNameInput.value)
|
|
53
|
-
throw new Error(i18next.t('error.value is empty', { value: i18next.t('field.name') }))
|
|
50
|
+
if (!this.customerNameInput.value) throw new Error(i18next.t('error.value is empty', { value: i18next.t('field.name') }))
|
|
54
51
|
|
|
55
52
|
if (this.customers.find(c => c.name?.toLowerCase() === this.customerNameInput.value.toLowerCase())) {
|
|
56
|
-
throw new Error(
|
|
57
|
-
i18next.t('error.x already exists in y', { x: this.customerNameInput.value, y: i18next.t('field.customer') })
|
|
58
|
-
)
|
|
53
|
+
throw new Error(i18next.t('error.x already exists in y', { x: this.customerNameInput.value, y: i18next.t('field.customer') }))
|
|
59
54
|
}
|
|
60
55
|
|
|
61
56
|
if (
|
|
@@ -26,7 +26,7 @@ class InviteUser extends localize(i18next)(LitElement) {
|
|
|
26
26
|
font: var(--input-font);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
md-outlined-button {
|
|
30
30
|
margin: var(--input-margin);
|
|
31
31
|
}
|
|
32
32
|
`
|
|
@@ -36,12 +36,7 @@ class InviteUser extends localize(i18next)(LitElement) {
|
|
|
36
36
|
render() {
|
|
37
37
|
return html`
|
|
38
38
|
<input name="email" type="email" required name="invite-email" autocapitalize="off" />
|
|
39
|
-
<
|
|
40
|
-
@click=${this.invite.bind(this)}
|
|
41
|
-
outlined
|
|
42
|
-
icon="group_add"
|
|
43
|
-
label=${String(i18next.t('label.invite user'))}
|
|
44
|
-
></mwc-button>
|
|
39
|
+
<md-outlined-button @click=${this.invite.bind(this)}> <md-icon slot="icon">group_add</md-icon>${String(i18next.t('label.invite user'))} </md-outlined-button>
|
|
45
40
|
`
|
|
46
41
|
}
|
|
47
42
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import '@material/
|
|
1
|
+
import '@material/web/button/elevated-button.js'
|
|
2
2
|
|
|
3
3
|
import gql from 'graphql-tag'
|
|
4
4
|
import { css, html, LitElement } from 'lit'
|
|
@@ -36,7 +36,7 @@ class OwnershipTransferPopup extends localize(i18next)(LitElement) {
|
|
|
36
36
|
margin: auto;
|
|
37
37
|
display: flex;
|
|
38
38
|
}
|
|
39
|
-
.input-container
|
|
39
|
+
.input-container md-elevated-button {
|
|
40
40
|
margin: auto 0px auto var(--padding-wide);
|
|
41
41
|
}
|
|
42
42
|
`
|
|
@@ -52,7 +52,7 @@ class OwnershipTransferPopup extends localize(i18next)(LitElement) {
|
|
|
52
52
|
<div>${i18next.t('text.please enter the email of the user you want to transfer owner')}</div>
|
|
53
53
|
<div class="input-container">
|
|
54
54
|
<input name="email" />
|
|
55
|
-
<
|
|
55
|
+
<md-elevated-button @click=${this.transferOwnership}>${i18next.t('button.confirm')}</md-elevated-button>
|
|
56
56
|
</div>
|
|
57
57
|
</div>
|
|
58
58
|
`
|
|
@@ -8,12 +8,14 @@ import { customElement, property, query } from 'lit/decorators.js'
|
|
|
8
8
|
import { client, gqlContext } from '@operato/graphql'
|
|
9
9
|
import { i18next, localize } from '@operato/i18n'
|
|
10
10
|
import { OxPrompt } from '@operato/popup/ox-prompt.js'
|
|
11
|
+
import { ButtonContainerStyles } from '@operato/styles'
|
|
11
12
|
|
|
12
13
|
import { RoleSelector } from './role-selector'
|
|
13
14
|
|
|
14
15
|
@customElement('partner-role-editor')
|
|
15
16
|
class PartnerRoleEditor extends localize(i18next)(LitElement) {
|
|
16
17
|
static styles = [
|
|
18
|
+
ButtonContainerStyles,
|
|
17
19
|
css`
|
|
18
20
|
:host {
|
|
19
21
|
display: flex;
|
|
@@ -24,16 +26,13 @@ class PartnerRoleEditor extends localize(i18next)(LitElement) {
|
|
|
24
26
|
font: normal 15px var(--theme-font);
|
|
25
27
|
color: var(--secondary-color);
|
|
26
28
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
padding: var(--padding-default);
|
|
30
|
-
background-color: rgba(var(--primary-color-rgb), 0.2);
|
|
31
|
-
}
|
|
32
|
-
mwc-button {
|
|
29
|
+
|
|
30
|
+
md-elevated-button {
|
|
33
31
|
margin-right: var(--padding-narrow);
|
|
34
32
|
}
|
|
33
|
+
|
|
35
34
|
[danger] {
|
|
36
|
-
--
|
|
35
|
+
--md-theme-primary: var(--md-danger-button-primary-color);
|
|
37
36
|
}
|
|
38
37
|
`
|
|
39
38
|
]
|
|
@@ -51,14 +50,9 @@ class PartnerRoleEditor extends localize(i18next)(LitElement) {
|
|
|
51
50
|
return html`
|
|
52
51
|
<role-selector .roles="${roles}" .userRoles="${grantingRoles}"></role-selector>
|
|
53
52
|
|
|
54
|
-
<div
|
|
55
|
-
<
|
|
56
|
-
<
|
|
57
|
-
@click=${this.onTerminateContract}
|
|
58
|
-
raised
|
|
59
|
-
danger
|
|
60
|
-
label="${i18next.t('button.terminate contract')}"
|
|
61
|
-
></mwc-button>
|
|
53
|
+
<div class="button-container">
|
|
54
|
+
<md-elevated-button @click=${this.onSave}>${i18next.t('button.save')}</md-elevated-button>
|
|
55
|
+
<md-elevated-button @click=${this.onTerminateContract} danger>${i18next.t('button.terminate contract')}</md-elevated-button>
|
|
62
56
|
</div>
|
|
63
57
|
`
|
|
64
58
|
}
|
|
@@ -4,13 +4,15 @@ import './change-password'
|
|
|
4
4
|
import './delete-user-popup'
|
|
5
5
|
import './my-login-history'
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import base64url from 'base64url'
|
|
8
|
+
import { css, html, LitElement, nothing } from 'lit'
|
|
8
9
|
import { customElement, property, query, state } from 'lit/decorators.js'
|
|
9
10
|
|
|
10
11
|
import { i18next, localize } from '@operato/i18n'
|
|
11
12
|
import { notify, openPopup } from '@operato/layout'
|
|
12
13
|
import { auth, getLanguages } from '@things-factory/auth-base/dist-client'
|
|
13
14
|
|
|
15
|
+
const isAvailableWebauthn = 'PublicKeyCredential' in window
|
|
14
16
|
@customElement('profile-component')
|
|
15
17
|
export class ProfileComponent extends localize(i18next)(LitElement) {
|
|
16
18
|
static styles = [
|
|
@@ -36,12 +38,12 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
|
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
input {
|
|
39
|
-
margin: var(--
|
|
40
|
-
border:
|
|
41
|
-
padding:
|
|
41
|
+
margin: var(--margin-narrow) 0;
|
|
42
|
+
border: 1px solid rgba(0, 0, 0, 0.2);
|
|
43
|
+
padding: 9px;
|
|
42
44
|
border-radius: var(--border-radius);
|
|
43
|
-
font: var(--input-font);
|
|
44
|
-
width: var(--
|
|
45
|
+
font: var(--auth-input-field-font);
|
|
46
|
+
width: var(--auth-input-field-width);
|
|
45
47
|
}
|
|
46
48
|
input:focus {
|
|
47
49
|
border: 1px solid var(--focus-background-color);
|
|
@@ -85,7 +87,7 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
|
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
[danger] {
|
|
88
|
-
--
|
|
90
|
+
--md-theme-primary: var(--md-danger-button-primary-color);
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
footer {
|
|
@@ -160,6 +162,14 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
|
|
|
160
162
|
|
|
161
163
|
<change-password id="change-password"></change-password>
|
|
162
164
|
|
|
165
|
+
${isAvailableWebauthn
|
|
166
|
+
? html`
|
|
167
|
+
<md-text-button @click=${() => this.registerWebAuthn()}
|
|
168
|
+
>${i18next.t('button.security-key registration')}</md-text-button
|
|
169
|
+
>
|
|
170
|
+
`
|
|
171
|
+
: nothing}
|
|
172
|
+
|
|
163
173
|
<footer>
|
|
164
174
|
<p>
|
|
165
175
|
${i18next.t('text.click login history')}
|
|
@@ -233,4 +243,111 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
|
|
|
233
243
|
title: i18next.t('label.delete account')
|
|
234
244
|
})
|
|
235
245
|
}
|
|
246
|
+
|
|
247
|
+
async registerWebAuthn() {
|
|
248
|
+
const challenge = await fetch('/auth/register-webauthn/challenge', {
|
|
249
|
+
method: 'POST',
|
|
250
|
+
headers: {
|
|
251
|
+
'Content-Type': 'application/json',
|
|
252
|
+
Accept: 'application/json'
|
|
253
|
+
},
|
|
254
|
+
body: JSON.stringify({ email: this.email }),
|
|
255
|
+
credentials: 'include'
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
if (!challenge.ok) {
|
|
259
|
+
notify({
|
|
260
|
+
level: 'error',
|
|
261
|
+
message: await challenge.text()
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
return
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const options = await challenge.json()
|
|
268
|
+
|
|
269
|
+
const credential = (await navigator.credentials.create({
|
|
270
|
+
publicKey: {
|
|
271
|
+
rp: {
|
|
272
|
+
name: this.applicationMeta.title
|
|
273
|
+
},
|
|
274
|
+
user: {
|
|
275
|
+
/* options.user.id must be the user's email */
|
|
276
|
+
id: Uint8Array.from(base64url.toBuffer(options.user.id)).buffer,
|
|
277
|
+
name: options.user.name,
|
|
278
|
+
displayName: options.user.displayName
|
|
279
|
+
},
|
|
280
|
+
challenge: Uint8Array.from(atob(options.challenge), c => c.charCodeAt(0)),
|
|
281
|
+
pubKeyCredParams: [
|
|
282
|
+
{
|
|
283
|
+
type: 'public-key',
|
|
284
|
+
alg: -7 // ES256
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
type: 'public-key',
|
|
288
|
+
alg: -257 // RS256
|
|
289
|
+
}
|
|
290
|
+
],
|
|
291
|
+
authenticatorSelection: {
|
|
292
|
+
userVerification: 'preferred'
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
})) as PublicKeyCredential
|
|
296
|
+
|
|
297
|
+
if (!credential) {
|
|
298
|
+
notify({
|
|
299
|
+
level: 'error',
|
|
300
|
+
message: 'can not get user credential'
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
return
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const response = credential.response as AuthenticatorAttestationResponse
|
|
307
|
+
|
|
308
|
+
var body = {
|
|
309
|
+
response: {
|
|
310
|
+
clientDataJSON: Buffer.from(response.clientDataJSON).toString('base64'),
|
|
311
|
+
attestationObject: Buffer.from(response.attestationObject).toString('base64')
|
|
312
|
+
} as any
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (response.getTransports) {
|
|
316
|
+
body.response.transports = response.getTransports()
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const signinResponse = await fetch('/auth/signin-webauthn', {
|
|
320
|
+
method: 'POST',
|
|
321
|
+
headers: {
|
|
322
|
+
'Content-Type': 'application/json',
|
|
323
|
+
Accept: 'application/json'
|
|
324
|
+
},
|
|
325
|
+
body: JSON.stringify(body),
|
|
326
|
+
credentials: 'include'
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
if (!signinResponse.ok) {
|
|
330
|
+
notify({
|
|
331
|
+
level: 'error',
|
|
332
|
+
message: await signinResponse.text()
|
|
333
|
+
})
|
|
334
|
+
} else {
|
|
335
|
+
notify({
|
|
336
|
+
level: 'info',
|
|
337
|
+
message: i18next.t('text.user credential registered successfully')
|
|
338
|
+
})
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
get applicationMeta() {
|
|
343
|
+
var iconLink: HTMLLinkElement | null = document.querySelector('link[rel="application-icon"]')
|
|
344
|
+
var titleMeta: HTMLMetaElement | null = document.querySelector('meta[name="application-name"]')
|
|
345
|
+
var descriptionMeta: HTMLMetaElement | null = document.querySelector('meta[name="application-description"]')
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
icon: iconLink?.href || '',
|
|
349
|
+
title: titleMeta?.content || 'Things Factory',
|
|
350
|
+
description: descriptionMeta?.content || 'Reimagining Software'
|
|
351
|
+
}
|
|
352
|
+
}
|
|
236
353
|
}
|
|
@@ -5,10 +5,12 @@ import { customElement, property } from 'lit/decorators.js'
|
|
|
5
5
|
import { client, gqlContext } from '@operato/graphql'
|
|
6
6
|
import { i18next, localize } from '@operato/i18n'
|
|
7
7
|
import { OxPrompt } from '@operato/popup/ox-prompt.js'
|
|
8
|
+
import { ButtonContainerStyles } from '@operato/styles'
|
|
8
9
|
|
|
9
10
|
@customElement('role-privilege-editor')
|
|
10
11
|
class RolePrivilegeEditor extends localize(i18next)(LitElement) {
|
|
11
12
|
static styles = [
|
|
13
|
+
ButtonContainerStyles,
|
|
12
14
|
css`
|
|
13
15
|
:host {
|
|
14
16
|
display: flex;
|
|
@@ -49,21 +51,15 @@ class RolePrivilegeEditor extends localize(i18next)(LitElement) {
|
|
|
49
51
|
font-weight: bold;
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
margin: 0;
|
|
54
|
-
padding: 5px;
|
|
55
|
-
background-color: rgba(var(--primary-color-rgb), 0.2);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
mwc-button {
|
|
54
|
+
md-elevated-button {
|
|
59
55
|
margin: 5px;
|
|
60
56
|
background-color: var(--theme-white-color);
|
|
61
57
|
}
|
|
62
58
|
|
|
63
59
|
[danger] {
|
|
64
|
-
--
|
|
60
|
+
--md-theme-primary: var(--md-danger-button-primary-color);
|
|
65
61
|
}
|
|
66
|
-
|
|
62
|
+
md-outlined-button {
|
|
67
63
|
background-color: var(--theme-white-color);
|
|
68
64
|
}
|
|
69
65
|
|
|
@@ -106,14 +102,11 @@ class RolePrivilegeEditor extends localize(i18next)(LitElement) {
|
|
|
106
102
|
)}
|
|
107
103
|
</ul>
|
|
108
104
|
|
|
109
|
-
<div
|
|
110
|
-
<
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
danger
|
|
115
|
-
label=${String(i18next.t('button.delete role'))}
|
|
116
|
-
></mwc-button>
|
|
105
|
+
<div class="button-container">
|
|
106
|
+
<md-elevated-button @click=${e => this.onSave()}>${String(i18next.t('button.save'))}</md-elevated-button>
|
|
107
|
+
<md-elevated-button @click=${e => this.onDeleteRole()} danger
|
|
108
|
+
>${String(i18next.t('button.delete role'))}</md-elevated-button
|
|
109
|
+
>
|
|
117
110
|
</div>
|
|
118
111
|
`
|
|
119
112
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import '@material/web/icon/icon.js'
|
|
2
|
+
import '@material/web/button/elevated-button.js'
|
|
3
|
+
|
|
1
4
|
import './ownership-transfer-popup'
|
|
2
5
|
import './role-selector'
|
|
3
6
|
|
|
@@ -11,12 +14,13 @@ import { i18next } from '@operato/i18n'
|
|
|
11
14
|
import { openPopup } from '@operato/layout'
|
|
12
15
|
import { store } from '@operato/shell'
|
|
13
16
|
import { OxPrompt } from '@operato/popup/ox-prompt.js'
|
|
14
|
-
|
|
17
|
+
import { ButtonContainerStyles } from '@operato/styles'
|
|
15
18
|
import { RoleSelector } from './role-selector'
|
|
16
19
|
|
|
17
20
|
@customElement('user-role-editor')
|
|
18
21
|
class UserRoleEditor extends connect(store)(LitElement) {
|
|
19
22
|
static styles = [
|
|
23
|
+
ButtonContainerStyles,
|
|
20
24
|
css`
|
|
21
25
|
:host {
|
|
22
26
|
display: flex;
|
|
@@ -51,9 +55,9 @@ class UserRoleEditor extends connect(store)(LitElement) {
|
|
|
51
55
|
[detail] {
|
|
52
56
|
background-color: rgba(var(--primary-color-rgb), 0.05);
|
|
53
57
|
}
|
|
54
|
-
[detail]
|
|
58
|
+
[detail] md-icon {
|
|
59
|
+
--md-icon-size: var(--fontsize-default);
|
|
55
60
|
vertical-align: middle;
|
|
56
|
-
--mdc-icon-size: var(--fontsize-default);
|
|
57
61
|
color: var(--primary-color);
|
|
58
62
|
}
|
|
59
63
|
[detail] li {
|
|
@@ -63,20 +67,15 @@ class UserRoleEditor extends connect(store)(LitElement) {
|
|
|
63
67
|
flex: 1;
|
|
64
68
|
}
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
margin: 0;
|
|
68
|
-
padding: 5px;
|
|
69
|
-
background-color: rgba(var(--primary-color-rgb), 0.2);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
mwc-button {
|
|
70
|
+
md-elevated-button {
|
|
73
71
|
margin: 5px;
|
|
74
72
|
}
|
|
75
73
|
|
|
76
74
|
[danger] {
|
|
77
|
-
--
|
|
75
|
+
--md-theme-primary: var(--md-danger-button-primary-color);
|
|
78
76
|
}
|
|
79
|
-
|
|
77
|
+
|
|
78
|
+
md-outlined-button {
|
|
80
79
|
background-color: var(--theme-white-color);
|
|
81
80
|
}
|
|
82
81
|
|
|
@@ -117,7 +116,7 @@ class UserRoleEditor extends connect(store)(LitElement) {
|
|
|
117
116
|
? html`
|
|
118
117
|
<li>
|
|
119
118
|
<span>
|
|
120
|
-
<
|
|
119
|
+
<md-icon>email</md-icon>
|
|
121
120
|
${user.email}
|
|
122
121
|
</span>
|
|
123
122
|
</li>
|
|
@@ -141,10 +140,9 @@ class UserRoleEditor extends connect(store)(LitElement) {
|
|
|
141
140
|
`
|
|
142
141
|
: ''}
|
|
143
142
|
|
|
144
|
-
<div
|
|
143
|
+
<div class="button-container">
|
|
145
144
|
${this.isRoleEditable()
|
|
146
|
-
? html` <
|
|
147
|
-
raised
|
|
145
|
+
? html` <md-elevated-button
|
|
148
146
|
@click=${() => {
|
|
149
147
|
const { availableRoles, selectedRoles } = Array.from(
|
|
150
148
|
this.renderRoot.querySelectorAll('role-selector') as NodeListOf<RoleSelector>
|
|
@@ -169,46 +167,37 @@ class UserRoleEditor extends connect(store)(LitElement) {
|
|
|
169
167
|
)
|
|
170
168
|
this.onSave(user, availableRoles, selectedRoles)
|
|
171
169
|
}}
|
|
172
|
-
|
|
173
|
-
|
|
170
|
+
>${String(i18next.t('button.save'))}</md-elevated-button
|
|
171
|
+
>`
|
|
174
172
|
: ''}
|
|
175
173
|
${user.userType === 'user'
|
|
176
174
|
? html`
|
|
177
175
|
${this.isTransferable(user)
|
|
178
176
|
? html`
|
|
179
|
-
<
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
@click=${() => this.onTransfer(user)}
|
|
183
|
-
label=${String(i18next.t('button.transfer owner'))}
|
|
184
|
-
></mwc-button>
|
|
177
|
+
<md-elevated-button danger @click=${() => this.onTransfer(user)}
|
|
178
|
+
>${String(i18next.t('button.transfer owner'))}</md-elevated-button
|
|
179
|
+
>
|
|
185
180
|
`
|
|
186
181
|
: ''}
|
|
187
182
|
${this.isPasswordResettable(user)
|
|
188
|
-
? html`<
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
@click="${() => this.onResetPassword(user)}"
|
|
192
|
-
label=${String(i18next.t('title.reset password'))}
|
|
193
|
-
></mwc-button>`
|
|
183
|
+
? html`<md-elevated-button danger @click=${() => this.onResetPassword(user)}
|
|
184
|
+
>${String(i18next.t('title.reset password'))}</md-elevated-button
|
|
185
|
+
>`
|
|
194
186
|
: ''}
|
|
195
187
|
`
|
|
196
188
|
: ''}
|
|
197
189
|
${this.isRemovable(user)
|
|
198
190
|
? html`
|
|
199
|
-
<
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
label=${String(i18next.t('button.delete user'))}
|
|
203
|
-
@click=${() => this.onDelete(user)}
|
|
204
|
-
></mwc-button>
|
|
191
|
+
<md-elevated-button danger @click=${() => this.onDelete(user)}
|
|
192
|
+
>${String(i18next.t('button.delete user'))}</md-elevated-button
|
|
193
|
+
>
|
|
205
194
|
`
|
|
206
195
|
: ''}
|
|
207
196
|
${this.isActivatable(user)
|
|
208
|
-
? html`<
|
|
197
|
+
? html`<md-elevated-button danger @click=${() => this.onActivate(user)}>activate</md-elevated-button>`
|
|
209
198
|
: ''}
|
|
210
199
|
${this.isInactivatable(user)
|
|
211
|
-
? html`<
|
|
200
|
+
? html`<md-elevated-button danger @click=${() => this.onInactivate(user)}>inactivate</md-elevated-button>`
|
|
212
201
|
: ''}
|
|
213
202
|
</div>
|
|
214
203
|
`
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import '@material/
|
|
1
|
+
import '@material/web/icon/icon.js'
|
|
2
|
+
import '@material/web/button/elevated-button.js'
|
|
3
|
+
|
|
2
4
|
import '@operato/i18n/ox-i18n.js'
|
|
3
5
|
import '@operato/layout/ox-snack-bar.js'
|
|
4
6
|
import '@operato/lottie-player'
|
|
@@ -66,11 +68,11 @@ export class AuthActivate extends localize(i18next)(LitElement) {
|
|
|
66
68
|
padding-top: 10px;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
--
|
|
71
|
-
--
|
|
72
|
-
--
|
|
73
|
-
--
|
|
71
|
+
md-elevated-button {
|
|
72
|
+
--md-theme-primary: var(--auth-button-background-color);
|
|
73
|
+
--md-theme-on-primary: var(--primary-color);
|
|
74
|
+
--md-button-horizontal-padding: var(--padding-default);
|
|
75
|
+
--md-button-ink-color: var(--primary-color);
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
contact-us {
|
|
@@ -162,20 +164,18 @@ export class AuthActivate extends localize(i18next)(LitElement) {
|
|
|
162
164
|
</form>
|
|
163
165
|
|
|
164
166
|
<div id="button-area">
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
></mwc-button>
|
|
171
|
-
<mwc-button
|
|
172
|
-
raised
|
|
173
|
-
icon="home"
|
|
174
|
-
label=${i18next.t('button.go to home')}
|
|
167
|
+
<md-elevated-button @click=${e => this.requestResend(e)}>
|
|
168
|
+
<md-icon slot="icon">mail_outline</md-icon>
|
|
169
|
+
${i18next.t('label.send activation email')}
|
|
170
|
+
</md-elevated-button>
|
|
171
|
+
<md-elevated-button
|
|
175
172
|
@click=${e => {
|
|
176
173
|
window.location.replace('/auth/signin')
|
|
177
174
|
}}
|
|
178
|
-
|
|
175
|
+
>
|
|
176
|
+
<md-icon slot="icon">home</md-icon>
|
|
177
|
+
${i18next.t('button.go to home')}
|
|
178
|
+
</md-elevated-button>
|
|
179
179
|
</div>
|
|
180
180
|
<contact-us></contact-us>
|
|
181
181
|
|