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
3 changes: 3 additions & 0 deletions commet/lib/client/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ abstract class Client {

Future<LoginResult> executeLoginFlow(LoginFlow flow);

// returns true if the homeserver is configured in a way to disable end to end encryption
Future<bool> hasServerDisabledEncryption();

/// Logout and invalidate the current session
Future<void> logout();

Expand Down
17 changes: 17 additions & 0 deletions commet/lib/client/matrix/matrix_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,23 @@ class MatrixClient extends Client {
});
}

@override
Future<bool> hasServerDisabledEncryption() async {
var data = await matrixClient.getWellknown();
Log.i(data);

var prop =
data.additionalProperties.tryGetMap<String, dynamic>("io.element.e2ee");

var value = prop?.tryGet<bool>("force_disable");

if (value == true) {
return true;
}

return false;
}

@override
Future<Room> joinRoomFromPreview(RoomPreview preview) {
String roomId = preview.roomId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,4 +271,10 @@ class MatrixBackgroundClient implements Client {
@override
// TODO: implement favoriteRooms
NotifyingListFilter<Room> get favoriteRooms => throw UnimplementedError();

@override
Future<bool> hasServerDisabledEncryption() {
// TODO: implement hasServerDisabledEncryption
throw UnimplementedError();
}
}
30 changes: 27 additions & 3 deletions commet/lib/ui/pages/matrix/authentication/matrix_uia_request.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import 'package:commet/ui/pages/matrix/authentication/matrix_uia_request_view.dart';
import 'package:commet/utils/error_utils.dart';
import 'package:commet/utils/links/link_utils.dart';
import 'package:flutter/widgets.dart';
import 'package:matrix/matrix.dart';

Expand All @@ -15,20 +17,23 @@ class MatrixUIARequest extends StatefulWidget {
class _MatrixUIARequestState extends State<MatrixUIARequest> {
void Function(UiaRequestState)? originalOnUpdate;
late UiaRequestState state;
late Set<String> steps;

@override
void initState() {
state = widget.request.state;

originalOnUpdate = widget.request.onUpdate;
widget.request.onUpdate = onUpdate;
steps = widget.request.nextStages;

super.initState();
}

void onUpdate(UiaRequestState state) {
setState(() {
this.state = state;
this.steps = widget.request.nextStages;
});

originalOnUpdate?.call(state);
Expand All @@ -38,15 +43,34 @@ class _MatrixUIARequestState extends State<MatrixUIARequest> {
Widget build(BuildContext context) {
return MatrixUIARequestView(
state,
nextSteps: steps,
onSubmitAuthentication: submitAuthentication,
onSubmitSso: submitSso,
onSuccess: () => Navigator.of(context).pop(),
onFail: () => Navigator.of(context).pop(),
);
}

void submitAuthentication(String password) {
widget.request.completeStage(AuthenticationPassword(
password: password,
identifier: AuthenticationUserIdentifier(user: "alice")));
ErrorUtils.tryRun(context, () async {
await widget.request.completeStage(AuthenticationPassword(
password: password,
identifier: AuthenticationUserIdentifier(
user: widget.client.matrixClient.userID!)));
});
}

submitSso() {
// https://spec.matrix.org/v1.15/client-server-api/#client-behaviour-21
var hs = widget.client.matrixClient.homeserver!;
var url = hs.replace(
path: "/_matrix/client/v3/auth/m.login.sso/fallback/web",
queryParameters: {"session": widget.request.session});

LinkUtils.open(url,
bypassConfirmation: true,
filterTrackingParameters: false,
context: context);
Navigator.of(context).pop();
}
}
114 changes: 98 additions & 16 deletions commet/lib/ui/pages/matrix/authentication/matrix_uia_request_view.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:commet/utils/common_strings.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
// have to do it this way to avoid some widgetbook codegen issue
// ignore: implementation_imports
import 'package:matrix/src/utils/uia_request.dart';
Expand All @@ -9,24 +9,54 @@ import 'package:flutter/material.dart' as material;

class MatrixUIARequestView extends StatefulWidget {
const MatrixUIARequestView(this.state,
{this.onSubmitAuthentication, super.key, this.onFail, this.onSuccess});
{this.onSubmitAuthentication,
required this.nextSteps,
super.key,
this.onFail,
this.onSubmitSso,
this.onSuccess});
final UiaRequestState state;
final Set<String> nextSteps;
final Function(String password)? onSubmitAuthentication;
final Function()? onSubmitSso;
final Function()? onSuccess;
final Function()? onFail;

@override
State<MatrixUIARequestView> createState() => _MatrixUIARequestViewState();
}

enum UIAStep {
password,
sso,
}

class _MatrixUIARequestViewState extends State<MatrixUIARequestView> {
TextEditingController passwordFieldController = TextEditingController();
bool get canUsePassword => widget.nextSteps.contains("m.login.password");
bool get canUseSso => widget.nextSteps.contains("m.login.sso");

bool get canUseAnyNextStep => canUsePassword || canUseSso;

UIAStep? pickedStep;

@override
void initState() {
if (canUsePassword && !canUseSso) {
pickedStep = UIAStep.password;
}

super.initState();
}

@override
Widget build(BuildContext context) {
return SizedBox(
width: 500,
height: 200,
child: buildView(),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: buildView(),
),
);
}

Expand All @@ -39,31 +69,83 @@ class _MatrixUIARequestViewState extends State<MatrixUIARequestView> {
case UiaRequestState.loading:
return loading();
case UiaRequestState.waitForUser:
return pickedStep == null ? showAvailableSteps() : showPickedStep();
}
}

Widget showAvailableSteps() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
spacing: 12,
children: [
if (canUsePassword)
tiamat.Button(
text: "Continue with password",
onTap: () => setState(() {
pickedStep = UIAStep.password;
}),
),
if (canUseSso)
tiamat.Button(
text: "Continue with SSO",
onTap: () {
widget.onSubmitSso?.call();
setState(() {
pickedStep = UIAStep.sso;
});
}),
if (canUseAnyNextStep == false) ...[
tiamat.Text.labelLow(
"Sorry, none of the authentication methods provided by the server are supported."),
tiamat.Text.labelLow(widget.nextSteps.toString()),
]
],
),
);
}

