mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-21 20:12:00 +00:00
feat: implement CF resolution server
This commit is contained in:
parent
1d81906c4f
commit
f06df9b3b1
3 changed files with 136 additions and 70 deletions
|
|
@ -50,6 +50,7 @@ DiscordRPC? discordRpc;
|
||||||
WebViewEnvironment? webViewEnvironment;
|
WebViewEnvironment? webViewEnvironment;
|
||||||
String? customDns;
|
String? customDns;
|
||||||
void main(List<String> args) async {
|
void main(List<String> args) async {
|
||||||
|
cfResolutionWebviewServer();
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
if (Platform.isLinux && runWebViewTitleBarWidget(args)) return;
|
if (Platform.isLinux && runWebViewTitleBarWidget(args)) return;
|
||||||
MediaKit.ensureInitialized();
|
MediaKit.ensureInitialized();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
import 'dart:convert';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:http_interceptor/http_interceptor.dart';
|
import 'package:http_interceptor/http_interceptor.dart';
|
||||||
import 'package:mangayomi/eval/model/m_bridge.dart';
|
import 'package:mangayomi/eval/model/m_bridge.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
@ -68,7 +70,7 @@ class MClient {
|
||||||
);
|
);
|
||||||
return InterceptedClient.build(
|
return InterceptedClient.build(
|
||||||
client: httpClient(settings: clientSettings, reqcopyWith: reqcopyWith),
|
client: httpClient(settings: clientSettings, reqcopyWith: reqcopyWith),
|
||||||
|
retryPolicy: ResolveCloudFlareChallenge(showCloudFlareError),
|
||||||
interceptors: [
|
interceptors: [
|
||||||
MCookieManager(reqcopyWith),
|
MCookieManager(reqcopyWith),
|
||||||
LoggerInterceptor(showCloudFlareError),
|
LoggerInterceptor(showCloudFlareError),
|
||||||
|
|
@ -256,78 +258,138 @@ bool isCloudflare(BaseResponse response) {
|
||||||
["cloudflare-nginx", "cloudflare"].contains(response.headers["server"]);
|
["cloudflare-nginx", "cloudflare"].contains(response.headers["server"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// class ResolveCloudFlareChallenge extends RetryPolicy {
|
class ResolveCloudFlareChallenge extends RetryPolicy {
|
||||||
// bool showCloudFlareError;
|
bool showCloudFlareError;
|
||||||
// ResolveCloudFlareChallenge(this.showCloudFlareError);
|
ResolveCloudFlareChallenge(this.showCloudFlareError);
|
||||||
// @override
|
@override
|
||||||
// int get maxRetryAttempts => 2;
|
int get maxRetryAttempts => 2;
|
||||||
// @override
|
@override
|
||||||
// Future<bool> shouldAttemptRetryOnResponse(BaseResponse response) async {
|
Future<bool> shouldAttemptRetryOnResponse(BaseResponse response) async {
|
||||||
// if (!showCloudFlareError || Platform.isLinux) return false;
|
if (!showCloudFlareError || Platform.isLinux) return false;
|
||||||
// flutter_inappwebview.HeadlessInAppWebView? headlessWebView;
|
bool isCloudFlare = isCloudflare(response);
|
||||||
// int time = 0;
|
if (isCloudFlare) {
|
||||||
// bool timeOut = false;
|
try {
|
||||||
// bool isCloudFlare = isCloudflare(response);
|
return http
|
||||||
// if (isCloudFlare) {
|
.post(
|
||||||
// headlessWebView = flutter_inappwebview.HeadlessInAppWebView(
|
Uri.parse('http://localhost:$cfPort/resolve_cf'),
|
||||||
// webViewEnvironment: webViewEnvironment,
|
headers: {HttpHeaders.contentTypeHeader: 'application/json'},
|
||||||
// initialUrlRequest: flutter_inappwebview.URLRequest(
|
body: jsonEncode({'url': response.request!.url.toString()}),
|
||||||
// url: flutter_inappwebview.WebUri(response.request!.url.toString()),
|
)
|
||||||
// ),
|
.then((res) {
|
||||||
// onLoadStop: (controller, url) async {
|
if (res.statusCode == 200) {
|
||||||
// try {
|
final data = jsonDecode(res.body) as Map<String, dynamic>;
|
||||||
// isCloudFlare = await controller.platform.evaluateJavascript(
|
return data['result'] as bool;
|
||||||
// source:
|
}
|
||||||
// "document.head.innerHTML.includes('#challenge-success-text')",
|
return false;
|
||||||
// );
|
});
|
||||||
// } catch (_) {
|
} catch (e) {
|
||||||
// isCloudFlare = false;
|
return false;
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// await Future.doWhile(() async {
|
return false;
|
||||||
// if (!timeOut && isCloudFlare) {
|
}
|
||||||
// try {
|
}
|
||||||
// isCloudFlare = await controller.platform.evaluateJavascript(
|
|
||||||
// source:
|
|
||||||
// "document.head.innerHTML.includes('#challenge-success-text')",
|
|
||||||
// );
|
|
||||||
// } catch (_) {
|
|
||||||
// isCloudFlare = false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (isCloudFlare) await Future.delayed(Duration(milliseconds: 300));
|
|
||||||
|
|
||||||
// return isCloudFlare;
|
int cfPort = 0;
|
||||||
// });
|
void cfResolutionWebviewServer() async {
|
||||||
// if (!timeOut) {
|
final server = await HttpServer.bind(InternetAddress.loopbackIPv4, cfPort);
|
||||||
// final ua =
|
cfPort = server.port;
|
||||||
// await controller.evaluateJavascript(
|
|
||||||
// source: "navigator.userAgent",
|
|
||||||
// ) ??
|
|
||||||
// "";
|
|
||||||
// await MClient.setCookie(url.toString(), ua, controller);
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
|
|
||||||
// headlessWebView.run();
|
server.listen((HttpRequest request) {
|
||||||
|
if (request.method == 'POST' && request.uri.path == '/resolve_cf') {
|
||||||
|
_handleResolveCf(request);
|
||||||
|
} else {
|
||||||
|
request.response
|
||||||
|
..statusCode = HttpStatus.notFound
|
||||||
|
..write('Not Found')
|
||||||
|
..close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// await Future.doWhile(() async {
|
void _handleResolveCf(HttpRequest request) async {
|
||||||
// timeOut = time == 15;
|
int time = 0;
|
||||||
// if (!isCloudFlare || timeOut) {
|
bool timeOut = false;
|
||||||
// return false;
|
bool isCloudFlare = true;
|
||||||
// }
|
try {
|
||||||
// await Future.delayed(const Duration(seconds: 1));
|
final body = await utf8.decoder.bind(request).join();
|
||||||
// time++;
|
final data = jsonDecode(body) as Map<String, dynamic>;
|
||||||
// return true;
|
final url = data['url'] as String?;
|
||||||
// });
|
|
||||||
// try {
|
|
||||||
// headlessWebView.dispose();
|
|
||||||
// } catch (_) {}
|
|
||||||
|
|
||||||
// return true;
|
if (url == null) {
|
||||||
// }
|
request.response
|
||||||
|
..statusCode = HttpStatus.badRequest
|
||||||
|
..write(jsonEncode({'error': 'Missing url parameter'}))
|
||||||
|
..close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// return false;
|
flutter_inappwebview.HeadlessInAppWebView? headlessWebView;
|
||||||
// }
|
headlessWebView = flutter_inappwebview.HeadlessInAppWebView(
|
||||||
// }
|
webViewEnvironment: webViewEnvironment,
|
||||||
|
initialUrlRequest: flutter_inappwebview.URLRequest(
|
||||||
|
url: flutter_inappwebview.WebUri(url),
|
||||||
|
),
|
||||||
|
onLoadStop: (controller, url) async {
|
||||||
|
try {
|
||||||
|
isCloudFlare = await controller.platform.evaluateJavascript(
|
||||||
|
source:
|
||||||
|
"document.head.innerHTML.includes('#challenge-success-text')",
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
isCloudFlare = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Future.doWhile(() async {
|
||||||
|
if (!timeOut && isCloudFlare) {
|
||||||
|
try {
|
||||||
|
isCloudFlare = await controller.platform.evaluateJavascript(
|
||||||
|
source:
|
||||||
|
"document.head.innerHTML.includes('#challenge-success-text')",
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
isCloudFlare = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isCloudFlare) await Future.delayed(Duration(milliseconds: 300));
|
||||||
|
|
||||||
|
return isCloudFlare;
|
||||||
|
});
|
||||||
|
if (!timeOut) {
|
||||||
|
final ua =
|
||||||
|
await controller.evaluateJavascript(
|
||||||
|
source: "navigator.userAgent",
|
||||||
|
) ??
|
||||||
|
"";
|
||||||
|
await MClient.setCookie(url.toString(), ua, controller);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
headlessWebView.run();
|
||||||
|
|
||||||
|
await Future.doWhile(() async {
|
||||||
|
timeOut = time == 15;
|
||||||
|
if (!isCloudFlare || timeOut) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
|
time++;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
headlessWebView.dispose();
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
request.response
|
||||||
|
..headers.contentType = ContentType.json
|
||||||
|
..write(jsonEncode({'result': isCloudFlare}))
|
||||||
|
..close();
|
||||||
|
} catch (e) {
|
||||||
|
request.response
|
||||||
|
..statusCode = HttpStatus.badRequest
|
||||||
|
..write(jsonEncode({'error': 'Invalid JSON'}))
|
||||||
|
..close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import 'package:mangayomi/eval/lib.dart';
|
||||||
import 'package:mangayomi/main.dart';
|
import 'package:mangayomi/main.dart';
|
||||||
import 'package:mangayomi/models/source.dart';
|
import 'package:mangayomi/models/source.dart';
|
||||||
import 'package:mangayomi/providers/storage_provider.dart';
|
import 'package:mangayomi/providers/storage_provider.dart';
|
||||||
|
import 'package:mangayomi/services/http/m_client.dart';
|
||||||
import 'package:mangayomi/utils/log/log.dart';
|
import 'package:mangayomi/utils/log/log.dart';
|
||||||
|
|
||||||
class _IsolateData {
|
class _IsolateData {
|
||||||
|
|
@ -103,6 +104,7 @@ class GetIsolateService {
|
||||||
final serviceType = message['serviceType'] as String?;
|
final serviceType = message['serviceType'] as String?;
|
||||||
final useLoggerValue = message['useLogger'] as bool?;
|
final useLoggerValue = message['useLogger'] as bool?;
|
||||||
final responsePort = message['responsePort'] as SendPort;
|
final responsePort = message['responsePort'] as SendPort;
|
||||||
|
cfPort = message['cfPort'] as int;
|
||||||
if (useLoggerValue != null) {
|
if (useLoggerValue != null) {
|
||||||
useLogger = useLoggerValue;
|
useLogger = useLoggerValue;
|
||||||
}
|
}
|
||||||
|
|
@ -195,6 +197,7 @@ class GetIsolateService {
|
||||||
'proxyServer': proxyServer,
|
'proxyServer': proxyServer,
|
||||||
'responsePort': responsePort.sendPort,
|
'responsePort': responsePort.sendPort,
|
||||||
'useLogger': useLogger,
|
'useLogger': useLogger,
|
||||||
|
'cfPort': cfPort,
|
||||||
});
|
});
|
||||||
|
|
||||||
return completer.future;
|
return completer.future;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue