mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-06-08 03:54:49 +08:00
* fix: mob geetest * geetest ios patch --------- Co-authored-by: dom <githubaccount56556@proton.me>
295 lines
8.3 KiB
Dart
295 lines
8.3 KiB
Dart
import 'dart:convert' show base64, jsonDecode, jsonEncode, utf8;
|
|
import 'dart:io' show Platform;
|
|
|
|
import 'package:PiliPlus/http/browser_ua.dart';
|
|
import 'package:PiliPlus/http/init.dart';
|
|
import 'package:PiliPlus/http/loading_state.dart';
|
|
import 'package:PiliPlus/main.dart';
|
|
import 'package:PiliPlus/utils/accounts/account.dart';
|
|
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
|
import 'package:dio/dio.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
|
import 'package:get/get.dart';
|
|
|
|
class GeetestWebviewDialog extends StatefulWidget {
|
|
const GeetestWebviewDialog(this.gt, this.challenge, {super.key});
|
|
|
|
final String gt;
|
|
final String challenge;
|
|
|
|
@override
|
|
State<GeetestWebviewDialog> createState() => _GeetestWebviewDialogState();
|
|
|
|
static Future geetest(String gt, String challenge) {
|
|
return showDialog(
|
|
context: Get.context!,
|
|
builder: (context) => GeetestWebviewDialog(gt, challenge),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _GeetestWebviewDialogState extends State<GeetestWebviewDialog> {
|
|
static const _geetestJsUri =
|
|
'https://static.geetest.com/static/js/fullpage.0.0.0.js';
|
|
|
|
late final Future<LoadingState<String>> _future;
|
|
Webview? _linuxWebview;
|
|
late bool _linuxWebviewLoading = true;
|
|
|
|
String _showJs(String response) =>
|
|
't=Geetest($response).onSuccess(()=>R("success",t.getValidate())).onError(o=>R("error",o)).onClose(o=>R("close",o));t.onReady(()=>t.verify())';
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_future = _getConfig(widget.gt, widget.challenge);
|
|
if (Platform.isLinux) {
|
|
_initLinuxWebview();
|
|
}
|
|
}
|
|
|
|
static Future<LoadingState<String>> _getConfig(
|
|
String gt,
|
|
String challenge,
|
|
) async {
|
|
final res = await Request().get<String>(
|
|
'https://api.geetest.com/gettype.php',
|
|
queryParameters: {'gt': gt},
|
|
options: Options(
|
|
responseType: ResponseType.plain,
|
|
extra: {'account': const NoAccount()},
|
|
),
|
|
);
|
|
if (res.data case final String data) {
|
|
if (data.startsWith('(') && data.endsWith(')')) {
|
|
final Map<String, dynamic> config;
|
|
try {
|
|
config = jsonDecode(data.substring(1, data.length - 1));
|
|
} catch (e) {
|
|
return Error(e.toString());
|
|
}
|
|
if (config['status'] == 'success') {
|
|
return Success(
|
|
jsonEncode(
|
|
config['data'] as Map<String, dynamic>..addAll({
|
|
"gt": gt,
|
|
"challenge": challenge,
|
|
"offline": false,
|
|
"new_captcha": true,
|
|
"product": "bind",
|
|
"width": "100%",
|
|
"https": true,
|
|
"protocol": "https://",
|
|
}),
|
|
),
|
|
);
|
|
} else {
|
|
return Error(data);
|
|
}
|
|
}
|
|
}
|
|
return Error(res.data['message']);
|
|
}
|
|
|
|
Future<void> _initLinuxWebview() async {
|
|
final config = await _future;
|
|
|
|
if (!mounted) {
|
|
return;
|
|
}
|
|
|
|
if (config is Error) {
|
|
config.toast();
|
|
Get.back();
|
|
return;
|
|
}
|
|
|
|
final response = (config as Success<String>).response;
|
|
|
|
_linuxWebview = await WebviewWindow.create(
|
|
configuration: const CreateConfiguration(
|
|
windowWidth: 300,
|
|
windowHeight: 400,
|
|
title: "验证码",
|
|
),
|
|
);
|
|
|
|
if (!mounted) {
|
|
_closeLinuxWebview();
|
|
return;
|
|
}
|
|
|
|
_linuxWebview!.addOnWebMessageReceivedCallback((msg) {
|
|
final msgStr = msg.toString();
|
|
if (msgStr.startsWith("success:")) {
|
|
final dataStr = msgStr.substring("success:".length);
|
|
try {
|
|
final data = jsonDecode(dataStr);
|
|
Get.back(result: data);
|
|
} catch (e) {
|
|
debugPrint('geetest decode error: $e');
|
|
}
|
|
} else if (msgStr.startsWith("error:")) {
|
|
debugPrint('geetest error: $msgStr');
|
|
} else if (msgStr.startsWith('close:')) {
|
|
Get.back();
|
|
}
|
|
});
|
|
|
|
_linuxWebview!.onClose.whenComplete(() {
|
|
if (mounted) {
|
|
Get.back();
|
|
}
|
|
});
|
|
|
|
final html =
|
|
'''
|
|
<!DOCTYPE html><html><head></head><body>
|
|
<script src="$_geetestJsUri"></script>
|
|
<script>
|
|
R=(n,o)=>webkit.messageHandlers.msgToNative.postMessage(n+':'+JSON.stringify(o))
|
|
${_showJs(response)}
|
|
</script>
|
|
</body></html>
|
|
''';
|
|
|
|
_linuxWebview!.launch(
|
|
'data:text/html;base64,${base64.encode(utf8.encode(html))}',
|
|
);
|
|
|
|
if (mounted) {
|
|
setState(() {
|
|
_linuxWebviewLoading = false;
|
|
});
|
|
}
|
|
}
|
|
|
|
void _closeLinuxWebview() {
|
|
_linuxWebview?.close();
|
|
_linuxWebview = null;
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_closeLinuxWebview();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
if (Platform.isLinux) {
|
|
return AlertDialog(
|
|
title: const Text('验证码'),
|
|
content: SizedBox(
|
|
width: 300,
|
|
height: 400,
|
|
child: Center(
|
|
child: _linuxWebviewLoading
|
|
? const CircularProgressIndicator()
|
|
: const Text('请在弹出的新窗口中完成验证'),
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: Get.back,
|
|
child: Text(
|
|
'取消',
|
|
style: TextStyle(color: ColorScheme.of(context).outline),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
return AlertDialog(
|
|
title: const Text('验证码'),
|
|
content: SizedBox(
|
|
width: 320,
|
|
height: 400,
|
|
child: InAppWebView(
|
|
webViewEnvironment: webViewEnvironment,
|
|
initialSettings: InAppWebViewSettings(
|
|
clearCache: true,
|
|
javaScriptEnabled: true,
|
|
forceDark: ForceDark.AUTO,
|
|
useHybridComposition: false,
|
|
algorithmicDarkeningAllowed: true,
|
|
useShouldOverrideUrlLoading: true,
|
|
userAgent: BrowserUa.mob,
|
|
mixedContentMode: .MIXED_CONTENT_ALWAYS_ALLOW,
|
|
|
|
incognito: true,
|
|
allowFileAccess: false,
|
|
allowsLinkPreview: false,
|
|
allowContentAccess: false,
|
|
useOnDownloadStart: false,
|
|
geolocationEnabled: false,
|
|
thirdPartyCookiesEnabled: false,
|
|
enterpriseAuthenticationAppLinkPolicyEnabled: false,
|
|
saveFormData: false,
|
|
safeBrowsingEnabled: false,
|
|
isFraudulentWebsiteWarningEnabled: false,
|
|
domStorageEnabled: false,
|
|
databaseEnabled: false,
|
|
cacheEnabled: false,
|
|
cacheMode: .LOAD_NO_CACHE,
|
|
|
|
horizontalScrollBarEnabled: false,
|
|
verticalScrollBarEnabled: false,
|
|
overScrollMode: .NEVER,
|
|
),
|
|
initialData: InAppWebViewInitialData(
|
|
data:
|
|
'<!DOCTYPE html><html><head><meta name="viewport" content="width=device-width"></head><body><script src="$_geetestJsUri"></script><script>R=flutter_inappwebview.callHandler</script></body></html>',
|
|
),
|
|
onWebViewCreated: (ctr) {
|
|
ctr
|
|
..addJavaScriptHandler(
|
|
handlerName: 'success',
|
|
callback: (args) {
|
|
if (args.isNotEmpty) {
|
|
if (args[0] case Map<String, dynamic> data) {
|
|
Get.back(result: data);
|
|
return;
|
|
}
|
|
}
|
|
debugPrint('geetest invalid result: $args');
|
|
},
|
|
)
|
|
..addJavaScriptHandler(
|
|
handlerName: 'error',
|
|
callback: (args) {
|
|
debugPrint('geetest error: $args');
|
|
},
|
|
)
|
|
..addJavaScriptHandler(
|
|
handlerName: 'close',
|
|
callback: (args) => Get.back(),
|
|
);
|
|
},
|
|
onLoadStop: (ctr, _) async {
|
|
final config = await _future;
|
|
if (!mounted) return;
|
|
if (config case Success(:final response)) {
|
|
ctr.evaluateJavascript(source: _showJs(response));
|
|
} else {
|
|
config.toast();
|
|
Get.back();
|
|
}
|
|
},
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: Get.back,
|
|
child: Text(
|
|
'取消',
|
|
style: TextStyle(color: ColorScheme.of(context).outline),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|