package ar.rulosoft.navegadores;
import android.util.Log;
import com.squareup.duktape.Duktape;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* Resolver based on habrahabr.ru/post/258101/.
*/
public class CFInterceptor implements Interceptor {
private final static Pattern OPERATION_PATTERN = Pattern.compile("setTimeout\\(function\\(\\)\\{\\s+(var .,.,.,.[\\s\\S]+?a\\.value = .+?)\r?\n");
private final static Pattern PASS_PATTERN = Pattern.compile("name=\"pass\" value=\"(.+?)\"");
private final static Pattern CHALLENGE_PATTERN = Pattern.compile("name=\"jschl_vc\" value=\"(\\w+)\"");
public static String getFirstMatch(Pattern p, String source) {
Matcher m = p.matcher(source);
if (m.find()) {
return m.group(1);
}
return null;
}
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
if (response.code() == 503 && response.headers().get("Server").contains("cloudflare")) {
return resolveOverCF(chain, response);
}
return response;
}
public Response resolveOverCF(Chain chain, Response response) throws IOException {
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Request request = response.request();
String content = response.body().string();
String domain = request.url().host().trim();
String rawOperation = getFirstMatch(OPERATION_PATTERN, content);
String challenge = getFirstMatch(CHALLENGE_PATTERN, content);
String challengePass = getFirstMatch(PASS_PATTERN, content);
if (rawOperation == null || challengePass == null || challenge == null) {
Log.e("CFI", "couldn't resolve over cloudflare");
return response; // returning null here is not a good idea since it could stop a download ~xtj-9182
}
String operation = rawOperation.replaceAll("a\\.value =(.+?) \\+ .+?;.*", "$1").replaceAll("\\s{3,}[a-z](?: = |\\.).+", "");
String js = operation.replace("\n", "");
Duktape duktape = Duktape.create();
int result = 0;
try {
String res = (String) duktape.evaluate(js + ".toString()");
result = Integer.parseInt(res);
} catch (Exception e) {
e.printStackTrace();
} finally {
duktape.close();
}
String answer = String.valueOf(result + domain.length());
String url = new HttpUrl.Builder().scheme("http").host(domain)
.addPathSegment("cdn-cgi").addPathSegment("l").addPathSegment("chk_jschl")
.addEncodedQueryParameter("jschl_vc", challenge)
.addEncodedQueryParameter("pass", challengePass)
.addEncodedQueryParameter("jschl_answer", answer)
.build().toString();
Request request1 = new Request.Builder()
.url(url)
.header("User-Agent", Navigator.USER_AGENT)
.header("Referer", request.url().toString())
.build();
response.body().close();
response = chain.proceed(request1);//generate the cookie
response.body().close();
response = chain.proceed(request.newBuilder().build());
return response;
}
}