@things-factory/auth-ui 7.0.1-alpha.10 → 7.0.1-alpha.100

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 (180) hide show
  1. package/client/auth-style-sign.ts +29 -18
  2. package/client/bootstrap.ts +6 -10
  3. package/client/components/abstract-auth-page.ts +41 -22
  4. package/client/components/abstract-password-reset.ts +11 -9
  5. package/client/components/abstract-sign.ts +138 -0
  6. package/client/components/change-password.ts +3 -3
  7. package/client/components/contact-us.ts +19 -23
  8. package/client/components/create-domain-popup.ts +12 -8
  9. package/client/components/create-role.ts +8 -20
  10. package/client/components/create-user.ts +8 -16
  11. package/client/components/credential-manager.ts +64 -0
  12. package/client/components/delete-user-popup.ts +1 -1
  13. package/client/components/domain-switch.ts +7 -4
  14. package/client/components/invite-customer.ts +7 -14
  15. package/client/components/invite-user.ts +2 -7
  16. package/client/components/my-login-history.ts +1 -1
  17. package/client/components/ownership-transfer-popup.ts +4 -4
  18. package/client/components/partner-role-editor.ts +11 -17
  19. package/client/components/profile-component.ts +127 -8
  20. package/client/components/role-privilege-editor.ts +10 -17
  21. package/client/components/user-role-editor.ts +27 -38
  22. package/client/entries/auth/activate.ts +17 -17
  23. package/client/entries/auth/checkin.ts +15 -19
  24. package/client/entries/auth/forgot-password.ts +8 -6
  25. package/client/entries/auth/result.ts +13 -12
  26. package/client/entries/auth/signup.ts +20 -24
  27. package/client/entries/oauth2/oauth2-decision-error-page.ts +2 -2
  28. package/client/entries/oauth2/oauth2-decision-page.ts +60 -55
  29. package/client/entries/public/home.ts +49 -25
  30. package/client/index.ts +93 -66
  31. package/client/pages/app-binding/app-binding.ts +4 -2
  32. package/client/pages/app-binding/app-bindings.ts +3 -3
  33. package/client/pages/appliance/appliance.ts +4 -2
  34. package/client/pages/appliance/home.ts +2 -2
  35. package/client/pages/appliance/register.ts +2 -2
  36. package/client/pages/application/application.ts +30 -51
  37. package/client/pages/application/applications.ts +6 -10
  38. package/client/pages/application/register.ts +2 -2
  39. package/client/pages/attribute/attribute-set-item-list.ts +8 -22
  40. package/client/pages/attribute/attribute-set-management.ts +14 -20
  41. package/client/pages/auth-provider/auth-provider-management.ts +10 -16
  42. package/client/pages/domain/domain-management.ts +4 -9
  43. package/client/pages/partner/partner-management.ts +1 -1
  44. package/client/pages/profile.ts +1 -1
  45. package/client/pages/role/role-management.ts +4 -5
  46. package/client/pages/user/user-management.ts +5 -3
  47. package/client/themes/auth-theme.css +1 -1
  48. package/dist-client/auth-style-sign.js +29 -18
  49. package/dist-client/auth-style-sign.js.map +1 -1
  50. package/dist-client/bootstrap.d.ts +1 -1
  51. package/dist-client/bootstrap.js +5 -5
  52. package/dist-client/bootstrap.js.map +1 -1
  53. package/dist-client/components/abstract-auth-page.d.ts +4 -4
  54. package/dist-client/components/abstract-auth-page.js +40 -22
  55. package/dist-client/components/abstract-auth-page.js.map +1 -1
  56. package/dist-client/components/abstract-password-reset.d.ts +3 -2
  57. package/dist-client/components/abstract-password-reset.js +10 -9
  58. package/dist-client/components/abstract-password-reset.js.map +1 -1
  59. package/dist-client/components/abstract-sign.d.ts +3 -0
  60. package/dist-client/components/abstract-sign.js +110 -0
  61. package/dist-client/components/abstract-sign.js.map +1 -1
  62. package/dist-client/components/change-password.js +3 -3
  63. package/dist-client/components/change-password.js.map +1 -1
  64. package/dist-client/components/contact-us.d.ts +4 -4
  65. package/dist-client/components/contact-us.js +18 -23
  66. package/dist-client/components/contact-us.js.map +1 -1
  67. package/dist-client/components/create-domain-popup.d.ts +1 -1
  68. package/dist-client/components/create-domain-popup.js +12 -8
  69. package/dist-client/components/create-domain-popup.js.map +1 -1
  70. package/dist-client/components/create-role.d.ts +1 -1
  71. package/dist-client/components/create-role.js +7 -19
  72. package/dist-client/components/create-role.js.map +1 -1
  73. package/dist-client/components/create-user.js +6 -14
  74. package/dist-client/components/create-user.js.map +1 -1
  75. package/dist-client/components/credential-manager.d.ts +11 -0
  76. package/dist-client/components/credential-manager.js +64 -0
  77. package/dist-client/components/credential-manager.js.map +1 -0
  78. package/dist-client/components/delete-user-popup.js +1 -1
  79. package/dist-client/components/delete-user-popup.js.map +1 -1
  80. package/dist-client/components/domain-switch.d.ts +2 -0
  81. package/dist-client/components/domain-switch.js +9 -4
  82. package/dist-client/components/domain-switch.js.map +1 -1
  83. package/dist-client/components/invite-customer.d.ts +1 -1
  84. package/dist-client/components/invite-customer.js +5 -8
  85. package/dist-client/components/invite-customer.js.map +1 -1
  86. package/dist-client/components/invite-user.js +2 -7
  87. package/dist-client/components/invite-user.js.map +1 -1
  88. package/dist-client/components/my-login-history.js +1 -1
  89. package/dist-client/components/my-login-history.js.map +1 -1
  90. package/dist-client/components/ownership-transfer-popup.d.ts +1 -1
  91. package/dist-client/components/ownership-transfer-popup.js +4 -4
  92. package/dist-client/components/ownership-transfer-popup.js.map +1 -1
  93. package/dist-client/components/partner-role-editor.d.ts +2 -2
  94. package/dist-client/components/partner-role-editor.js +11 -17
  95. package/dist-client/components/partner-role-editor.js.map +1 -1
  96. package/dist-client/components/profile-component.d.ts +7 -0
  97. package/dist-client/components/profile-component.js +117 -8
  98. package/dist-client/components/profile-component.js.map +1 -1
  99. package/dist-client/components/role-privilege-editor.js +10 -17
  100. package/dist-client/components/role-privilege-editor.js.map +1 -1
  101. package/dist-client/components/user-role-editor.d.ts +2 -0
  102. package/dist-client/components/user-role-editor.js +26 -37
  103. package/dist-client/components/user-role-editor.js.map +1 -1
  104. package/dist-client/entries/auth/activate.d.ts +2 -1
  105. package/dist-client/entries/auth/activate.js +16 -17
  106. package/dist-client/entries/auth/activate.js.map +1 -1
  107. package/dist-client/entries/auth/checkin.d.ts +2 -2
  108. package/dist-client/entries/auth/checkin.js +13 -16
  109. package/dist-client/entries/auth/checkin.js.map +1 -1
  110. package/dist-client/entries/auth/forgot-password.d.ts +2 -1
  111. package/dist-client/entries/auth/forgot-password.js +7 -6
  112. package/dist-client/entries/auth/forgot-password.js.map +1 -1
  113. package/dist-client/entries/auth/result.d.ts +2 -2
  114. package/dist-client/entries/auth/result.js +12 -12
  115. package/dist-client/entries/auth/result.js.map +1 -1
  116. package/dist-client/entries/auth/signup.js +19 -24
  117. package/dist-client/entries/auth/signup.js.map +1 -1
  118. package/dist-client/entries/oauth2/oauth2-decision-error-page.d.ts +1 -1
  119. package/dist-client/entries/oauth2/oauth2-decision-error-page.js +2 -2
  120. package/dist-client/entries/oauth2/oauth2-decision-error-page.js.map +1 -1
  121. package/dist-client/entries/oauth2/oauth2-decision-page.d.ts +1 -1
  122. package/dist-client/entries/oauth2/oauth2-decision-page.js +59 -54
  123. package/dist-client/entries/oauth2/oauth2-decision-page.js.map +1 -1
  124. package/dist-client/entries/public/home.d.ts +3 -2
  125. package/dist-client/entries/public/home.js +49 -25
  126. package/dist-client/entries/public/home.js.map +1 -1
  127. package/dist-client/index.d.ts +11 -2
  128. package/dist-client/index.js +74 -66
  129. package/dist-client/index.js.map +1 -1
  130. package/dist-client/pages/app-binding/app-binding.d.ts +1 -1
  131. package/dist-client/pages/app-binding/app-binding.js +3 -2
  132. package/dist-client/pages/app-binding/app-binding.js.map +1 -1
  133. package/dist-client/pages/app-binding/app-bindings.js +3 -3
  134. package/dist-client/pages/app-binding/app-bindings.js.map +1 -1
  135. package/dist-client/pages/appliance/appliance.d.ts +1 -1
  136. package/dist-client/pages/appliance/appliance.js +3 -2
  137. package/dist-client/pages/appliance/appliance.js.map +1 -1
  138. package/dist-client/pages/appliance/home.js +2 -2
  139. package/dist-client/pages/appliance/home.js.map +1 -1
  140. package/dist-client/pages/appliance/register.js +2 -2
  141. package/dist-client/pages/appliance/register.js.map +1 -1
  142. package/dist-client/pages/application/application.d.ts +1 -1
  143. package/dist-client/pages/application/application.js +29 -51
  144. package/dist-client/pages/application/application.js.map +1 -1
  145. package/dist-client/pages/application/applications.js +6 -10
  146. package/dist-client/pages/application/applications.js.map +1 -1
  147. package/dist-client/pages/application/register.js +2 -2
  148. package/dist-client/pages/application/register.js.map +1 -1
  149. package/dist-client/pages/attribute/attribute-set-item-list.d.ts +1 -1
  150. package/dist-client/pages/attribute/attribute-set-item-list.js +6 -22
  151. package/dist-client/pages/attribute/attribute-set-item-list.js.map +1 -1
  152. package/dist-client/pages/attribute/attribute-set-management.d.ts +11 -2
  153. package/dist-client/pages/attribute/attribute-set-management.js +7 -11
  154. package/dist-client/pages/attribute/attribute-set-management.js.map +1 -1
  155. package/dist-client/pages/auth-provider/auth-provider-management.d.ts +11 -2
  156. package/dist-client/pages/auth-provider/auth-provider-management.js +8 -11
  157. package/dist-client/pages/auth-provider/auth-provider-management.js.map +1 -1
  158. package/dist-client/pages/domain/domain-management.d.ts +1 -0
  159. package/dist-client/pages/domain/domain-management.js +3 -7
  160. package/dist-client/pages/domain/domain-management.js.map +1 -1
  161. package/dist-client/pages/partner/partner-management.js +1 -1
  162. package/dist-client/pages/partner/partner-management.js.map +1 -1
  163. package/dist-client/pages/profile.js +1 -1
  164. package/dist-client/pages/profile.js.map +1 -1
  165. package/dist-client/pages/role/role-management.js +3 -3
  166. package/dist-client/pages/role/role-management.js.map +1 -1
  167. package/dist-client/pages/user/user-management.d.ts +1 -0
  168. package/dist-client/pages/user/user-management.js +4 -3
  169. package/dist-client/pages/user/user-management.js.map +1 -1
  170. package/dist-client/themes/auth-theme.css +1 -1
  171. package/dist-client/tsconfig.tsbuildinfo +1 -1
  172. package/dist-server/tsconfig.tsbuildinfo +1 -1
  173. package/package.json +8 -12
  174. package/translations/en.json +1 -0
  175. package/translations/ja.json +1 -0
  176. package/translations/ko.json +1 -0
  177. package/translations/ms.json +1 -0
  178. package/translations/zh.json +1 -0
  179. package/views/auth-page.html +3 -2
  180. package/views/oauth2-page.html +3 -2
