Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions packages/secure-origin/build-record.json
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@
]
},
"shell.css": {
"bytes": 26350,
"bytes": 26409,
"sources": [
{
"package": "@cardstack/secure-origin",
Expand Down Expand Up @@ -734,6 +734,10 @@
"package": "@cardstack/secure-origin",
"module": "src/shell/sign-in/040e10289d.css"
},
{
"package": "@cardstack/secure-origin",
"module": "src/shell/sign-in/1d730c0edf.css"
},
{
"package": "@cardstack/secure-origin",
"module": "src/shell/sign-in/2d5d118eaf.css"
Expand All @@ -757,7 +761,7 @@
]
},
"shell.js": {
"bytes": 70953,
"bytes": 71781,
"modules": [
{
"package": "@cardstack/secure-origin",
Expand Down Expand Up @@ -902,7 +906,7 @@
{
"package": "@cardstack/secure-origin",
"module": "src/shell/sign-in/cli-auth-page.gts",
"size": 3326
"size": 3681
},
{
"package": "@cardstack/secure-origin",
Expand All @@ -912,7 +916,7 @@
{
"package": "@cardstack/secure-origin",
"module": "src/shell/sign-in/cli-sign-in-page.gts",
"size": 1240
"size": 1776
},
{
"package": "@cardstack/secure-origin",
Expand Down
20 changes: 15 additions & 5 deletions packages/secure-origin/src/shell/sign-in/cli-auth-page.gts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// The `cli-auth` mode: `boxel profile add` signing in for a Matrix device of
// its own, for the CLI waiting on the loopback port the URL names with `port`
// and `state`. Signed in, the CLI is handed a single-use login token (see
// `CliHandoff`); this window keeps none of it.
// `CliHandoff`); this window keeps none of it. A CLI whose URL carries
// `session=secure` is also handed the secure session, which lets it manage
// the user's keys, and the page says so.
//
// A window already signed in asks the same account to confirm its password,
// as the app's own CLI page does: whoever this browser is signed in as is
Expand Down Expand Up @@ -47,16 +49,19 @@ export default class CliAuthPage extends Component {
>
<:intro>
{{#if this.state.signedInAs}}
<p class='intro-text'>Confirm your password to give the Boxel
CLI running on this computer access to the workspaces of
<p class='intro-text' data-test-secure-cli-auth-confirm>Confirm
your password to give the Boxel CLI running on this computer
access to the workspaces of
<span
class='signed-in-user'
data-test-secure-cli-auth-signed-in-as
>{{this.state.signedInAs}}</span>.</p>
>{{this.state.signedInAs}}</span>{{#if this.managesKeys}}, and
to let it manage their keys{{/if}}.</p>
{{else}}
<p class='intro-text' data-test-secure-cli-auth-subtitle>Signing
in gives the Boxel CLI running on this computer access to your
workspaces.</p>
workspaces{{#if this.managesKeys}}, and lets it manage your
keys{{/if}}.</p>
{{/if}}
</:intro>
</SignInForm>
Expand Down Expand Up @@ -99,6 +104,11 @@ export default class CliAuthPage extends Component {
}
}

// Whether the CLI takes the secure session as well as the login token.
private get managesKeys() {
return Boolean(this.callback?.profile?.secureSession);
}

private get ready() {
return this.state.page === 'ready';
}
Expand Down
21 changes: 19 additions & 2 deletions packages/secure-origin/src/shell/sign-in/cli-sign-in-page.gts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// The `cli-sign-in` mode: a session for the CLI waiting on a loopback port,
// which the URL names with `port` and `state`. Signed in, the session goes to
// that listener and nowhere else; this window keeps none of it.
// that listener and nowhere else; this window keeps none of it. The CLI uses
// that session to change the user's keys, so the page names the CLI and says
// what signing in lets it do.
import Component from '@glimmer/component';
import { trackedObject } from '@ember/reactive/collections';

Expand Down Expand Up @@ -29,12 +31,27 @@ export default class CliSignInPage extends Component {
@cli={{this.callback}}
@username={{this.username}}
@onSignedIn={{this.signedIn}}
/>
@title='Authorize Boxel CLI'
>
<:intro>
<p
class='intro-text'
data-test-secure-cli-sign-in-subtitle
>Signing in lets the Boxel CLI running on this computer manage
your keys.</p>
</:intro>
</SignInForm>
</AuthContainer>
{{/if}}
{{else}}
<IncompleteCliLink />
{{/if}}

<style scoped>
.intro-text {
margin: 0;
}
</style>
</template>

private config = readConfig();
Expand Down
47 changes: 46 additions & 1 deletion packages/secure-origin/tests/integration/sign-in-test.gts
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,20 @@ module('Integration | sign-in', function (hooks) {
}
});

test('names the CLI and what signing in lets it do, in place of the Google subtitle', async function (assert) {
serve(WITH_GOOGLE);
visitShell(`?mode=cli-sign-in&port=51234&state=${STATE}&user=someone`);
await render(CliSignInPage);
await waitFor('[data-test-secure-google]');
assert.dom('[data-test-secure-title]').hasText('Authorize Boxel CLI');
assert
.dom('[data-test-secure-cli-sign-in-subtitle]')
.hasText(
'Signing in lets the Boxel CLI running on this computer manage your keys.',
);
assert.dom('[data-test-secure-sign-in-subtitle]').doesNotExist();
});

test('fills in the username the CLI named, and starts on the password', async function (assert) {
serve(NO_GOOGLE);
visitShell(`?mode=cli-sign-in&port=51234&state=${STATE}&user=someone`);
Expand Down Expand Up @@ -582,7 +596,7 @@ module('Integration | sign-in', function (hooks) {
assert
.dom('[data-test-secure-cli-auth-subtitle]')
.hasText(
'Signing in gives the Boxel CLI running on this computer access to your workspaces.',
'Signing in gives the Boxel CLI running on this computer access to your workspaces, and lets it manage your keys.',
);
assert.dom('[data-test-secure-sign-in-subtitle]').doesNotExist();
assert.dom('[data-test-secure-username]').isFocused();
Expand All @@ -609,6 +623,11 @@ module('Integration | sign-in', function (hooks) {
assert
.dom('[data-test-secure-cli-auth-signed-in-as]')
.hasText(SESSION.user);
assert
.dom('[data-test-secure-cli-auth-confirm]')
.hasText(
`Confirm your password to give the Boxel CLI running on this computer access to the workspaces of ${SESSION.user}, and to let it manage their keys.`,
);
assert.dom('[data-test-secure-username]').hasValue('someone');
assert.dom('[data-test-secure-password]').isFocused();
});
Expand Down Expand Up @@ -651,6 +670,32 @@ module('Integration | sign-in', function (hooks) {
assert.strictEqual(localStorage.getItem('boxel-secure-session'), null);
});

test('a CLI that takes no secure session is told it gets access to the workspaces alone', async function (assert) {
serve(NO_GOOGLE);
visitShell(`?mode=cli-auth&port=51234&state=${STATE}`);
await render(CliAuthPage);
await waitFor('[data-test-secure-sign-in-form]');
assert.dom('[data-test-secure-title]').hasText('Authorize Boxel CLI');
assert
.dom('[data-test-secure-cli-auth-subtitle]')
.hasText(
'Signing in gives the Boxel CLI running on this computer access to your workspaces.',
);
});

test('a window already signed in, for a CLI that takes no secure session, asks only for access to the workspaces', async function (assert) {
storeSession(SESSION);
serve(NO_GOOGLE, { 'GET _secure-session': () => ({ status: 204 }) });
visitShell(`?mode=cli-auth&port=51234&state=${STATE}`);
await render(CliAuthPage);
await waitFor('[data-test-secure-cli-auth-confirm]');
assert
.dom('[data-test-secure-cli-auth-confirm]')
.hasText(
`Confirm your password to give the Boxel CLI running on this computer access to the workspaces of ${SESSION.user}.`,
);
});

test('a CLI that takes no secure session gets the login token in the query of a navigation, and the session is ended', async function (assert) {
let server = serve(NO_GOOGLE, signsIn(SIGNED_IN), MINTS, ENDS);
visitShell(`?mode=cli-auth&port=51234&state=${STATE}`);
Expand Down
Loading