fix: 因 RSI 官网变更,移除自动填充功能 (不再支持)

This commit is contained in:
2024-04-26 22:55:38 +08:00
parent 2c71f3baba
commit d2694a1e25
24 changed files with 12 additions and 515 deletions

View File

@ -42,13 +42,6 @@ class HomeGameLoginDialogUI extends HookConsumerWidget {
Text(S.current.home_title_logging_in),
const SizedBox(height: 12),
const ProgressRing(),
if (loginState.isDeviceSupportWinHello ?? false)
const SizedBox(height: 24),
Text(
S.current.home_info_auto_fill_notice,
style: TextStyle(
fontSize: 13, color: Colors.white.withOpacity(.6)),
)
],
),
),

View File

@ -4,16 +4,13 @@ import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hive/hive.dart';
import 'package:local_auth/local_auth.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:cryptography/cryptography.dart';
import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:jwt_decode/jwt_decode.dart';
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/common/utils/provider.dart';
import 'package:starcitizen_doctor/common/win32/credentials.dart';
import 'package:starcitizen_doctor/data/rsi_game_library_data.dart';
import 'package:starcitizen_doctor/ui/home/home_ui_model.dart';
import 'package:starcitizen_doctor/ui/webview/webview.dart';
@ -46,25 +43,20 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
return HomeGameLoginState(loginStatus: 0);
}
final LocalAuthentication _localAuth = LocalAuthentication();
// ignore: avoid_build_context_in_providers
Future<void> launchWebLogin(BuildContext context) async {
final homeState = ref.read(homeUIModelProvider);
final isDeviceSupportWinHello = await _localAuth.isDeviceSupported();
state = state.copyWith(isDeviceSupportWinHello: isDeviceSupportWinHello);
if (!context.mounted) return;
goWebView(context, S.current.home_action_login_rsi_account,
"https://robertsspaceindustries.com/connect", loginMode: true,
rsiLoginCallback: (message, ok) async {
"https://robertsspaceindustries.com/connect?jumpto=/connect",
loginMode: true, rsiLoginCallback: (message, ok) async {
// dPrint(
// "======rsiLoginCallback=== $ok ===== data==\n${json.encode(message)}");
if (message == null || !ok) {
Navigator.pop(context);
return;
}
dPrint("web message == $message");
// final emailBox = await Hive.openBox("quick_login_email");
final data = message["data"];
final authToken = data["authToken"];
@ -78,13 +70,6 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
final Map<String, dynamic> payload = Jwt.parseJwt(authToken!);
final nickname = payload["nickname"] ?? "";
final inputEmail = data["inputEmail"];
final inputPassword = data["inputPassword"];
final userBox = await Hive.openBox("rsi_account_data");
if (inputEmail != null && inputEmail != "") {
await userBox.put("account_email", inputEmail);
}
state = state.copyWith(
nickname: nickname,
avatarUrl: avatarUrl,
@ -94,37 +79,11 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
libraryData: libraryData,
);
if (isDeviceSupportWinHello) {
if (await userBox.get("enable", defaultValue: true)) {
if (inputEmail != null &&
inputEmail != "" &&
inputPassword != null &&
inputPassword != "") {
if (!context.mounted) return;
final ok = await showConfirmDialogs(
context,
S.current.home_action_q_auto_password_fill_prompt,
Text(S.current.home_login_info_password_encryption_notice));
if (ok == true) {
if (await _localAuth.authenticate(
localizedReason:
S.current.home_login_info_enter_pin_to_encrypt) ==
true) {
await _savePwd(inputEmail, inputPassword);
}
} else {
await userBox.put("enable", false);
}
}
}
}
final buildInfoFile =
File("${homeState.scInstalledPath}\\build_manifest.id");
if (await buildInfoFile.exists()) {
final buildInfo =
json.decode(await buildInfoFile.readAsString())["Data"];
dPrint("buildInfo ======= $buildInfo");
if (releaseInfo?["versionLabel"] != null &&
buildInfo["RequestedP4ChangeNum"] != null) {
@ -265,33 +224,4 @@ class HomeGameLoginUIModel extends _$HomeGameLoginUIModel {
}
return "PTU";
}
_savePwd(String inputEmail, String inputPassword) async {
final algorithm = AesGcm.with256bits();
final secretKey = await algorithm.newSecretKey();
final nonce = algorithm.newNonce();
final secretBox = await algorithm.encrypt(utf8.encode(inputPassword),
secretKey: secretKey, nonce: nonce);
await algorithm.decrypt(
SecretBox(secretBox.cipherText,
nonce: secretBox.nonce, mac: secretBox.mac),
secretKey: secretKey);
final pwdEncrypted = base64.encode(secretBox.cipherText);
final userBox = await Hive.openBox("rsi_account_data");
await userBox.put("account_email", inputEmail);
await userBox.put("account_pwd_encrypted", pwdEncrypted);
await userBox.put("nonce", base64.encode(secretBox.nonce));
await userBox.put("mac", base64.encode(secretBox.mac.bytes));
final secretKeyStr = base64.encode((await secretKey.extractBytes()));
Win32Credentials.write(
credentialName: "SCToolbox_RSI_Account_secret",
userName: inputEmail,
password: secretKeyStr);
}
}

View File

@ -7,7 +7,7 @@ part of 'home_game_login_dialog_ui_model.dart';
// **************************************************************************
String _$homeGameLoginUIModelHash() =>
r'55ae072fdc222a015661e50f2d8d60e95911ce14';
r'862fac9e29e55937e1246542feac75cf55062182';
/// See also [HomeGameLoginUIModel].
@ProviderFor(HomeGameLoginUIModel)

View File

@ -2,7 +2,6 @@ import 'package:fluent_ui/fluent_ui.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:starcitizen_doctor/app.dart';
import 'package:starcitizen_doctor/common/conf/const_conf.dart';
import 'package:starcitizen_doctor/generated/l10n.dart';
import 'package:starcitizen_doctor/ui/settings/settings_ui_model.dart';
@ -31,23 +30,6 @@ class SettingsUI extends HookConsumerWidget {
S.current.setting_action_create_settings_shortcut,
subTitle: S.current.setting_action_create_desktop_shortcut,
onTap: () => model.addShortCut(context)),
if (ConstConf.isMSE) ...[
const SizedBox(height: 12),
makeSettingsItem(const Icon(FluentIcons.reset_device, size: 20),
S.current.setting_action_reset_auto_password_fill,
subTitle: S.current.setting_action_info_device_support_info(
sate.isEnableAutoLogin
? S.current.setting_action_info_enabled
: S.current.setting_action_info_disabled,
sate.isDeviceSupportWinHello
? S.current.setting_action_info_support
: S.current.setting_action_info_not_support,
sate.autoLoginEmail,
sate.isEnableAutoLoginPwd
? S.current.setting_action_info_encrypted_saved
: S.current.setting_action_info_not_saved),
onTap: () => model.onResetAutoLogin(context)),
],
const SizedBox(height: 12),
makeSettingsItem(const Icon(FontAwesomeIcons.microchip, size: 20),
S.current.setting_action_ignore_efficiency_cores_on_launch,
@ -176,4 +158,4 @@ class SettingsUI extends HookConsumerWidget {
),
);
}
}
}

View File

@ -6,13 +6,11 @@ import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/services.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hive/hive.dart';
import 'package:local_auth/local_auth.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:starcitizen_doctor/common/conf/const_conf.dart';
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/common/utils/provider.dart';
import 'package:starcitizen_doctor/common/win32/credentials.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
part 'settings_ui_model.g.dart';
@ -22,10 +20,6 @@ part 'settings_ui_model.freezed.dart';
@freezed
class SettingsUIState with _$SettingsUIState {
factory SettingsUIState({
@Default(false) isDeviceSupportWinHello,
@Default("-") String autoLoginEmail,
@Default(false) bool isEnableAutoLogin,
@Default(false) bool isEnableAutoLoginPwd,
@Default(false) bool isEnableToolSiteMirrors,
@Default("0") String inputGameLaunchECore,
String? customLauncherPath,
@ -44,47 +38,12 @@ class SettingsUIModel extends _$SettingsUIModel {
}
void _initState() async {
final LocalAuthentication localAuth = LocalAuthentication();
final isDeviceSupportWinHello = await localAuth.isDeviceSupported();
state = state.copyWith(isDeviceSupportWinHello: isDeviceSupportWinHello);
_updateGameLaunchECore();
if (ConstConf.isMSE) {
_updateAutoLoginAccount();
}
_loadCustomPath();
_loadLocationCacheSize();
_loadToolSiteMirrorState();
}
Future<void> onResetAutoLogin(BuildContext context) async {
final ok = await showConfirmDialogs(
context,
S.current.setting_action_info_confirm_reset_autofill,
Text(S.current.setting_action_info_delete_local_account_warning));
if (ok) {
final userBox = await Hive.openBox("rsi_account_data");
await userBox.deleteFromDisk();
Win32Credentials.delete("SCToolbox_RSI_Account_secret");
if (!context.mounted) return;
showToast(context, S.current.setting_action_info_autofill_data_cleared);
_initState();
}
}
Future _updateAutoLoginAccount() async {
final userBox = await Hive.openBox("rsi_account_data");
final autoLoginEmail = userBox.get("account_email", defaultValue: "-");
final isEnableAutoLogin = userBox.get("enable", defaultValue: true);
final isEnableAutoLoginPwd =
userBox.get("account_pwd_encrypted", defaultValue: "") != "";
state = state.copyWith(
autoLoginEmail: autoLoginEmail,
isEnableAutoLogin: isEnableAutoLogin,
isEnableAutoLoginPwd: isEnableAutoLoginPwd);
}
Future<void> setGameLaunchECore(BuildContext context) async {
final userBox = await Hive.openBox("app_conf");
final defaultInput =

View File

@ -17,9 +17,6 @@ final _privateConstructorUsedError = UnsupportedError(
/// @nodoc
mixin _$SettingsUIState {
dynamic get isDeviceSupportWinHello => throw _privateConstructorUsedError;
String get autoLoginEmail => throw _privateConstructorUsedError;
bool get isEnableAutoLogin => throw _privateConstructorUsedError;
bool get isEnableAutoLoginPwd => throw _privateConstructorUsedError;
bool get isEnableToolSiteMirrors => throw _privateConstructorUsedError;
String get inputGameLaunchECore => throw _privateConstructorUsedError;
String? get customLauncherPath => throw _privateConstructorUsedError;
@ -39,9 +36,6 @@ abstract class $SettingsUIStateCopyWith<$Res> {
@useResult
$Res call(
{dynamic isDeviceSupportWinHello,
String autoLoginEmail,
bool isEnableAutoLogin,
bool isEnableAutoLoginPwd,
bool isEnableToolSiteMirrors,
String inputGameLaunchECore,
String? customLauncherPath,
@ -63,9 +57,6 @@ class _$SettingsUIStateCopyWithImpl<$Res, $Val extends SettingsUIState>
@override
$Res call({
Object? isDeviceSupportWinHello = freezed,
Object? autoLoginEmail = null,
Object? isEnableAutoLogin = null,
Object? isEnableAutoLoginPwd = null,
Object? isEnableToolSiteMirrors = null,
Object? inputGameLaunchECore = null,
Object? customLauncherPath = freezed,
@ -77,18 +68,6 @@ class _$SettingsUIStateCopyWithImpl<$Res, $Val extends SettingsUIState>
? _value.isDeviceSupportWinHello
: isDeviceSupportWinHello // ignore: cast_nullable_to_non_nullable
as dynamic,
autoLoginEmail: null == autoLoginEmail
? _value.autoLoginEmail
: autoLoginEmail // ignore: cast_nullable_to_non_nullable
as String,
isEnableAutoLogin: null == isEnableAutoLogin
? _value.isEnableAutoLogin
: isEnableAutoLogin // ignore: cast_nullable_to_non_nullable
as bool,
isEnableAutoLoginPwd: null == isEnableAutoLoginPwd
? _value.isEnableAutoLoginPwd
: isEnableAutoLoginPwd // ignore: cast_nullable_to_non_nullable
as bool,
isEnableToolSiteMirrors: null == isEnableToolSiteMirrors
? _value.isEnableToolSiteMirrors
: isEnableToolSiteMirrors // ignore: cast_nullable_to_non_nullable
@ -123,9 +102,6 @@ abstract class _$$SettingsUIStateImplCopyWith<$Res>
@useResult
$Res call(
{dynamic isDeviceSupportWinHello,
String autoLoginEmail,
bool isEnableAutoLogin,
bool isEnableAutoLoginPwd,
bool isEnableToolSiteMirrors,
String inputGameLaunchECore,
String? customLauncherPath,
@ -145,9 +121,6 @@ class __$$SettingsUIStateImplCopyWithImpl<$Res>
@override
$Res call({
Object? isDeviceSupportWinHello = freezed,
Object? autoLoginEmail = null,
Object? isEnableAutoLogin = null,
Object? isEnableAutoLoginPwd = null,
Object? isEnableToolSiteMirrors = null,
Object? inputGameLaunchECore = null,
Object? customLauncherPath = freezed,
@ -158,18 +131,6 @@ class __$$SettingsUIStateImplCopyWithImpl<$Res>
isDeviceSupportWinHello: freezed == isDeviceSupportWinHello
? _value.isDeviceSupportWinHello!
: isDeviceSupportWinHello,
autoLoginEmail: null == autoLoginEmail
? _value.autoLoginEmail
: autoLoginEmail // ignore: cast_nullable_to_non_nullable
as String,
isEnableAutoLogin: null == isEnableAutoLogin
? _value.isEnableAutoLogin
: isEnableAutoLogin // ignore: cast_nullable_to_non_nullable
as bool,
isEnableAutoLoginPwd: null == isEnableAutoLoginPwd
? _value.isEnableAutoLoginPwd
: isEnableAutoLoginPwd // ignore: cast_nullable_to_non_nullable
as bool,
isEnableToolSiteMirrors: null == isEnableToolSiteMirrors
? _value.isEnableToolSiteMirrors
: isEnableToolSiteMirrors // ignore: cast_nullable_to_non_nullable
@ -199,9 +160,6 @@ class __$$SettingsUIStateImplCopyWithImpl<$Res>
class _$SettingsUIStateImpl implements _SettingsUIState {
_$SettingsUIStateImpl(
{this.isDeviceSupportWinHello = false,
this.autoLoginEmail = "-",
this.isEnableAutoLogin = false,
this.isEnableAutoLoginPwd = false,
this.isEnableToolSiteMirrors = false,
this.inputGameLaunchECore = "0",
this.customLauncherPath,
@ -213,15 +171,6 @@ class _$SettingsUIStateImpl implements _SettingsUIState {
final dynamic isDeviceSupportWinHello;
@override
@JsonKey()
final String autoLoginEmail;
@override
@JsonKey()
final bool isEnableAutoLogin;
@override
@JsonKey()
final bool isEnableAutoLoginPwd;
@override
@JsonKey()
final bool isEnableToolSiteMirrors;
@override
@JsonKey()
@ -236,7 +185,7 @@ class _$SettingsUIStateImpl implements _SettingsUIState {
@override
String toString() {
return 'SettingsUIState(isDeviceSupportWinHello: $isDeviceSupportWinHello, autoLoginEmail: $autoLoginEmail, isEnableAutoLogin: $isEnableAutoLogin, isEnableAutoLoginPwd: $isEnableAutoLoginPwd, isEnableToolSiteMirrors: $isEnableToolSiteMirrors, inputGameLaunchECore: $inputGameLaunchECore, customLauncherPath: $customLauncherPath, customGamePath: $customGamePath, locationCacheSize: $locationCacheSize)';
return 'SettingsUIState(isDeviceSupportWinHello: $isDeviceSupportWinHello, isEnableToolSiteMirrors: $isEnableToolSiteMirrors, inputGameLaunchECore: $inputGameLaunchECore, customLauncherPath: $customLauncherPath, customGamePath: $customGamePath, locationCacheSize: $locationCacheSize)';
}
@override
@ -246,12 +195,6 @@ class _$SettingsUIStateImpl implements _SettingsUIState {
other is _$SettingsUIStateImpl &&
const DeepCollectionEquality().equals(
other.isDeviceSupportWinHello, isDeviceSupportWinHello) &&
(identical(other.autoLoginEmail, autoLoginEmail) ||
other.autoLoginEmail == autoLoginEmail) &&
(identical(other.isEnableAutoLogin, isEnableAutoLogin) ||
other.isEnableAutoLogin == isEnableAutoLogin) &&
(identical(other.isEnableAutoLoginPwd, isEnableAutoLoginPwd) ||
other.isEnableAutoLoginPwd == isEnableAutoLoginPwd) &&
(identical(
other.isEnableToolSiteMirrors, isEnableToolSiteMirrors) ||
other.isEnableToolSiteMirrors == isEnableToolSiteMirrors) &&
@ -269,9 +212,6 @@ class _$SettingsUIStateImpl implements _SettingsUIState {
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(isDeviceSupportWinHello),
autoLoginEmail,
isEnableAutoLogin,
isEnableAutoLoginPwd,
isEnableToolSiteMirrors,
inputGameLaunchECore,
customLauncherPath,
@ -289,9 +229,6 @@ class _$SettingsUIStateImpl implements _SettingsUIState {
abstract class _SettingsUIState implements SettingsUIState {
factory _SettingsUIState(
{final dynamic isDeviceSupportWinHello,
final String autoLoginEmail,
final bool isEnableAutoLogin,
final bool isEnableAutoLoginPwd,
final bool isEnableToolSiteMirrors,
final String inputGameLaunchECore,
final String? customLauncherPath,
@ -301,12 +238,6 @@ abstract class _SettingsUIState implements SettingsUIState {
@override
dynamic get isDeviceSupportWinHello;
@override
String get autoLoginEmail;
@override
bool get isEnableAutoLogin;
@override
bool get isEnableAutoLoginPwd;
@override
bool get isEnableToolSiteMirrors;
@override
String get inputGameLaunchECore;

View File

@ -6,7 +6,7 @@ part of 'settings_ui_model.dart';
// RiverpodGenerator
// **************************************************************************
String _$settingsUIModelHash() => r'aab08176293b380f09c89e006f373fbfd7a7ba16';
String _$settingsUIModelHash() => r'897176bc24ec5397cce0dd1ceea58338ac7841e0';
/// See also [SettingsUIModel].
@ProviderFor(SettingsUIModel)

View File

@ -3,17 +3,14 @@
import 'dart:async';
import 'dart:convert';
import 'package:cryptography/cryptography.dart';
import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:hive/hive.dart';
import 'package:local_auth/local_auth.dart';
import 'package:starcitizen_doctor/common/conf/url_conf.dart';
import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/common/win32/credentials.dart';
import 'package:starcitizen_doctor/data/app_version_data.dart';
import 'package:starcitizen_doctor/data/app_web_localization_versions_data.dart';
@ -188,7 +185,6 @@ class WebViewModel {
final message = json.decode(messageString);
if (message["action"] == "webview_rsi_login_show_window") {
webview.setWebviewWindowVisibility(true);
_checkAutoLogin(webview);
} else if (message["action"] == "webview_rsi_login_success") {
_loginModeSuccess = true;
loginCallback?.call(message, true);
@ -302,39 +298,4 @@ class WebViewModel {
}
_isClosed = true;
}
Future<void> _checkAutoLogin(Webview webview) async {
final LocalAuthentication localAuth = LocalAuthentication();
if (!await localAuth.isDeviceSupported()) return;
final userBox = await Hive.openBox("rsi_account_data");
final email = await userBox.get("account_email", defaultValue: "");
final pwdE = await userBox.get("account_pwd_encrypted", defaultValue: "");
final nonceStr = await userBox.get("nonce", defaultValue: "");
final macStr = await userBox.get("mac", defaultValue: "");
if (email == "") return;
webview.evaluateJavaScript("RSIAutoLogin(\"$email\",\"\")");
if (pwdE != "" && nonceStr != "" && macStr != "") {
// send toast
final toastMsg =
S.current.webview_localization_device_windows_hello_toast;
webview.evaluateJavaScript("SCTShowToast(\"$toastMsg\")");
// decrypt
if (await localAuth.authenticate(
localizedReason:
S.current.webview_localization_enter_device_pin) !=
true) return;
final kv = Win32Credentials.read("SCToolbox_RSI_Account_secret");
if (kv == null || kv.key != email) return;
final algorithm = AesGcm.with256bits();
final r = await algorithm.decrypt(
SecretBox(base64.decode(pwdE),
nonce: base64.decode(nonceStr), mac: Mac(base64.decode(macStr))),
secretKey: SecretKey(base64.decode(kv.value)));
final decryptedPwd = utf8.decode(r);
webview.evaluateJavaScript("RSIAutoLogin(\"$email\",\"$decryptedPwd\")");
}
}
}