👽 Update API to microservices
♻️ Refactor router pushes
This commit is contained in:
17
lib/screens/auth/captcha.config.dart
Normal file
17
lib/screens/auth/captcha.config.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'captcha.config.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<String> captchaUrl(Ref ref) async {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final resp = await apiClient.get('/.well-known/services');
|
||||
final serviceMapping = await resp.data;
|
||||
var baseUrl = serviceMapping['DysonNetwork.Pass'] as String;
|
||||
// The backend using self-signed certicates on development
|
||||
// Which mobile simulator might not accept, use this to avoid errors
|
||||
if (baseUrl.contains('https://localhost')) baseUrl = 'http://localhost:5216';
|
||||
return '$baseUrl/captcha';
|
||||
}
|
26
lib/screens/auth/captcha.config.g.dart
Normal file
26
lib/screens/auth/captcha.config.g.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'captcha.config.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$captchaUrlHash() => r'627caa2f2eb020a28a4b138122fe8e99915185f9';
|
||||
|
||||
/// See also [captchaUrl].
|
||||
@ProviderFor(captchaUrl)
|
||||
final captchaUrlProvider = AutoDisposeFutureProvider<String>.internal(
|
||||
captchaUrl,
|
||||
name: r'captchaUrlProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$captchaUrlHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef CaptchaUrlRef = AutoDisposeFutureProviderRef<String>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/screens/auth/captcha.config.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
|
||||
class CaptchaScreen extends ConsumerWidget {
|
||||
@@ -9,13 +9,15 @@ class CaptchaScreen extends ConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final serverUrl = ref.watch(serverUrlProvider);
|
||||
final captchaUrl = ref.watch(captchaUrlProvider);
|
||||
|
||||
if (!captchaUrl.hasValue) return Center(child: CircularProgressIndicator());
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(title: Text("Anti-Robot")),
|
||||
body: InAppWebView(
|
||||
initialUrlRequest: URLRequest(
|
||||
url: WebUri('$serverUrl/auth/captcha?redirect_uri=solink://captcha'),
|
||||
url: WebUri('${captchaUrl.value}?redirect_uri=solian://captcha'),
|
||||
),
|
||||
shouldOverrideUrlLoading: (controller, navigationAction) async {
|
||||
Uri? url = navigationAction.request.url;
|
||||
|
@@ -3,6 +3,7 @@
|
||||
import 'dart:ui_web' as ui;
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/screens/auth/captcha.config.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:web/web.dart' as web;
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -17,7 +18,7 @@ class CaptchaScreen extends ConsumerStatefulWidget {
|
||||
class _CaptchaScreenState extends ConsumerState<CaptchaScreen> {
|
||||
bool _isInitialized = false;
|
||||
|
||||
void _setupWebListener(String serverUrl) {
|
||||
void _setupWebListener(String serverUrl) async {
|
||||
web.window.onMessage.listen((event) {
|
||||
if (event.data != null && event.data is String) {
|
||||
final message = event.data as String;
|
||||
@@ -29,9 +30,11 @@ class _CaptchaScreenState extends ConsumerState<CaptchaScreen> {
|
||||
}
|
||||
});
|
||||
|
||||
final captchaUrl = await ref.watch(captchaUrlProvider.future);
|
||||
|
||||
final iframe =
|
||||
web.HTMLIFrameElement()
|
||||
..src = '$serverUrl/auth/captcha'
|
||||
..src = captchaUrl
|
||||
..style.border = 'none'
|
||||
..width = '100%'
|
||||
..height = '100%';
|
||||
|
@@ -49,7 +49,7 @@ class CreateAccountScreen extends HookConsumerWidget {
|
||||
showLoadingModal(context);
|
||||
final client = ref.watch(apiClientProvider);
|
||||
await client.post(
|
||||
'/accounts',
|
||||
'/id/accounts',
|
||||
data: {
|
||||
'name': usernameController.text,
|
||||
'nick': nicknameController.text,
|
||||
@@ -305,7 +305,7 @@ class _PostCreateModal extends HookConsumerWidget {
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
context.pushReplacement('/auth/login');
|
||||
context.pushReplacementNamed('login');
|
||||
},
|
||||
child: Text('login'.tr()),
|
||||
),
|
||||
|
@@ -178,7 +178,7 @@ class _LoginCheckScreen extends HookConsumerWidget {
|
||||
// Get token if challenge is completed
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final tokenResp = await client.post(
|
||||
'/auth/token',
|
||||
'/id/auth/token',
|
||||
data: {
|
||||
'grant_type': 'authorization_code',
|
||||
'code': code ?? challenge!.id,
|
||||
@@ -215,7 +215,7 @@ class _LoginCheckScreen extends HookConsumerWidget {
|
||||
if (name != null) {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
await client.patch(
|
||||
'/accounts/me/sessions/current/label',
|
||||
'/id/accounts/me/sessions/current/label',
|
||||
data: jsonEncode(name),
|
||||
);
|
||||
}
|
||||
@@ -225,6 +225,7 @@ class _LoginCheckScreen extends HookConsumerWidget {
|
||||
useEffect(() {
|
||||
if (challenge != null && challenge?.stepRemain == 0) {
|
||||
Future(() {
|
||||
if (isBusy.value) return;
|
||||
isBusy.value = true;
|
||||
getToken().catchError((err) {
|
||||
showErrorAlert(err);
|
||||
@@ -265,7 +266,7 @@ class _LoginCheckScreen extends HookConsumerWidget {
|
||||
// Pass challenge
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final resp = await client.patch(
|
||||
'/auth/challenge/${challenge!.id}',
|
||||
'/id/auth/challenge/${challenge!.id}',
|
||||
data: {'factor_id': factor!.id, 'password': pwd},
|
||||
);
|
||||
final result = SnAuthChallenge.fromJson(resp.data);
|
||||
@@ -412,7 +413,7 @@ class _LoginPickerScreen extends HookConsumerWidget {
|
||||
|
||||
try {
|
||||
await client.post(
|
||||
'/auth/challenge/${challenge!.id}/factors/${factorPicked.value!.id}',
|
||||
'/id/auth/challenge/${challenge!.id}/factors/${factorPicked.value!.id}',
|
||||
data:
|
||||
hintController.text.isNotEmpty
|
||||
? jsonEncode(hintController.text)
|
||||
@@ -555,7 +556,7 @@ class _LoginLookupScreen extends HookConsumerWidget {
|
||||
try {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
await client.post(
|
||||
'/accounts/recovery/password',
|
||||
'/id/accounts/recovery/password',
|
||||
data: {'account': uname, 'captcha_token': captchaTk},
|
||||
);
|
||||
showInfoAlert('loginResetPasswordSent'.tr(), 'done'.tr());
|
||||
@@ -573,7 +574,7 @@ class _LoginLookupScreen extends HookConsumerWidget {
|
||||
try {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final resp = await client.post(
|
||||
'/auth/challenge',
|
||||
'/id/auth/challenge',
|
||||
data: {
|
||||
'account': uname,
|
||||
'device_id': await getUdid(),
|
||||
@@ -593,7 +594,7 @@ class _LoginLookupScreen extends HookConsumerWidget {
|
||||
final result = SnAuthChallenge.fromJson(resp.data);
|
||||
onChallenge(result);
|
||||
final factorResp = await client.get(
|
||||
'/auth/challenge/${result.id}/factors',
|
||||
'/id/auth/challenge/${result.id}/factors',
|
||||
);
|
||||
onFactor(
|
||||
List<SnAuthFactor>.from(
|
||||
@@ -622,7 +623,7 @@ class _LoginLookupScreen extends HookConsumerWidget {
|
||||
|
||||
if (context.mounted) showLoadingModal(context);
|
||||
final resp = await client.post(
|
||||
'/auth/login/apple/mobile',
|
||||
'/id/auth/login/apple/mobile',
|
||||
data: {
|
||||
'identity_token': credential.identityToken!,
|
||||
'authorization_code': credential.authorizationCode,
|
||||
@@ -633,7 +634,7 @@ class _LoginLookupScreen extends HookConsumerWidget {
|
||||
final challenge = SnAuthChallenge.fromJson(resp.data);
|
||||
onChallenge(challenge);
|
||||
final factorResp = await client.get(
|
||||
'/auth/challenge/${challenge.id}/factors',
|
||||
'/id/auth/challenge/${challenge.id}/factors',
|
||||
);
|
||||
onFactor(
|
||||
List<SnAuthFactor>.from(
|
||||
@@ -658,11 +659,11 @@ class _LoginLookupScreen extends HookConsumerWidget {
|
||||
|
||||
final client = ref.watch(apiClientProvider);
|
||||
try {
|
||||
final resp = await client.get('/auth/challenge/$challengeId');
|
||||
final resp = await client.get('/id/auth/challenge/$challengeId');
|
||||
final challenge = SnAuthChallenge.fromJson(resp.data);
|
||||
onChallenge(challenge);
|
||||
final factorResp = await client.get(
|
||||
'/auth/challenge/${challenge.id}/factors',
|
||||
'/id/auth/challenge/${challenge.id}/factors',
|
||||
);
|
||||
onFactor(
|
||||
List<SnAuthFactor>.from(
|
||||
|
@@ -120,7 +120,7 @@ class _OidcScreenState extends ConsumerState<OidcScreen> {
|
||||
final queryParams = url.queryParameters;
|
||||
|
||||
// Check if we're on the token page
|
||||
if (path.endsWith('/auth/callback')) {
|
||||
if (path.endsWith('/id/auth/callback')) {
|
||||
// Extract token from URL
|
||||
final challenge = queryParams['challenge'];
|
||||
// Return the token and close the webview
|
||||
|
Reference in New Issue
Block a user