@@ -1,4 +1,4 @@
1
- import '@material/mwc-textfield'
1
+ import '@material/web/textfield/filled-text-field.js'
2
2
 
3
3
  import gql from 'graphql-tag'
4
4
  import { css, html, LitElement } from 'lit'
@@ -12,7 +12,7 @@ import { OxPrompt } from '@operato/popup/ox-prompt.js'
12
12
  class CreateRole extends localize(i18next)(LitElement) {
13
13
  static styles = css`
14
14
  :host {
15
- --mdc-text-field-fill-color: var(--theme-white-color);
15
+ --md-text-field-fill-color: var(--theme-white-color);
16
16
  background-color: var(--theme-white-color);
17
17
  margin: var(--margin-wide) 0;
18
18
  padding: var(--padding-wide);
@@ -28,7 +28,7 @@ class CreateRole extends localize(i18next)(LitElement) {
28
28
  align-items: center;
29
29
  }
30
30
 
31
- mwc-button {
31
+ md-outlined-button {
32
32
  margin: var(--input-margin);
33
33
  }
34
34
 
@@ -37,7 +37,7 @@ class CreateRole extends localize(i18next)(LitElement) {
37
37
  grid-template-columns: 1fr 1fr;
38
38
  }
39
39
 
40
- mwc-button {
40
+ md-outlined-button {
41
41
  grid-column: span 2;
42
42
 
43
43
  margin: var(--input-margin);
@@ -50,22 +50,10 @@ class CreateRole extends localize(i18next)(LitElement) {
50
50
 
51
51
  render() {
52
52
  return html`
53
- <mwc-textfield
54
- type="text"
55
- name="name"
56
- label=${String(i18next.t('label.x name', { x: i18next.t('label.role') }))}
57
- ></mwc-textfield>
58
- <mwc-textfield
59
- type="text"
60
- name="description"
61
- label=${String(i18next.t('label.x description', { x: i18next.t('label.role') }))}
62
- ></mwc-textfield>
63
-
64
- <mwc-button
65
- @click=${this.onCreateRole.bind(this)}
66
- outlined
67
- label=${String(i18next.t('button.create'))}
68
- ></mwc-button>
53
+ <md-filled-text-field type="text" name="name" label=${String(i18next.t('label.x name', { x: i18next.t('label.role') }))}></md-filled-text-field>
54
+ <md-filled-text-field type="text" name="description" label=${String(i18next.t('label.x description', { x: i18next.t('label.role') }))}></md-filled-text-field>
55
+
56
+ <md-outlined-button @click=${this.onCreateRole.bind(this)}>${String(i18next.t('button.create'))}</md-outlined-button>
69
57
  `
70
58
  }
71
59
 
@@ -7,7 +7,7 @@ import { i18next } from '@operato/i18n'
7
7
  class CreateUser extends LitElement {
8
8
  static styles = css`
9
9
  :host {
10
- --mdc-text-field-fill-color: var(--theme-white-color);
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
- mwc-button {
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
- mwc-button {
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
- <mwc-textfield
49
- type="text"
50
- name="name"
51
- label=${String(i18next.t('label.x name', { x: i18next.t('label.user') }))}
52
- ></mwc-textfield>
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
+ }
@@ -5,7 +5,7 @@ import { customElement } from 'lit/decorators.js'
5
5
 
6
6
  import { i18next, localize } from '@operato/i18n'
7
7
  import { notify } from '@operato/layout'
8
- import { auth } from '@things-factory/auth-base/dist-client'
8
+ import { auth } from '@things-factory/auth-base/dist-client/auth.js'
9
9
 
10
10
  @customElement('delete-user-popup')
11
11
  export class DeleteUserPopup extends localize(i18next)(LitElement) {
@@ -1,4 +1,6 @@
1
- import { css, html, LitElement } from 'lit'
1
+ import '@material/web/icon/icon.js'
2
+
3
+ import { css, html, LitElement, nothing } from 'lit'
2
4
  import { customElement, property } from 'lit/decorators.js'
3
5
  import { connect } from 'pwa-helpers/connect-mixin'
4
6
 
@@ -28,7 +30,7 @@ export class DomainSwitch extends connect(store)(LitElement) {
28
30
  padding: var(--padding-default);
29
31
  }
30
32
 
31
- mwc-icon {
33
+ md-icon {
32
34
  background-color: rgba(var(--primary-color-rgb), 0.8);
33
35
  margin-right: var(--margin-narrow);
34
36
  padding: 2px;
@@ -56,7 +58,7 @@ export class DomainSwitch extends connect(store)(LitElement) {
56
58
  padding: 0 !important;
57
59
  border-bottom: none;
58
60
  }
59
- :host([dark]) mwc-icon {
61
+ :host([dark]) md-icon {
60
62
  background-color: var(--secondary-text-color);
61
63
  margin: 1px 4px 0px 0px;
62
64
  padding: 1px 2px;
@@ -90,6 +92,7 @@ export class DomainSwitch extends connect(store)(LitElement) {
90
92
  @property({ type: Array }) domains: any[] = []
91
93
  @property({ type: Object }) domain: any
92
94
  @property({ type: String, attribute: true }) attrname: string = 'name'
95
+ @property({ type: String, attribute: true }) icon?: string
93
96
 
94
97
  render() {
95
98
  const domains = this.domains || []
@@ -98,7 +101,7 @@ export class DomainSwitch extends connect(store)(LitElement) {
98
101
 
99
102
  return html`
100
103
  <div>
101
- <mwc-icon>outlined_flag</mwc-icon>
104
+ ${this.icon ? html`<md-icon>${this.icon}</md-icon>` : nothing}
102
105
  ${domains.length <= 1
103
106
  ? html` <span>${domains[0]?.[attrname] || domain.name}</span> `
104
107
  : html`
@@ -1,5 +1,3 @@
1
- import '@things-factory/auth-ui'
2
-
3
1
  import gql from 'graphql-tag'
4
2
  import { css, html, LitElement } from 'lit'
5
3
  import { customElement, property, query } from 'lit/decorators.js'
@@ -20,7 +18,7 @@ class InviteCustomer extends localize(i18next)(LitElement) {
20
18
  min-width: 250px;
21
19
  font: var(--input-font);
22
20
  }
23
- mwc-button {
21
+ md-outlined-button {
24
22
  margin: var(--input-margin);
25
23
  }
26
24
  @media screen and (max-width: 480px) {
@@ -39,25 +37,20 @@ class InviteCustomer extends localize(i18next)(LitElement) {
39
37
  return html`
40
38
  <div>
41
39
  <input id="customer-name" required />
42
- <mwc-button
43
- @click=${this.invite.bind(this)}
44
- outlined
45
- icon="group_add"
46
- label=${String(i18next.t('label.invite customer'))}
47
- ></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>
48
44
  </div>
49
45
  `
50
46
  }
51
47
 
52
48
  async invite() {
53
49
  try {
54
- if (!this.customerNameInput.value)
55
- 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') }))
56
51
 
57
52
  if (this.customers.find(c => c.name?.toLowerCase() === this.customerNameInput.value.toLowerCase())) {
58
- throw new Error(
59
- i18next.t('error.x already exists in y', { x: this.customerNameInput.value, y: i18next.t('field.customer') })
60
- )
53
+ throw new Error(i18next.t('error.x already exists in y', { x: this.customerNameInput.value, y: i18next.t('field.customer') }))
61
54
  }
62
55
 
63
56
  if (
@@ -26,7 +26,7 @@ class InviteUser extends localize(i18next)(LitElement) {
26
26
  font: var(--input-font);
27
27
  }
28
28
 
29
- mwc-button {
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
- <mwc-button
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
 
@@ -14,7 +14,7 @@ class MyLoginHistory extends LitElement {
14
14
  :host {
15
15
  display: flex;
16
16
  flex-direction: column;
17
- background-color: var(--main-section-background-color);
17
+ background-color: var(--md-sys-color-background);
18
18
  padding: var(--padding-wide);
19
19
  overflow: auto;
20
20
  }
@@ -1,4 +1,4 @@
1
- import '@material/mwc-button'
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'
@@ -15,7 +15,7 @@ class OwnershipTransferPopup extends localize(i18next)(LitElement) {
15
15
  :host {
16
16
  display: flex;
17
17
  flex-direction: column;
18
- background-color: var(--main-section-background-color);
18
+ background-color: var(--md-sys-color-background);
19
19
  padding: var(--padding-wide);
20
20
  overflow: auto;
21
21
  }
@@ -36,7 +36,7 @@ class OwnershipTransferPopup extends localize(i18next)(LitElement) {
36
36
  margin: auto;
37
37
  display: flex;
38
38
  }
39
- .input-container mwc-button {
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
- <mwc-button raised @click=${this.transferOwnership}>${i18next.t('button.confirm')}</mwc-button>
55
+ <md-elevated-button @click=${this.transferOwnership}>${i18next.t('button.confirm')}</md-elevated-button>
56
56
  </div>
57
57
  </div>
58
58
  `
@@ -1,5 +1,5 @@
1
- import '@material/mwc-icon'
2
- import '@things-factory/auth-ui'
1
+ import '@material/web/button/elevated-button.js'
2
+ import './role-selector.js'
3
3
 
4
4
  import gql from 'graphql-tag'
5
5
  import { css, html, LitElement } from 'lit'
@@ -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
- [buttons] {
28
- margin: 0;
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
- --mdc-theme-primary: var(--mdc-danger-button-primary-color);
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 buttons>
55
- <mwc-button @click=${this.onSave} raised label="${i18next.t('button.save')}"></mwc-button>
56
- <mwc-button
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,20 +4,22 @@ import './change-password'
4
4
  import './delete-user-popup'
5
5
  import './my-login-history'
6
6
 
7
- import { css, html, LitElement } from 'lit'
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 = [
17
19
  css`
18
20
  :host {
19
21
  display: block;
20
- background-color: var(--main-section-background-color);
22
+ background-color: var(--md-sys-color-background);
21
23
  padding: 15px 0;
22
24
  }
23
25
  .wrap {
@@ -36,12 +38,12 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
36
38
  }
37
39
 
38
40
  input {
39
- margin: var(--change-password-field-margin);
40
- border: var(--input-field-border);
41
- padding: var(--input-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(--change-password-field-width);
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
- --mdc-theme-primary: var(--mdc-danger-button-primary-color);
90
+ --md-theme-primary: var(--md-danger-button-primary-color);
89
91
  }
90
92
 
91
93
  footer {
@@ -106,6 +108,7 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
106
108
  `
107
109
  ]
108
110
 
111
+ @property({ type: String }) userId?: string
109
112
  @property({ type: String }) email?: string
110
113
  @property({ type: String }) name?: string
111
114
 
@@ -126,9 +129,11 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
126
129
 
127
130
  setCredential(credential) {
128
131
  if (credential) {
132
+ this.userId = credential.id
129
133
  this.name = credential.name
130
134
  this.email = credential.email
131
135
  } else {
136
+ this.userId = ''
132
137
  this.name = ''
133
138
  this.email = ''
134
139
  }
@@ -160,6 +165,14 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
160
165
 
161
166
  <change-password id="change-password"></change-password>
162
167
 
168
+ ${isAvailableWebauthn
169
+ ? html`
170
+ <md-text-button @click=${() => this.registerWebAuthn()}
171
+ >${i18next.t('button.security-key registration')}</md-text-button
172
+ >
173
+ `
174
+ : nothing}
175
+
163
176
  <footer>
164
177
  <p>
165
178
  ${i18next.t('text.click login history')}
@@ -233,4 +246,110 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
233
246
  title: i18next.t('label.delete account')
234
247
  })
235
248
  }
249
+
250
+ async registerWebAuthn() {
251
+ const challenge = await fetch('/auth/register-webauthn/challenge', {
252
+ method: 'POST',
253
+ headers: {
254
+ 'Content-Type': 'application/json',
255
+ Accept: 'application/json'
256
+ },
257
+ body: JSON.stringify({ id: this.userId }),
258
+ credentials: 'include'
259
+ })
260
+
261
+ if (!challenge.ok) {
262
+ notify({
263
+ level: 'error',
264
+ message: await challenge.text()
265
+ })
266
+
267
+ return
268
+ }
269
+
270
+ const options = await challenge.json()
271
+
272
+ const credential = (await navigator.credentials.create({
273
+ publicKey: {
274
+ rp: {
275
+ name: this.applicationMeta.title
276
+ },
277
+ user: {
278
+ id: Uint8Array.from(base64url.toBuffer(options.user.id)).buffer,
279
+ name: options.user.name,
280
+ displayName: options.user.displayName
281
+ },
282
+ challenge: Uint8Array.from(atob(options.challenge), c => c.charCodeAt(0)),
283
+ pubKeyCredParams: [
284
+ {
285
+ type: 'public-key',
286
+ alg: -7 // ES256
287
+ },
288
+ {
289
+ type: 'public-key',
290
+ alg: -257 // RS256
291
+ }
292
+ ],
293
+ authenticatorSelection: {
294
+ userVerification: 'preferred'
295
+ }
296
+ }
297
+ })) as PublicKeyCredential
298
+
299
+ if (!credential) {
300
+ notify({
301
+ level: 'error',
302
+ message: 'can not get user credential'
303
+ })
304
+
305
+ return
306
+ }
307
+
308
+ const response = credential.response as AuthenticatorAttestationResponse
309
+
310
+ var body = {
311
+ response: {
312
+ clientDataJSON: Buffer.from(response.clientDataJSON).toString('base64'),
313
+ attestationObject: Buffer.from(response.attestationObject).toString('base64')
314
+ } as any
315
+ }
316
+
317
+ if (response.getTransports) {
318
+ body.response.transports = response.getTransports()
319
+ }
320
+
321
+ const signinResponse = await fetch('/auth/signin-webauthn', {
322
+ method: 'POST',
323
+ headers: {
324
+ 'Content-Type': 'application/json',
325
+ Accept: 'application/json'
326
+ },
327
+ body: JSON.stringify(body),
328
+ credentials: 'include'
329
+ })
330
+
331
+ if (!signinResponse.ok) {
332
+ notify({
333
+ level: 'error',
334
+ message: await signinResponse.text()
335
+ })
336
+ } else {
337
+ notify({
338
+ level: 'info',
339
+ message: i18next.t('text.user credential registered successfully')
340
+ })
341
+ }
342
+ }
343
+
344
+ get applicationMeta() {
345
+ var iconLink: HTMLLinkElement | null = document.querySelector('link[rel="application-icon"]')
346
+ var titleMeta: HTMLMetaElement | null = document.querySelector('meta[name="application-name"]')
347
+ var descriptionMeta: HTMLMetaElement | null = document.querySelector('meta[name="application-description"]')
348
+
349
+ return {
350
+ icon: iconLink?.href || '',
351
+ title: titleMeta?.content || 'Things Factory',
352
+ description: descriptionMeta?.content || 'Reimagining Software'
353
+ }
354
+ }
236
355
  }
@@ -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
- [buttons] {
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
- --mdc-theme-primary: var(--mdc-danger-button-primary-color);
60
+ --md-theme-primary: var(--md-danger-button-primary-color);
65
61
  }
66
- [outlined] {
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 buttons>
110
- <mwc-button @click=${e => this.onSave()} outlined label=${String(i18next.t('button.save'))}></mwc-button>
111
- <mwc-button
112
- @click=${e => this.onDeleteRole()}
113
- raised
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
  }