@wral/studio.mods.auth 0.3.7 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -47
- package/bitbucket-pipelines.yml +25 -1
- package/dist/auth.cjs.js +326 -1467
- package/dist/auth.es.js +1081 -3093
- package/dist/lib.cjs.js +1 -1
- package/dist/lib.es.js +13 -7
- package/eslint.config.mjs +41 -34
- package/index.html +83 -18
- package/jest.config.mjs +24 -0
- package/jest.setup.mjs +5 -0
- package/package.json +15 -28
- package/src/auth.mjs +204 -69
- package/src/auth.test.mjs +97 -0
- package/src/components/auth-app.mjs +26 -0
- package/src/components/forgot-password-form.mjs +217 -0
- package/src/components/login-form.mjs +288 -0
- package/src/config.mjs +27 -0
- package/src/helper.mjs +31 -0
- package/src/helper.test.mjs +44 -0
- package/src/index.mjs +17 -0
- package/src/login-layout.mjs +32 -0
- package/src/login.mjs +20 -0
- package/src/routes/change-password.mjs +158 -0
- package/src/routes/dashboard.mjs +17 -0
- package/src/routes/index.mjs +15 -0
- package/src/state.mjs +61 -0
- package/src/state.test.mjs +58 -0
- package/src/styles.mjs +9 -0
- package/src/token.mjs +40 -0
- package/src/utils.mjs +3 -0
- package/vellum-fixture.mjs +86 -0
- package/vite.config.mjs +12 -0
- package/components.html +0 -43
- package/development.md +0 -41
- package/src/components/mod-auth-login-form.mjs +0 -133
- package/src/components/studio-change-password.mjs +0 -84
- package/src/components/studio-login.mjs +0 -94
- package/src/components/studio-profile-view.mjs +0 -56
- package/src/components/studio-reset-password.mjs +0 -110
- package/src/lib.mjs +0 -16
- package/src/tool-dummy.mjs +0 -84
- package/src/util.mjs +0 -194
- package/src/util.test.mjs +0 -171
- package/vite.config.js +0 -12
- package/web-test-runner.config.mjs +0 -28
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { LitElement, html, css } from 'lit';
|
|
2
|
-
import { createClient } from '@wral/sdk-auth';
|
|
3
|
-
import './studio-login.mjs';
|
|
4
|
-
import './studio-change-password.mjs';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* This is a login form for the auth module. It consumes the generic
|
|
8
|
-
* studio-login component.
|
|
9
|
-
*
|
|
10
|
-
* This component is responsible for sending requests to the auth API
|
|
11
|
-
* to generate a JWT token, and for enforcing a password change flow.
|
|
12
|
-
*
|
|
13
|
-
* @attribute apibaseurl
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* <mod-auth-login-form
|
|
17
|
-
* apibaseurl="https://api.wral.com/auth"
|
|
18
|
-
* @login-success=${({ detail }) => console.log(detail.token)}
|
|
19
|
-
* >
|
|
20
|
-
* </mod-auth-login-form>
|
|
21
|
-
*
|
|
22
|
-
* @fires login-success
|
|
23
|
-
*/
|
|
24
|
-
class ModAuthLoginForm extends LitElement {
|
|
25
|
-
|
|
26
|
-
constructor() {
|
|
27
|
-
super();
|
|
28
|
-
this.apibaseurl = '';
|
|
29
|
-
this.error = '';
|
|
30
|
-
this.isAwaiting = false;
|
|
31
|
-
this.lastResult = undefined;
|
|
32
|
-
this.forceChangePassword = false;
|
|
33
|
-
this.handleLogin = this.handleLogin.bind(this);
|
|
34
|
-
this.handleLoginResult = this.handleLoginResult.bind(this);
|
|
35
|
-
this.handleLoginError = this.handleLoginError.bind(this);
|
|
36
|
-
this.renderPasswordChangeForm = this.renderPasswordChangeForm.bind(this);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
static properties = {
|
|
40
|
-
apibaseurl: { type: String },
|
|
41
|
-
error: { type: String },
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
static styles = css`
|
|
45
|
-
:host {
|
|
46
|
-
display: block;
|
|
47
|
-
max-width: 400px;
|
|
48
|
-
margin: 0 auto;
|
|
49
|
-
}
|
|
50
|
-
`;
|
|
51
|
-
|
|
52
|
-
handleLogin(event) {
|
|
53
|
-
this.isAwaiting = true;
|
|
54
|
-
const { username, password } = event.detail;
|
|
55
|
-
const client = createClient({ baseUrl: this.apibaseurl });
|
|
56
|
-
this.requestUpdate();
|
|
57
|
-
client.mintToken({ username, password })
|
|
58
|
-
.then(this.handleLoginResult)
|
|
59
|
-
.catch(this.handleLoginError);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
handleLoginResult(result) {
|
|
63
|
-
this.error = '';
|
|
64
|
-
this.isAwaiting = false;
|
|
65
|
-
this.lastResult = result;
|
|
66
|
-
if (result.challenge?.name === 'NEW_PASSWORD_REQUIRED') {
|
|
67
|
-
this.forceChangePassword = true;
|
|
68
|
-
this.error = 'You must set a new password to continue.';
|
|
69
|
-
} else {
|
|
70
|
-
this.dispatchEvent(new CustomEvent('login-success', { detail: result }));
|
|
71
|
-
}
|
|
72
|
-
this.requestUpdate();
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
handleLoginError(error) {
|
|
76
|
-
// Debugging login errors is a high priority
|
|
77
|
-
/* eslint-disable no-console */
|
|
78
|
-
console.error("Error logging in:", error);
|
|
79
|
-
this.error = error?.body?.error?.message || 'Invalid username or password';
|
|
80
|
-
this.isAwaiting = false;
|
|
81
|
-
this.requestUpdate();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
handleChangePassword(event) {
|
|
85
|
-
const { currentPassword, newPassword } = event.detail;
|
|
86
|
-
const { token } = this.lastResult;
|
|
87
|
-
const client = createClient({ baseUrl: this.apibaseurl });
|
|
88
|
-
this.requestUpdate();
|
|
89
|
-
client.updatePassword({ token, currentPassword, newPassword })
|
|
90
|
-
.then(() => {
|
|
91
|
-
this.forceChangePassword = false;
|
|
92
|
-
this.error = 'Login with your new password.';
|
|
93
|
-
this.isAwaiting = false;
|
|
94
|
-
this.requestUpdate();
|
|
95
|
-
})
|
|
96
|
-
.catch((error) => {
|
|
97
|
-
this.error = error?.body?.error?.message || error.message;
|
|
98
|
-
this.isAwaiting = false;
|
|
99
|
-
this.requestUpdate();
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
renderPasswordChangeForm() {
|
|
104
|
-
return html`
|
|
105
|
-
<div>
|
|
106
|
-
${this.error ? html`<div class="error">${this.error}</div>` : null}
|
|
107
|
-
<studio-change-password @change-password=${this.handleChangePassword}>
|
|
108
|
-
</studio-change-password>
|
|
109
|
-
</div>
|
|
110
|
-
`;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
renderLoginForm() {
|
|
114
|
-
return html`
|
|
115
|
-
${this.error ? html`<div class="error">${this.error}</div>` : null}
|
|
116
|
-
<studio-login
|
|
117
|
-
@login-attempt=${this.handleLogin}
|
|
118
|
-
?disabled=${this.isAwaiting}
|
|
119
|
-
></studio-login>
|
|
120
|
-
`;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
render() {
|
|
124
|
-
// TODO: handle resets with a route
|
|
125
|
-
if (this.forceChangePassword) {
|
|
126
|
-
return this.renderPasswordChangeForm();
|
|
127
|
-
} else {
|
|
128
|
-
return this.renderLoginForm();
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
window.customElements.define('mod-auth-login-form', ModAuthLoginForm);
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { LitElement, html, css } from 'lit';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Describes a generic change password form.
|
|
5
|
-
*
|
|
6
|
-
* @attribute currentPassword - The current password
|
|
7
|
-
* @attribute newPassword - The new password
|
|
8
|
-
* @attribute confirmPassword - The new password confirmation
|
|
9
|
-
*
|
|
10
|
-
* @fires change-password - Fired when the user submits the change password form
|
|
11
|
-
*/
|
|
12
|
-
class StudioChangePassword extends LitElement {
|
|
13
|
-
static styles = css`
|
|
14
|
-
:host {
|
|
15
|
-
display: block;
|
|
16
|
-
box-sizing: border-box;
|
|
17
|
-
}
|
|
18
|
-
input, button {
|
|
19
|
-
width: 100%;
|
|
20
|
-
margin-bottom: 10px;
|
|
21
|
-
padding: 8px;
|
|
22
|
-
box-sizing: border-box;
|
|
23
|
-
}
|
|
24
|
-
`;
|
|
25
|
-
|
|
26
|
-
static properties = {
|
|
27
|
-
currentPassword: { type: String },
|
|
28
|
-
newPassword: { type: String },
|
|
29
|
-
confirmPassword: { type: String },
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
constructor() {
|
|
33
|
-
super();
|
|
34
|
-
this.currentPassword = '';
|
|
35
|
-
this.newPassword = '';
|
|
36
|
-
this.confirmPassword = '';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
render() {
|
|
40
|
-
return html`
|
|
41
|
-
<form @submit="${this.handleSubmit}">
|
|
42
|
-
<input type="password" name="currentPassword"
|
|
43
|
-
autocomplete="current-password"
|
|
44
|
-
placeholder="Current Password"
|
|
45
|
-
.value="${this.currentPassword}"
|
|
46
|
-
@input="${this.updateProperty('currentPassword')}"
|
|
47
|
-
>
|
|
48
|
-
<input type="password" name="newPassword"
|
|
49
|
-
placeholder="New Password"
|
|
50
|
-
.value="${this.newPassword}"
|
|
51
|
-
@input="${this.updateProperty('newPassword')}"
|
|
52
|
-
>
|
|
53
|
-
<input type="password" name="confirmPassword"
|
|
54
|
-
placeholder="Confirm New Password"
|
|
55
|
-
.value="${this.confirmPassword}"
|
|
56
|
-
@input="${this.updateProperty('confirmPassword')}"
|
|
57
|
-
>
|
|
58
|
-
<button type="submit">Change Password</button>
|
|
59
|
-
</form>
|
|
60
|
-
`;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
updateProperty(property) {
|
|
64
|
-
return (e) => {
|
|
65
|
-
this[property] = e.target.value;
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
handleSubmit(e) {
|
|
70
|
-
e.preventDefault();
|
|
71
|
-
if (this.newPassword === this.confirmPassword) {
|
|
72
|
-
this.dispatchEvent(new CustomEvent('change-password', {
|
|
73
|
-
detail: {
|
|
74
|
-
currentPassword: this.currentPassword,
|
|
75
|
-
newPassword: this.newPassword,
|
|
76
|
-
},
|
|
77
|
-
}));
|
|
78
|
-
} else {
|
|
79
|
-
alert('The new passwords do not match.');
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
customElements.define('studio-change-password', StudioChangePassword);
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { LitElement, html, css } from 'lit';
|
|
2
|
-
import '@shoelace-style/shoelace/dist/components/card/card.js';
|
|
3
|
-
import '@shoelace-style/shoelace/dist/components/input/input.js';
|
|
4
|
-
import '@shoelace-style/shoelace/dist/components/button/button.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Login Form for the Studio
|
|
8
|
-
* @customElement studio-login
|
|
9
|
-
* @example
|
|
10
|
-
* <studio-login></studio-login>
|
|
11
|
-
*
|
|
12
|
-
* @fires login-attempt - Fired when the user submits the login form
|
|
13
|
-
*/
|
|
14
|
-
class StudioLogin extends LitElement {
|
|
15
|
-
static styles = css`
|
|
16
|
-
:host {
|
|
17
|
-
display: flex;
|
|
18
|
-
justify-content: center;
|
|
19
|
-
align-items: center;
|
|
20
|
-
height: 100vh;
|
|
21
|
-
box-sizing: border-box;
|
|
22
|
-
}
|
|
23
|
-
sl-card {
|
|
24
|
-
width: 300px;
|
|
25
|
-
--padding: var(--sl-card-padding);
|
|
26
|
-
--background-color: var(--sl-card-background-color);
|
|
27
|
-
--border-radius: var(--sl-card-border-radius);
|
|
28
|
-
--box-shadow: var(--sl-card-shadow);
|
|
29
|
-
}
|
|
30
|
-
sl-input, sl-button {
|
|
31
|
-
width: 100%;
|
|
32
|
-
margin-bottom: 10px;
|
|
33
|
-
}
|
|
34
|
-
`;
|
|
35
|
-
|
|
36
|
-
static properties = {
|
|
37
|
-
username: { type: String },
|
|
38
|
-
password: { type: String },
|
|
39
|
-
disabled: { type: Boolean, reflect: true },
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
constructor() {
|
|
43
|
-
super();
|
|
44
|
-
this.username = '';
|
|
45
|
-
this.password = '';
|
|
46
|
-
this.disabled = false;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
handleSubmit(e) {
|
|
50
|
-
e.preventDefault();
|
|
51
|
-
this.dispatchEvent(
|
|
52
|
-
new CustomEvent('login-attempt', {
|
|
53
|
-
detail: {
|
|
54
|
-
username: this.username,
|
|
55
|
-
password: this.password,
|
|
56
|
-
},
|
|
57
|
-
bubbles: true,
|
|
58
|
-
composed: true,
|
|
59
|
-
})
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
handleInputChange(e) {
|
|
64
|
-
const { name, value } = e.target;
|
|
65
|
-
this[name] = value;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
render() {
|
|
69
|
-
return html`
|
|
70
|
-
<sl-card>
|
|
71
|
-
<form @submit="${this.handleSubmit}">
|
|
72
|
-
<sl-input
|
|
73
|
-
name="username"
|
|
74
|
-
placeholder="Username or Email"
|
|
75
|
-
.value="${this.username}"
|
|
76
|
-
autocomplete="username"
|
|
77
|
-
@sl-change="${this.handleInputChange}">
|
|
78
|
-
</sl-input>
|
|
79
|
-
<sl-input
|
|
80
|
-
type="password"
|
|
81
|
-
name="password"
|
|
82
|
-
placeholder="Password"
|
|
83
|
-
.value="${this.password}"
|
|
84
|
-
autocomplete="current-password"
|
|
85
|
-
@sl-change="${this.handleInputChange}">
|
|
86
|
-
</sl-input>
|
|
87
|
-
<sl-button type="submit" ?disabled="${this.disabled}">Login</sl-button>
|
|
88
|
-
</form>
|
|
89
|
-
</sl-card>
|
|
90
|
-
`;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
customElements.define('studio-login', StudioLogin);
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { LitElement, html } from 'lit';
|
|
2
|
-
import { getToken } from '../lib.mjs';
|
|
3
|
-
import { getStudio } from '@wral/studio-tools';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Parses the payload of a JWT, without any validation.
|
|
7
|
-
* @param {string} token - The JWT token
|
|
8
|
-
* @returns {object} The parsed token's payload
|
|
9
|
-
*/
|
|
10
|
-
function parseToken(token) {
|
|
11
|
-
return JSON.parse(atob(token.split('.')[1]));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
class StudioProfileView extends LitElement {
|
|
15
|
-
|
|
16
|
-
constructor() {
|
|
17
|
-
super();
|
|
18
|
-
this.token = null;
|
|
19
|
-
this.studio = getStudio();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
firstUpdated() {
|
|
23
|
-
this.fetchToken().then(() => {
|
|
24
|
-
this.requestUpdate();
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async fetchToken() {
|
|
29
|
-
return this.token = await getToken(this.studio);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
render() {
|
|
33
|
-
if (!this.token) {
|
|
34
|
-
return html`<div>You are not logged in</div>`;
|
|
35
|
-
}
|
|
36
|
-
const payload = parseToken(this.token);
|
|
37
|
-
return html`<div>
|
|
38
|
-
<h2>Your Profile</h2>
|
|
39
|
-
<div class="username">${payload.username || payload.sub}</div>
|
|
40
|
-
<div>
|
|
41
|
-
<h3>Permissions</h3>
|
|
42
|
-
<ul>
|
|
43
|
-
${(payload.scope || '').split(' ')
|
|
44
|
-
.map(permission => html`<li>${permission}</li>`)}
|
|
45
|
-
</ul>
|
|
46
|
-
</div>
|
|
47
|
-
<div>
|
|
48
|
-
<studio-change-password></studio-change-password>
|
|
49
|
-
</div>
|
|
50
|
-
</div>`;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
customElements.define('studio-profile-view', StudioProfileView);
|
|
55
|
-
|
|
56
|
-
export default html`<studio-profile-view id="profile"></studio-profile-view>`
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { LitElement, html, css } from 'lit';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Describes a reset password form
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* <studio-reset-password></studio-reset-password>
|
|
8
|
-
*
|
|
9
|
-
* @attribute hide-confirmation-code - Hides the confirmation code input
|
|
10
|
-
* @attribute triggered - Indicates that the reset password form was triggered
|
|
11
|
-
*
|
|
12
|
-
* @fires request-trigger - Fired when the user submits the login form
|
|
13
|
-
* @fires reset-password - Fired when the user submits the reset password form
|
|
14
|
-
*
|
|
15
|
-
* @TODO: refactor password reset as a form and add browser validation
|
|
16
|
-
*/
|
|
17
|
-
class StudioResetPassword extends LitElement {
|
|
18
|
-
static styles = css`
|
|
19
|
-
:host {
|
|
20
|
-
display: block;
|
|
21
|
-
box-sizing: border-box;
|
|
22
|
-
}
|
|
23
|
-
input, button {
|
|
24
|
-
width: 100%;
|
|
25
|
-
margin-bottom: 10px;
|
|
26
|
-
box-sizing: border-box;
|
|
27
|
-
padding: 8px;
|
|
28
|
-
}
|
|
29
|
-
`;
|
|
30
|
-
|
|
31
|
-
static properties = {
|
|
32
|
-
email: { type: String },
|
|
33
|
-
confirmationCode: { type: String },
|
|
34
|
-
hideConfirmationCode: { type: Boolean },
|
|
35
|
-
newPassword: { type: String },
|
|
36
|
-
triggered: { type: Boolean },
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
constructor() {
|
|
40
|
-
super();
|
|
41
|
-
this.email = '';
|
|
42
|
-
this.confirmationCode = '';
|
|
43
|
-
this.newPassword = '';
|
|
44
|
-
this.hideConfirmationCode = false;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
handleInput(field) {
|
|
48
|
-
return (e) => {
|
|
49
|
-
this[field] = e.target.value;
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
triggerRequest() {
|
|
54
|
-
const event = new CustomEvent('request-trigger', {
|
|
55
|
-
detail: { email: this.email },
|
|
56
|
-
cancelable: true,
|
|
57
|
-
});
|
|
58
|
-
this.dispatchEvent(event);
|
|
59
|
-
|
|
60
|
-
// If the event is not cancelled, set the stage to 2
|
|
61
|
-
if (!event.defaultPrevented) {
|
|
62
|
-
this.triggered = true;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
handleSubmit(e) {
|
|
67
|
-
e.preventDefault();
|
|
68
|
-
this.dispatchEvent(new CustomEvent('password-reset', {
|
|
69
|
-
detail: {
|
|
70
|
-
email: this.email,
|
|
71
|
-
confirmationCode: this.confirmationCode,
|
|
72
|
-
newPassword: this.newPassword,
|
|
73
|
-
},
|
|
74
|
-
}));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
render() {
|
|
78
|
-
return html`
|
|
79
|
-
<form @submit="${this.handleSubmit}">
|
|
80
|
-
${!this.triggered ? html`
|
|
81
|
-
<input type="email"
|
|
82
|
-
name="email"
|
|
83
|
-
placeholder="Email"
|
|
84
|
-
autocomplete="email"
|
|
85
|
-
.value="${this.email}"
|
|
86
|
-
required
|
|
87
|
-
@input="${this.handleInput('email')}">
|
|
88
|
-
<button type="button" @click="${this.triggerRequest}">Request Reset</button>
|
|
89
|
-
` : html`
|
|
90
|
-
<input name="confirmationCode"
|
|
91
|
-
type=${this.hideConfirmationCode ? 'hidden' : 'text'}
|
|
92
|
-
autocomplete="one-time-code"
|
|
93
|
-
placeholder="Confirmation Code"
|
|
94
|
-
.value="${this.confirmationCode}"
|
|
95
|
-
@input="${this.handleInput('confirmationCode')}">
|
|
96
|
-
<input type="password" name="newPassword"
|
|
97
|
-
autocomplete="new-password"
|
|
98
|
-
placeholder="New Password"
|
|
99
|
-
.value="${this.newPassword}"
|
|
100
|
-
@input="${this.handleInput('newPassword')}"
|
|
101
|
-
required
|
|
102
|
-
>
|
|
103
|
-
<button type="submit">Reset Password</button>
|
|
104
|
-
`}
|
|
105
|
-
</form>
|
|
106
|
-
`;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
customElements.define('studio-reset-password', StudioResetPassword);
|
package/src/lib.mjs
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Get an auth token
|
|
3
|
-
* @param {Studio} studio
|
|
4
|
-
* @return {Promise<string>} bearer token
|
|
5
|
-
*/
|
|
6
|
-
export function getToken(studio) {
|
|
7
|
-
return new Promise((resolve, reject) => {
|
|
8
|
-
studio.pub('studio.wral::mod-auth', 'token-request', {
|
|
9
|
-
callback: (token, error) => {
|
|
10
|
-
if (error) {
|
|
11
|
-
reject(error);
|
|
12
|
-
}
|
|
13
|
-
resolve(token);
|
|
14
|
-
}});
|
|
15
|
-
});
|
|
16
|
-
}
|
package/src/tool-dummy.mjs
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { LitElement, css, html } from 'lit';
|
|
2
|
-
import { getStudio } from '@wral/studio-tools';
|
|
3
|
-
import { defineTool } from '@wral/studio-ui/define-tool';
|
|
4
|
-
import { getToken } from './lib.mjs';
|
|
5
|
-
|
|
6
|
-
import './components/studio-profile-view.mjs';
|
|
7
|
-
|
|
8
|
-
/* Console use should be permitted in this component, since its only
|
|
9
|
-
* purpose is as a fixture for development and debugging. */
|
|
10
|
-
/* eslint-disable no-console */
|
|
11
|
-
|
|
12
|
-
class DummyTool extends LitElement {
|
|
13
|
-
constructor() {
|
|
14
|
-
super();
|
|
15
|
-
this.studio = getStudio();
|
|
16
|
-
this.handleClick = this.handleClick.bind(this);
|
|
17
|
-
this.handleLogout = this.handleLogout.bind(this);
|
|
18
|
-
this.token = null;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
static get styles() {
|
|
22
|
-
return css`
|
|
23
|
-
:host {
|
|
24
|
-
display: block;
|
|
25
|
-
}
|
|
26
|
-
`;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
handleClick() {
|
|
30
|
-
console.log("Dummy tool is requesting a token");
|
|
31
|
-
this.getToken().then((token) => {
|
|
32
|
-
console.log("Dummy tool received token:", token);
|
|
33
|
-
this.token = token;
|
|
34
|
-
this.requestUpdate();
|
|
35
|
-
}).catch((error) => {
|
|
36
|
-
console.error("Dummy tool did not receive token:", error);
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
handleLogout() {
|
|
41
|
-
this.studio.pub('studio.wral::mod-auth', 'logout');
|
|
42
|
-
this.token = null;
|
|
43
|
-
this.requestUpdate();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
getToken() {
|
|
47
|
-
return getToken(this.studio);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
render() {
|
|
51
|
-
return html`
|
|
52
|
-
<h1>Dummy Tool</h1>
|
|
53
|
-
<p>This tool represents a studio mod that needs an auth token. The
|
|
54
|
-
token will be requested when the button is clicked.</p>
|
|
55
|
-
<button @click="${this.handleClick}">Click me</button>
|
|
56
|
-
<div>${this.token ? 'You are authenticated' : 'Token not requested'}</div>
|
|
57
|
-
<div>
|
|
58
|
-
${this.token && html`
|
|
59
|
-
<button @click="${this.handleLogout}">Request Logout</button>
|
|
60
|
-
`}
|
|
61
|
-
</div>
|
|
62
|
-
${this.token ? html`<studio-profile-view token="${this.token}">
|
|
63
|
-
</studio-profile-view>` : null}
|
|
64
|
-
`;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const dummyTool = defineTool({
|
|
70
|
-
component: DummyTool,
|
|
71
|
-
token: 'dummy-tool',
|
|
72
|
-
label: 'Dummy Tool',
|
|
73
|
-
description: 'Dummy Tool',
|
|
74
|
-
icon: '🤖',
|
|
75
|
-
toolHtml: html`<tool-dummy-tool exportparts="title,description"></tool-dummy-tool>`,
|
|
76
|
-
buttonHtml: html`<tool-dummy-tool-button exportparts="button,icon">
|
|
77
|
-
</tool-dummy-tool-button>`,
|
|
78
|
-
});
|
|
79
|
-
export default dummyTool;
|
|
80
|
-
|
|
81
|
-
export function init(studio) {
|
|
82
|
-
// Force this tool to activate on init
|
|
83
|
-
studio.pub('system::workspace', 'present', dummyTool);
|
|
84
|
-
}
|