Add experimental legacy captcha support

filtering
Floens 10 years ago
parent 5a8a646709
commit 23708e6728
  1. 2
      Clover/app/src/main/assets/captcha/captcha.html
  2. 45
      Clover/app/src/main/assets/captcha/captcha1.html
  3. 5
      Clover/app/src/main/java/org/floens/chan/core/http/ReplyHttpCall.java
  4. 8
      Clover/app/src/main/java/org/floens/chan/core/model/Reply.java
  5. 3
      Clover/app/src/main/java/org/floens/chan/core/presenter/ReplyPresenter.java
  6. 2
      Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java
  7. 1
      Clover/app/src/main/java/org/floens/chan/ui/controller/AdvancedSettingsController.java
  8. 49
      Clover/app/src/main/java/org/floens/chan/ui/layout/CaptchaLayout.java
  9. 5
      Clover/app/src/main/java/org/floens/chan/ui/layout/ReplyLayout.java
  10. 2
      Clover/app/src/main/res/values-sw600dp/dimens.xml
  11. 2
      Clover/app/src/main/res/values/dimens.xml
  12. 2
      Clover/app/src/main/res/values/strings.xml

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta name=viewport content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css"> <style type="text/css">
#captcha-container div { #captcha-container div {
margin: 0 auto; margin: 0 auto;

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
#container {
width: 440px;
margin: 0 auto;
}
#captcha-submit {
width: 100%;
height: 30px;
margin: 10px 0 0 0;
}
</style>
</head>
<body>
<div id="container">
<div id="captcha-container"></div>
<input type="button" id="captcha-submit" value="Submit">
</div>
<script src="https://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
<script type="text/javascript">
(function() {
var container = document.querySelector('#captcha-container');
var submitButton = document.querySelector('#captcha-submit')
submitButton.addEventListener('click', function() {
var challenge = document.querySelector('#recaptcha_challenge_field').value;
var response = document.querySelector('#recaptcha_response_field').value;
CaptchaCallback.onCaptchaEnteredv1(challenge, response);
});
Recaptcha.create('__site_key__', container, {
theme: 'clean'
});
})();
</script>
</body>
</html>

