Skip to content

Commit a24d8e2

Browse files
committed
Offer guest mode login if advertised by OIDC Provider
1 parent f114094 commit a24d8e2

File tree

6 files changed

+50
-6
lines changed

6 files changed

+50
-6
lines changed

src/domain/login/LoginViewModel.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export class LoginViewModel extends ViewModel<SegmentType, Options> {
4646
private _startSSOLoginViewModel?: StartSSOLoginViewModel;
4747
private _completeSSOLoginViewModel?: CompleteSSOLoginViewModel;
4848
private _startOIDCLoginViewModel?: StartOIDCLoginViewModel;
49+
private _startOIDCGuestLoginViewModel?: StartOIDCLoginViewModel;
4950
private _completeOIDCLoginViewModel?: CompleteOIDCLoginViewModel;
5051
private _loadViewModel?: SessionLoadViewModel;
5152
private _loadViewModelSubscription?: () => void;
@@ -85,6 +86,10 @@ export class LoginViewModel extends ViewModel<SegmentType, Options> {
8586
return this._startOIDCLoginViewModel;
8687
}
8788

89+
get startOIDCGuestLoginViewModel(): StartOIDCLoginViewModel {
90+
return this._startOIDCGuestLoginViewModel;
91+
}
92+
8893
get completeOIDCLoginViewModel(): CompleteOIDCLoginViewModel {
8994
return this._completeOIDCLoginViewModel;
9095
}
@@ -169,7 +174,7 @@ export class LoginViewModel extends ViewModel<SegmentType, Options> {
169174

170175
private async _showOIDCLogin(): Promise<void> {
171176
this._startOIDCLoginViewModel = this.track(
172-
new StartOIDCLoginViewModel(this.childOptions({loginOptions: this._loginOptions}))
177+
new StartOIDCLoginViewModel(this.childOptions({loginOptions: this._loginOptions, asGuest: false}))
173178
);
174179
this.emitChange("startOIDCLoginViewModel");
175180
try {
@@ -180,6 +185,19 @@ export class LoginViewModel extends ViewModel<SegmentType, Options> {
180185
}
181186
}
182187

188+
private async _showOIDCGuestLogin(): Promise<void> {
189+
this._startOIDCGuestLoginViewModel = this.track(
190+
new StartOIDCLoginViewModel(this.childOptions({loginOptions: this._loginOptions, asGuest: true}))
191+
);
192+
this.emitChange("startOIDCGuestLoginViewModel");
193+
try {
194+
await this._startOIDCLoginViewModel.discover();
195+
} catch (err) {
196+
this._showError(err.message);
197+
this._disposeViewModels();
198+
}
199+
}
200+
183201
private _showError(message: string): void {
184202
this._errorMessage = message;
185203
this.emitChange("errorMessage");
@@ -190,6 +208,7 @@ export class LoginViewModel extends ViewModel<SegmentType, Options> {
190208
this._passwordLoginViewModel?.setBusy(status);
191209
this._startSSOLoginViewModel?.setBusy(status);
192210
this._startOIDCLoginViewModel?.setBusy(status);
211+
this._startOIDCGuestLoginViewModel?.setBusy(status);
193212
this.emitChange("isBusy");
194213
}
195214

@@ -244,6 +263,7 @@ export class LoginViewModel extends ViewModel<SegmentType, Options> {
244263
this._passwordLoginViewModel = this.disposeTracked(this._passwordLoginViewModel);
245264
this._completeSSOLoginViewModel = this.disposeTracked(this._completeSSOLoginViewModel);
246265
this._startOIDCLoginViewModel = this.disposeTracked(this._startOIDCLoginViewModel);
266+
this._startOIDCGuestLoginViewModel = this.disposeTracked(this._startOIDCGuestLoginViewModel);
247267
this.emitChange("disposeViewModels");
248268
}
249269

@@ -309,6 +329,7 @@ export class LoginViewModel extends ViewModel<SegmentType, Options> {
309329
if (this._loginOptions.sso) { this._showSSOLogin(); }
310330
if (this._loginOptions.password) { this._showPasswordLogin(); }
311331
if (this._loginOptions.oidc) { this._showOIDCLogin(); }
332+
if (this._loginOptions.oidc?.guestAvailable) { this._showOIDCGuestLogin(); }
312333
if (!this._loginOptions.sso && !this._loginOptions.password && !this._loginOptions.oidc) {
313334
this._showError("This homeserver supports neither SSO nor password based login flows or has a usable OIDC Provider");
314335
}
@@ -335,6 +356,6 @@ export type LoginOptions = {
335356
homeserver: string;
336357
password?: (username: string, password: string) => PasswordLoginMethod;
337358
sso?: SSOLoginHelper;
338-
oidc?: { issuer: string };
359+
oidc?: { issuer: string, guestAvailable: boolean };
339360
token?: (loginToken: string) => TokenLoginMethod;
340361
};

src/domain/login/StartOIDCLoginViewModel.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export class StartOIDCLoginViewModel extends ViewModel {
3232
urlRouter: this.urlRouter,
3333
staticClients: this.platform.config["staticOidcClients"],
3434
});
35+
this._asGuest = options.asGuest;
3536
}
3637

3738
get isBusy() { return this._isBusy; }
@@ -60,7 +61,7 @@ export class StartOIDCLoginViewModel extends ViewModel {
6061
async startOIDCLogin() {
6162
const deviceScope = this._api.generateDeviceScope();
6263
const p = this._api.generateParams({
63-
scope: `openid urn:matrix:org.matrix.msc2967.client:api:* ${deviceScope}`,
64+
scope: `openid urn:matrix:org.matrix.msc2967.client:api:${this._asGuest ? 'guest' : '*'} ${deviceScope}`,
6465
redirectUri: this.urlRouter.createOIDCRedirectURL(),
6566
});
6667
const clientId = await this._api.clientId();

src/matrix/Client.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,11 @@ export class Client {
141141
});
142142
await oidcApi.validate();
143143

144+
const guestAvailable = await oidcApi.isGuestAvailable();
145+
144146
return {
145147
homeserver,
146-
oidc: { issuer, account },
148+
oidc: { issuer, account, guestAvailable },
147149
};
148150
} catch (e) {
149151
console.log(e);

src/matrix/net/OidcApi.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@ export class OidcApi<N extends object = SegmentType> {
226226
return metadata["revocation_endpoint"];
227227
}
228228

229+
async isGuestAvailable(): Promise<boolean> {
230+
const metadata = await this.metadata();
231+
return metadata["scopes_supported"]?.includes("urn:matrix:org.matrix.msc2967.client:api:guest");
232+
}
233+
229234
generateDeviceScope(): String {
230235
const deviceId = randomString(10);
231236
return `urn:matrix:org.matrix.msc2967.client:device:${deviceId}`;

src/platform/web/ui/css/login.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,13 @@ limitations under the License.
6868
--size: 20px;
6969
}
7070

71-
.StartSSOLoginView, .StartOIDCLoginView {
71+
.StartSSOLoginView, .StartOIDCLoginView, .StartOIDCGuestLoginView {
7272
display: flex;
7373
flex-direction: column;
7474
padding: 0 0.4em 0;
7575
}
7676

77-
.StartSSOLoginView_button, .StartOIDCLoginView_button {
77+
.StartSSOLoginView_button, .StartOIDCLoginView_button, .StartOIDCGuestLoginView_button {
7878
flex: 1;
7979
margin-top: 12px;
8080
}

src/platform/web/ui/login/LoginView.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ export class LoginView extends TemplateView {
5858
t.if(vm => vm.passwordLoginViewModel && vm.startSSOLoginViewModel, t => t.p({className: "LoginView_separator"}, vm.i18n`or`)),
5959
t.mapView(vm => vm.startSSOLoginViewModel, vm => vm ? new StartSSOLoginView(vm) : null),
6060
t.mapView(vm => vm.startOIDCLoginViewModel, vm => vm ? new StartOIDCLoginView(vm) : null),
61+
t.if(vm => vm.startOIDCLoginViewModel && vm.startOIDCGuestLoginViewModel, t => t.p({className: "LoginView_separator"}, vm.i18n`or`)),
62+
t.mapView(vm => vm.startOIDCGuestLoginViewModel, vm => vm ? new StartOIDCGuestLoginView(vm) : null),
6163
t.mapView(vm => vm.loadViewModel, loadViewModel => loadViewModel ? new SessionLoadStatusView(loadViewModel) : null),
6264
// use t.mapView rather than t.if to create a new view when the view model changes too
6365
t.p(hydrogenGithubLink(t))
@@ -90,3 +92,16 @@ class StartOIDCLoginView extends TemplateView {
9092
);
9193
}
9294
}
95+
96+
class StartOIDCGuestLoginView extends TemplateView {
97+
render(t, vm) {
98+
return t.div({ className: "StartOIDCGuestLoginView" },
99+
t.a({
100+
className: "StartOIDCGuestLoginView_button button-action primary",
101+
type: "button",
102+
onClick: () => vm.startOIDCLogin(),
103+
disabled: vm => vm.isBusy
104+
}, vm.i18n`Continue as Guest`)
105+
);
106+
}
107+
}

0 commit comments

Comments
 (0)