/*
* Overchan Android (Meta Imageboard Client)
* Copyright (C) 2014-2016 miku-nyan <https://github.com/miku-nyan>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package nya.miku.wishmaster.http.cloudflare;
import nya.miku.wishmaster.api.HttpChanModule;
import nya.miku.wishmaster.api.interfaces.CancellableTask;
import nya.miku.wishmaster.common.MainApplication;
import nya.miku.wishmaster.http.interactive.InteractiveException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.app.Activity;
/**
* Исключение, вызванное запросом проверки Cloudflare
* @author miku-nyan
*
*/
public class CloudflareException extends InteractiveException {
private static final long serialVersionUID = 1L;
private static final String SERVICE_NAME = "Cloudflare";
private static final String COOKIE_NAME = "cf_clearance";
private static final String RECAPTCHA_KEY = "6LfOYgoTAAAAAInWDVTLSc8Yibqp-c9DaLimzNGM";
private static final Pattern PATTERN_STOKEN = Pattern.compile("stoken=\"?([^\"&]+)");
private static final Pattern PATTERN_ID = Pattern.compile("stoken=\"?([^\"&]+)");
private boolean recaptcha;
private String url;
private String sToken;
private boolean fallback;
private String checkCaptchaUrlFormat;
private String chanName;
//для создания экземплятов используются статические методы
private CloudflareException() {}
@Override
public String getServiceName() {
return SERVICE_NAME;
}
/**
* Создать новый экземпляр cloudflare-исключения (обычная js-antiddos проверка, без рекапчи).
* @param url адрес, по которому вызвана проверка
* @param cfCookieName название cloudflare-куки
* @param chanName название модуля чана (модуль должен имплементировать {@link HttpChanModule})
* @return созданный объект
*/
public static CloudflareException antiDDOS(String url, String chanName) {
CloudflareException e = new CloudflareException();
e.url = url;
e.chanName = chanName;
e.recaptcha = false;
return e;
}
@Deprecated
public static CloudflareException antiDDOS(String url, String cookie, String chanName) {
return antiDDOS(url, chanName);
}
public static CloudflareException withRecaptcha(String url, String chanName, String sToken, String checkUrlFormat, boolean fallback) {
CloudflareException e = new CloudflareException();
e.url = url;
e.recaptcha = true;
e.sToken = sToken;
e.checkCaptchaUrlFormat = checkUrlFormat;
e.chanName = chanName;
e.fallback = fallback;
return e;
}
@Deprecated
public static CloudflareException withRecaptcha(String key, String url, String cookie, String chanName) {
return withRecaptcha(url, chanName, "", true);
}
/**
* Создать новый экземпляр cloudflare-исключения (проверка с рекапчей).
* @param url адрес, по которому вызвана проверка
* @param chanName название модуля чана
* @param htmlString строка с html-страницей, загрузившейся с запросом проверки
* @param fallback использовать ли проверку в fallback-режиме (без js)
* @return созданный объект
*/
public static CloudflareException withRecaptcha(String url, String chanName, String htmlString, boolean fallback) {
String token = null;
Matcher m = PATTERN_STOKEN.matcher(htmlString);
if (m.find()) token = m.group(1);
String id = null;
m = PATTERN_ID.matcher(htmlString);
if (m.find()) id = m.group(1);
try {
URL baseUrl = new URL(url);
url = baseUrl.getProtocol() + "://" + baseUrl.getHost() + "/";
} catch (Exception e) {
if (!url.endsWith("/")) url = url + "/";
}
String checkUrl = url + "cdn-cgi/l/chk_captcha?" + (id != null ? ("id=" + id + "&") : "") + "g-recaptcha-response=%s";
return withRecaptcha(url, chanName, token, checkUrl, fallback);
}
/**
* определить тип проверки (рекапча или обычная anti-ddos)
* @return true, если проверка с рекапчей
*/
/*package*/ boolean isRecaptcha() {
return recaptcha;
}
/**
* получить url, по которому была вызвана проверка
* @return url
*/
/*package*/ String getCheckUrl() {
return url;
}
/**
* получить открытый ключ рекапчи
* @return открытый ключ
*/
/*package*/ String getRecaptchaPublicKey() {
return RECAPTCHA_KEY;
}
/**
* получить secure token (data-stoken, stoken) для рекапчи
*/
/*package*/ String getRecaptchaSecureToken() {
return sToken;
}
/**
* определяет, требуется ли использовать проверку recaptcha в fallback-режиме (без js)
* @return true, если в режиме fallback
*/
/*package*/ boolean isRecaptchaFallback() {
return fallback;
}
/**
* получить строку-формат URL для проверки рекапчи
* @return формат (первый %s - challenge, второй %s - ответ на капчу)
*/
/*package*/ String getCheckCaptchaUrlFormat() {
return checkCaptchaUrlFormat;
}
/**
* получить название cloudflare-куки, которую необходимо получить
* @return название cookie
*/
/*package*/ String getRequiredCookieName() {
return COOKIE_NAME;
}
@Override
public void handle(Activity activity, CancellableTask task, Callback callback) {
CloudflareUIHandler.handleCloudflare(this, (HttpChanModule) MainApplication.getInstance().getChanModule(chanName), activity, task, callback);
}
}