@ -79,8 +79,13 @@ public class ReplyHttpCall extends HttpCall {
formBuilder.addFormDataPart("com", reply.comment); formBuilder.addFormDataPart("com", reply.comment);
if (reply.captchaResponse != null) { if (reply.captchaResponse != null) {
if (reply.captchaChallenge != null) {
formBuilder.addFormDataPart("recaptcha_challenge_field", reply.captchaChallenge);
formBuilder.addFormDataPart("recaptcha_response_field", reply.captchaResponse);
} else {
formBuilder.addFormDataPart("g-recaptcha-response", reply.captchaResponse); formBuilder.addFormDataPart("g-recaptcha-response", reply.captchaResponse);
} }
}
if (reply.file != null) { if (reply.file != null) {
formBuilder.addFormDataPart("upfile", reply.fileName, RequestBody.create( formBuilder.addFormDataPart("upfile", reply.fileName, RequestBody.create(

@ -23,6 +23,14 @@ import java.io.File;
* The data needed to send a reply. * The data needed to send a reply.
*/ */
public class Reply { public class Reply {
/**
* Optional. Null when ReCaptcha v2 was used or a 4pass
*/
public String captchaChallenge;
/**
* Optional. Null when a 4pass was used.
*/
public String captchaResponse; public String captchaResponse;
public boolean usePass = false; public boolean usePass = false;
public String board; public String board;

@ -233,7 +233,8 @@ public class ReplyPresenter implements ReplyManager.FileListener, ReplyManager.H
} }
@Override @Override
public void captchaEntered(CaptchaLayout captchaLayout, String response) { public void captchaEntered(CaptchaLayout captchaLayout, String challenge, String response) {
draft.captchaChallenge = challenge;
draft.captchaResponse = response; draft.captchaResponse = response;
captchaLayout.reset(); captchaLayout.reset();
makeSubmitCall(); makeSubmitCall();

@ -43,6 +43,7 @@ public class ChanSettings {
public static final StringSetting postDefaultName; public static final StringSetting postDefaultName;
public static final BooleanSetting postPinThread; public static final BooleanSetting postPinThread;
public static final BooleanSetting postNewCaptcha;
public static final BooleanSetting developer; public static final BooleanSetting developer;
@ -87,6 +88,7 @@ public class ChanSettings {
postDefaultName = new StringSetting(p, "preference_default_name", ""); postDefaultName = new StringSetting(p, "preference_default_name", "");
postPinThread = new BooleanSetting(p, "preference_pin_on_post", false); postPinThread = new BooleanSetting(p, "preference_pin_on_post", false);
postNewCaptcha = new BooleanSetting(p, "preference_new_captcha", true);
developer = new BooleanSetting(p, "preference_developer", false); developer = new BooleanSetting(p, "preference_developer", false);

@ -80,6 +80,7 @@ public class AdvancedSettingsController extends SettingsController {
})); }));
setSaveLocationDescription(); setSaveLocationDescription();
settings.add(new BooleanSettingView(this, ChanSettings.postNewCaptcha, string(R.string.setting_use_new_captcha), string(R.string.setting_use_new_captcha_description)));
settings.add(new BooleanSettingView(this, ChanSettings.saveOriginalFilename, string(R.string.setting_save_original_filename), null)); settings.add(new BooleanSettingView(this, ChanSettings.saveOriginalFilename, string(R.string.setting_save_original_filename), null));
settings.add(new BooleanSettingView(this, ChanSettings.shareUrl, string(R.string.setting_share_url), string(R.string.setting_share_url_description))); settings.add(new BooleanSettingView(this, ChanSettings.shareUrl, string(R.string.setting_share_url), string(R.string.setting_share_url_description)));
settings.add(new BooleanSettingView(this, ChanSettings.networkHttps, string(R.string.setting_network_https), string(R.string.setting_network_https_description))); settings.add(new BooleanSettingView(this, ChanSettings.networkHttps, string(R.string.setting_network_https), string(R.string.setting_network_https_description)));

@ -19,6 +19,8 @@ package org.floens.chan.ui.layout;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
@ -28,7 +30,9 @@ import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient; import android.webkit.WebChromeClient;
import android.webkit.WebSettings; import android.webkit.WebSettings;
import android.webkit.WebView; import android.webkit.WebView;
import android.webkit.WebViewClient;
import org.floens.chan.ChanBuild;
import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.AndroidUtils;
import org.floens.chan.utils.IOUtils; import org.floens.chan.utils.IOUtils;
@ -40,6 +44,7 @@ public class CaptchaLayout extends WebView {
private String baseUrl; private String baseUrl;
private String siteKey; private String siteKey;
private boolean lightTheme; private boolean lightTheme;
private boolean useNew;
public CaptchaLayout(Context context) { public CaptchaLayout(Context context) {
super(context); super(context);
@ -54,11 +59,12 @@ public class CaptchaLayout extends WebView {
} }
@SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface"}) @SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface"})
public void initCaptcha(String baseUrl, String siteKey, boolean lightTheme, CaptchaCallback callback) { public void initCaptcha(String baseUrl, String siteKey, boolean lightTheme, boolean useNew, CaptchaCallback callback) {
this.callback = callback; this.callback = callback;
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
this.siteKey = siteKey; this.siteKey = siteKey;
this.lightTheme = lightTheme; this.lightTheme = lightTheme;
this.useNew = useNew;
WebSettings settings = getSettings(); WebSettings settings = getSettings();
settings.setJavaScriptEnabled(true); settings.setJavaScriptEnabled(true);
@ -70,16 +76,33 @@ public class CaptchaLayout extends WebView {
return true; return true;
} }
}); });
setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Uri.parse(url).getHost().equals(Uri.parse(CaptchaLayout.this.baseUrl).getHost())) {
return false;
} else {
AndroidUtils.openLink(url);
return true;
}
}
});
setBackgroundColor(0x00000000); setBackgroundColor(0x00000000);
addJavascriptInterface(new CaptchaInterface(this), "CaptchaCallback"); addJavascriptInterface(new CaptchaInterface(this), "CaptchaCallback");
//noinspection PointlessBooleanExpression
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && ChanBuild.DEVELOPER_MODE) {
setWebContentsDebuggingEnabled(true);
}
} }
public void load() { public void load() {
if (!loaded) { if (!loaded) {
loaded = true; loaded = true;
String html = IOUtils.assetAsString(getContext(), "captcha/captcha.html"); String html = IOUtils.assetAsString(getContext(), useNew ? "captcha/captcha.html" : "captcha/captcha1.html");
html = html.replace("__site_key__", siteKey); html = html.replace("__site_key__", siteKey);
html = html.replace("__theme__", lightTheme ? "light" : "dark"); html = html.replace("__theme__", lightTheme ? "light" : "dark");
@ -89,7 +112,11 @@ public class CaptchaLayout extends WebView {
public void reset() { public void reset() {
if (loaded) { if (loaded) {
if (useNew) {
loadUrl("javascript:grecaptcha.reset()"); loadUrl("javascript:grecaptcha.reset()");
} else {
loadUrl("javascript:Recaptcha.reload()");
}
} else { } else {
load(); load();
} }
@ -99,18 +126,18 @@ public class CaptchaLayout extends WebView {
callback.captchaLoaded(this); callback.captchaLoaded(this);
} }
private void onCaptchaEntered(String response) { private void onCaptchaEntered(String challenge, String response) {
if (TextUtils.isEmpty(response)) { if (TextUtils.isEmpty(response)) {
reset(); reset();
} else { } else {
callback.captchaEntered(this, response); callback.captchaEntered(this, challenge, response);
} }
} }
public interface CaptchaCallback { public interface CaptchaCallback {
void captchaLoaded(CaptchaLayout captchaLayout); void captchaLoaded(CaptchaLayout captchaLayout);
void captchaEntered(CaptchaLayout captchaLayout, String response); void captchaEntered(CaptchaLayout captchaLayout, String challenge, String response);
} }
public static class CaptchaInterface { public static class CaptchaInterface {
@ -135,7 +162,17 @@ public class CaptchaLayout extends WebView {
AndroidUtils.runOnUiThread(new Runnable() { AndroidUtils.runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
layout.onCaptchaEntered(response); layout.onCaptchaEntered(null, response);
}
});
}
@JavascriptInterface
public void onCaptchaEnteredv1(final String challenge, final String response) {
AndroidUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
layout.onCaptchaEntered(challenge, response);
} }
}); });
} }

