Closed WeebNetsu closed 1 year ago
Host is protected via cloudflare, you must provide valid cf_clearance cookie and user agent to make it work. See advanced example: https://github.com/Zekfad/nhentai_dart/blob/984ce5ef3e8b872a6b8b36851158699b9f992862/example/cookie.dart#L12-L20
Thank you for your reply!
After getting the cookies and setting the user agent, I still have this issue... Here i printed out some of the details from the error. It seems to be similar to #2 where it is loading cloudflare. SInce I provided a (valid) cookie, should it not skip it?
originalException:
FormatException: Unexpected character (at character 1)
<!DOCTYPE html>
^
message: Bad response type
reasonPhrase: Forbidden
headers:
{connection: close, cache-control: private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, transfer-encoding: chunked, date: Sun, 16 Jul 2023 11:05:35 GMT, content-encoding: gzip, vary: Accept-Encoding, permissions-policy: accelerometer=(),autoplay=(),camera=(),clipboard-read=(),clipboard-write=(),geolocation=(),gyroscope=(),hid=(),interest-cohort=(),magnetometer=(),microphone=(),payment=(),publickey-credentials-get=(),screen-wake-lock=(),serial=(),sync-xhr=(),usb=(), referrer-policy: same-origin, report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=uX%2Fbic%2F63TztEwQ%2FP8t3Evk%2FpvXylkm5KkOrGI3IMFFvEcd62RbjJWigSBhIFmAOK3Cb%2FhkoMa6iRs2VGuOpKjxAKq3YudBqr6J5RRJ140pS9Vl1ovYZ%2FGfDQ2qL"}],"group":"cf-nel","max_age":604800}, cross-origin-opener-policy: same-origin, content-type: text/html; charset=UTF-8, cross-origin-embedder-policy: require-corp, server: cloudflare, cf-mitigated: challenge, cross-origin-resource-policy: same-origin, nel: {"success_fr
statusCode: 403
request
method: GET
headers:
{cookie: cf_clearance=3L1OOZ1qLd70K3zRhFQXz76iq_IuPx_l7yC9ff1jkCs-1689503608-0-250; HttpOnly; csrftoken=cP03hL0aevSvgzYs9ErsvDpRxWr9r5Am6EoDEofkrAlVBlt5oObMT6b1mX4o4XvH; HttpOnly}
url: https://nhentai.net/api/gallery/177013
Here is my user agent I got from fk_user_agent
, if it might be important: Dalvik/2.1.0 (Linux; U; Android 13; sdk_gphone_x86_64 Build/TE1A.220922.025)
After looking at your example again, could it be that I have to use a proxy?
The condition behind cf_clearance is single token corresponds to single User Agent and IP address, meaning if you obtain token from browser, you must use browser's User Agent (or complete challenge by setting browser's UA to module's).
From what I know, you could use WebView to implement cookie grabber.
Proxy from my example comes from the fact that the site is blocked in the country.
YES! Thank you my friend, so turns out the issue was that the user agent used by flutter_webview was not the same user agent returned by fk_user_agent, which caused it to continuously fail the check!
For anyone else who might be in a similar bind in the future, here is a snippet of my solution:
WebView:
import 'package:fk_user_agent/fk_user_agent.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:nclientv3/constants/constants.dart';
import 'package:nclientv3/models/cook.dart';
import 'package:nclientv3/utils/utils.dart';
import 'package:webview_cookie_manager/webview_cookie_manager.dart';
import 'package:webview_flutter/webview_flutter.dart';
class NotARobotView extends StatefulWidget {
const NotARobotView({super.key});
static route() => MaterialPageRoute(
builder: (context) => const NotARobotView(),
);
@override
State<NotARobotView> createState() => _NotARobotViewState();
}
class _NotARobotViewState extends State<NotARobotView> {
@override
void initState() {
super.initState();
}
final controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0x00000000))
..setNavigationDelegate(
NavigationDelegate(
onPageStarted: (String url) async {
final currentUserAgent = await WebViewController().runJavaScriptReturningResult('navigator.userAgent');
// NOTE THIS! You need to save this value to use as your user agent!!!
debugPrint(currentUserAgent.toString());
},
onUrlChange: (change) async {
if (change.url == NHentaiConstants.url) {
final realCookieManager = WebviewCookieManager();
final gotCookies = await realCookieManager.getCookies(NHentaiConstants.url);
// save your cookies (cooks is a global variable used for testing)
cooks = gotCookies;
saveCookieData(gotCookies);
}
},
),
)
..loadRequest(Uri.parse(NHentaiConstants.url));
@override
Widget build(BuildContext context) {
return Scaffold(
body: WebViewWidget(controller: controller),
);
}
}
Component contacting API:
import 'package:fk_user_agent/fk_user_agent.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:nclientv3/models/cook.dart';
import 'package:nclientv3/utils/utils.dart';
import 'package:nhentai/before_request_add_cookies.dart';
import 'package:nhentai/nhentai.dart' as nh;
class BrowseView extends StatefulWidget {
const BrowseView({super.key});
static route() => MaterialPageRoute(
builder: (context) => const BrowseView(),
);
@override
State<BrowseView> createState() => _BrowseViewState();
}
class _BrowseViewState extends State<BrowseView> {
@override
void initState() {
super.initState();
}
void setNotRobot() {
Navigator.pushNamed(context, "/not-a-robot");
}
void getData() async {
final t = await loadCookieData();
if (t == null || t.isEmpty) {
return setNotRobot();
}
final api = nh.API(
userAgent:
// NOTE HERE: You need to pass in the user agent you got inside your webview
"Mozilla/5.0 (Linux; Android 13; sdk_gphone_x86_64 Build/TE1A.220922.025; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/103.0.5060.71 Mobile Safari/537.36",
beforeRequest: beforeRequestAddCookiesStatic(
// the cookies (cooks - global variable that I stored the cookies in)
cooks,
),
);
try {
/// Throws if book is not found, or parse failed, see docs.
final nh.Book book = await api.getBook(177013);
// Short book summary
debugPrint('Book: $book\n');
} on nh.ApiClientException catch (e) {
debugPrint('url ${e.request?.url}');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
children: [
MaterialButton(
onPressed: getData,
child: const Text('Get data'),
),
MaterialButton(
onPressed: setNotRobot,
child: const Text('Fetch Tokens'),
),
],
),
),
),
),
);
}
}
Thanks a ton for your help and patience @Zekfad !
You're welcome!
I tried using the example you provided in the readme:
I seem to be getting a 403 error response. This is currently only running in a basic Dart project , no Flutter or anything else
It is making a request to
https://nhentai.net/api/gallery/177013
which when visited in browser seems to work fine