Widget showPickedStep() {
if (pickedStep == UIAStep.password) {
return userPasswordInput();
}

switch (pickedStep!) {
case UIAStep.password:
return userPasswordInput();
case UIAStep.sso:
return showSsoStep();
}
}

Widget showSsoStep() {
return SizedBox(
height: 300,
width: 300,
child: Center(
child: CircularProgressIndicator(),
));
}

Widget userPasswordInput() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
spacing: 12,
children: [
TextInput(
placeholder: "Account Password",
obscureText: true,
controller: passwordFieldController,
),
Align(
alignment: Alignment.centerRight,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
width: 100,
height: 40,
child: Button(
text: CommonStrings.promptSubmit,
onTap: () => widget.onSubmitAuthentication
?.call(passwordFieldController.text),
)),
SizedBox(
height: 40,
child: Button(
text: CommonStrings.promptSubmit,
onTap: () => widget.onSubmitAuthentication
?.call(passwordFieldController.text),
))
],
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:commet/main.dart';
import 'package:commet/ui/atoms/code_block.dart';
import 'package:commet/utils/common_strings.dart';
import 'package:commet/utils/error_utils.dart';
import 'package:commet/utils/text_utils.dart';
Expand Down Expand Up @@ -279,19 +278,33 @@ class _MatrixCrossSigningViewState extends State<MatrixCrossSigningView> {
return m.Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
spacing: 12,
children: [
m.Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
spacing: 12,
children: [
tiamat.Text.label(labelMatrixRecoveryKeyExplanation),
const SizedBox(height: 8),
m.SelectionArea(
child: Codeblock(
text: widget.recoveryKey!,
m.Container(
decoration: BoxDecoration(
color: m.ColorScheme.of(context).surfaceContainerLowest,
borderRadius: BorderRadiusGeometry.circular(8),
),
child: m.SelectionArea(
child: m.Padding(
padding: const EdgeInsets.fromLTRB(0, 12, 0, 12),
child: m.Center(
child: Text(
widget.recoveryKey!,
style: const TextStyle(
fontSize: 12,
fontFamily: "Code",
fontFeatures: [FontFeature.disable("calt")]),
)),
),
),
),
const SizedBox(height: 8),
tiamat.Button.secondary(
tiamat.Button(
text: copyBackupCodeText,
onTap: () {
services.Clipboard.setData(
Expand All @@ -302,10 +315,7 @@ class _MatrixCrossSigningViewState extends State<MatrixCrossSigningView> {
}),
],
),
const SizedBox(
height: 50,
),
tiamat.Button(
tiamat.Button.secondary(
text: CommonStrings.promptConfirm,
isLoading: isActionLoading,
onTap: () async {
Expand Down
Loading
Loading