@ -37,6 +37,7 @@ import org.floens.chan.R;
import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Loadable;
import org.floens.chan.core.model.Reply; import org.floens.chan.core.model.Reply;
import org.floens.chan.core.presenter.ReplyPresenter; import org.floens.chan.core.presenter.ReplyPresenter;
import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.ui.drawable.DropdownArrowDrawable; import org.floens.chan.ui.drawable.DropdownArrowDrawable;
import org.floens.chan.ui.view.LoadView; import org.floens.chan.ui.view.LoadView;
import org.floens.chan.ui.view.SelectionListeningEditText; import org.floens.chan.ui.view.SelectionListeningEditText;
@ -165,7 +166,7 @@ public class ReplyLayout extends LoadView implements View.OnClickListener, Anima
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
} else { } else {
// Captcha and the loadbar // Captcha and the loadbar
return new LayoutParams(LayoutParams.MATCH_PARENT, dp(250)); return new LayoutParams(LayoutParams.MATCH_PARENT, getResources().getDimensionPixelSize(R.dimen.reply_height_loading));
} }
} }
@ -217,7 +218,7 @@ public class ReplyLayout extends LoadView implements View.OnClickListener, Anima
@Override @Override
public void initCaptcha(String baseUrl, String siteKey, CaptchaLayout.CaptchaCallback callback) { public void initCaptcha(String baseUrl, String siteKey, CaptchaLayout.CaptchaCallback callback) {
captchaLayout.initCaptcha(baseUrl, siteKey, ThemeHelper.getInstance().getTheme().isLightTheme, callback); captchaLayout.initCaptcha(baseUrl, siteKey, ThemeHelper.getInstance().getTheme().isLightTheme, ChanSettings.postNewCaptcha.get(), callback);
captchaLayout.load(); captchaLayout.load();
} }

@ -20,4 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<dimen name="grid_card_width">180dp</dimen> <dimen name="grid_card_width">180dp</dimen>
<integer name="grid_card_max_spans">5</integer> <integer name="grid_card_max_spans">5</integer>
<dimen name="reply_height_loading">400dp</dimen>
</resources> </resources>

@ -22,4 +22,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<dimen name="grid_card_width">140dp</dimen> <dimen name="grid_card_width">140dp</dimen>
<integer name="grid_card_max_spans">-1</integer> <integer name="grid_card_max_spans">-1</integer>
<dimen name="reply_height_loading">250dp</dimen>
</resources> </resources>

@ -213,6 +213,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<string name="setting_save_folder">File save folder</string> <string name="setting_save_folder">File save folder</string>
<string name="setting_save_folder_error_create_folder">Error creating save folder</string> <string name="setting_save_folder_error_create_folder">Error creating save folder</string>
<string name="setting_folder_pick_ok">Choose</string> <string name="setting_folder_pick_ok">Choose</string>
<string name="setting_use_new_captcha">Use the new captcha</string>
<string name="setting_use_new_captcha_description">Disable to fallback to the old captcha (EXPERIMENTAL).</string>
<string name="setting_save_original_filename">Save original filename</string> <string name="setting_save_original_filename">Save original filename</string>
<string name="setting_share_url">Share url to image</string> <string name="setting_share_url">Share url to image</string>
<string name="setting_share_url_description">Share the url to the image instead of the image itself</string> <string name="setting_share_url_description">Share the url to the image instead of the image itself</string>

Loading…
Cancel
Save