forked from Nexus/nexus
OAuth Support (#53)
Rips out the old auth method, adds OAuth support. Fixes #51. Tested Platforms: - [x] Linux - [x] Flatpak - [x] Native (Nix) - [x] Android - [ ] Windows - [ ] MacOS Reviewed-on: Nexus/nexus#53
This commit is contained in:
parent
5df975f607
commit
7d106ad3a2
86 changed files with 558 additions and 1344 deletions
|
|
@ -18,6 +18,7 @@ class ChatPage extends ConsumerWidget {
|
|||
final showMembersByDefault = constraints.maxWidth > 1000;
|
||||
final initComplete = ref.watch(InitCompleteController.provider);
|
||||
final roomId = ref.watch(KeyController.provider(KeyController.roomKey));
|
||||
|
||||
ref.read(EmojiController.provider);
|
||||
|
||||
return SafeArea(
|
||||
|
|
|
|||
|
|
@ -1,99 +0,0 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_hooks/flutter_hooks.dart";
|
||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||
import "package:nexus/controllers/client.dart";
|
||||
import "package:nexus/widgets/appbar.dart";
|
||||
import "package:nexus/helpers/required_validator_helper.dart";
|
||||
|
||||
class LoginPage extends HookConsumerWidget {
|
||||
final Uri homeserver;
|
||||
const LoginPage({super.key, required this.homeserver});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final client = ref.watch(ClientController.provider.notifier);
|
||||
|
||||
final isLoading = useState(false);
|
||||
final username = useTextEditingController();
|
||||
final password = useTextEditingController();
|
||||
|
||||
final inputError = useState<String?>(null);
|
||||
final formKey = useRef(GlobalKey<FormState>());
|
||||
|
||||
Future<void> tryLogin() async {
|
||||
isLoading.value = true;
|
||||
|
||||
try {
|
||||
if (formKey.value.currentState?.validate() != true) return;
|
||||
|
||||
final error = await client.login(
|
||||
.new(
|
||||
username: username.text,
|
||||
password: password.text,
|
||||
homeserverUrl: homeserver.origin,
|
||||
),
|
||||
);
|
||||
|
||||
if (error != null) {
|
||||
inputError.value = error;
|
||||
isLoading.value = false;
|
||||
} else {
|
||||
if (context.mounted) Navigator.of(context).pop();
|
||||
}
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: Appbar(
|
||||
leading: IconButton(
|
||||
icon: Icon(Icons.arrow_back),
|
||||
onPressed: Navigator.of(context).pop,
|
||||
),
|
||||
),
|
||||
body: AlertDialog(
|
||||
title: Text("Login to ${homeserver.host}"),
|
||||
content: Form(
|
||||
key: formKey.value,
|
||||
child: Column(
|
||||
mainAxisSize: .min,
|
||||
crossAxisAlignment: .start,
|
||||
children: [
|
||||
TextFormField(
|
||||
autofocus: true,
|
||||
textInputAction: .next,
|
||||
autovalidateMode: .onUserInteraction,
|
||||
validator: requiredValidator,
|
||||
decoration: .new(label: Text("Username")),
|
||||
controller: username,
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
TextFormField(
|
||||
textInputAction: .done,
|
||||
decoration: .new(
|
||||
label: Text("Password"),
|
||||
errorText: inputError.value,
|
||||
errorMaxLines: 5,
|
||||
),
|
||||
autovalidateMode: .onUserInteraction,
|
||||
validator: requiredValidator,
|
||||
controller: password,
|
||||
obscureText: true,
|
||||
onFieldSubmitted: (_) => tryLogin(),
|
||||
// Don't defocus on submit
|
||||
onEditingComplete: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: isLoading.value ? null : tryLogin,
|
||||
child: Text("Sign In"),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
import "package:app_links/app_links.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter_hooks/flutter_hooks.dart";
|
||||
import "package:flutter_svg/flutter_svg.dart";
|
||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||
import "package:nexus/controllers/auth_url.dart";
|
||||
import "package:nexus/controllers/client.dart";
|
||||
import "package:nexus/controllers/client_id.dart";
|
||||
import "package:nexus/helpers/launch_helper.dart";
|
||||
import "package:nexus/main.dart";
|
||||
import "package:nexus/models/homeserver.dart";
|
||||
import "package:nexus/pages/login.dart";
|
||||
import "package:nexus/widgets/appbar.dart";
|
||||
import "package:nexus/widgets/divider_text.dart";
|
||||
|
||||
|
|
@ -32,7 +35,7 @@ class SelectServerPage extends HookConsumerWidget {
|
|||
final newUrl = newHomeserver == null
|
||||
? null
|
||||
: await ref
|
||||
.watch(ClientController.provider.notifier)
|
||||
.read(ClientController.provider.notifier)
|
||||
.discoverHomeserver(newHomeserver);
|
||||
|
||||
if (context.mounted) {
|
||||
|
|
@ -47,11 +50,42 @@ class SelectServerPage extends HookConsumerWidget {
|
|||
),
|
||||
);
|
||||
} else {
|
||||
await Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (_) => LoginPage(homeserver: newUrl)),
|
||||
final codeResponse = await ref.watch(
|
||||
AuthUrlController.provider(newUrl).future,
|
||||
);
|
||||
|
||||
await ref.watch(LaunchHelper.provider).launchUrl(codeResponse.url);
|
||||
|
||||
AppLinks().uriLinkStream.listen((encodedUri) async {
|
||||
final code = encodedUri.queryParameters["code"];
|
||||
|
||||
if (code != null) {
|
||||
await ref
|
||||
.watch(ClientController.provider.notifier)
|
||||
.exchangeToken(
|
||||
.new(
|
||||
homeserverUrl: newUrl,
|
||||
codeVerifier: codeResponse.codeVerifier,
|
||||
redirectUri: .new(
|
||||
scheme: "nexus.federated.nexus",
|
||||
path: "/",
|
||||
),
|
||||
code: code,
|
||||
clientId: await ref.watch(
|
||||
ClientIdController.provider(newUrl).future,
|
||||
),
|
||||
),
|
||||
)
|
||||
.onError(showError);
|
||||
}
|
||||
});
|
||||
// await Navigator.of(context).push(
|
||||
// MaterialPageRoute(builder: (_) => LoginPage(homeserver: newUrl)),
|
||||
// );
|
||||
}
|
||||
}
|
||||
} catch (error, stackTrace) {
|
||||
showError(error, stackTrace);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue