From 9ffe4ec060ed2974fe56a8d2d6a3b6b0c94a9231 Mon Sep 17 00:00:00 2001 From: Floens Date: Sun, 21 Jan 2018 20:49:10 +0100 Subject: [PATCH] add captcha v2 nojs add a setting to the site for it. --- .../captcha/{captcha.html => captcha2.html} | 0 .../src/main/java/org/floens/chan/Chan.java | 3 +- .../floens/chan/core/model/orm/SiteModel.java | 8 +- .../core/presenter/SiteSetupPresenter.java | 10 + .../chan/core/settings/ChanSettings.java | 14 +- .../chan/core/settings/OptionSettingItem.java | 2 +- .../chan/core/settings/OptionsSetting.java | 21 +- .../floens/chan/core/site/Authentication.java | 8 + .../java/org/floens/chan/core/site/Site.java | 7 +- .../org/floens/chan/core/site/SiteBase.java | 13 ++ .../chan/core/site/sites/chan4/Chan4.java | 49 ++++- .../floens/chan/ui/captcha/CaptchaLayout.java | 7 +- .../chan/ui/captcha/CaptchaNojsLayout.java | 191 ++++++++++++++++++ .../controller/MediaSettingsController.java | 6 +- .../ui/controller/SiteSetupController.java | 30 +++ .../floens/chan/ui/layout/ReplyLayout.java | 4 + 16 files changed, 343 insertions(+), 30 deletions(-) rename Clover/app/src/main/assets/captcha/{captcha.html => captcha2.html} (100%) create mode 100644 Clover/app/src/main/java/org/floens/chan/ui/captcha/CaptchaNojsLayout.java diff --git a/Clover/app/src/main/assets/captcha/captcha.html b/Clover/app/src/main/assets/captcha/captcha2.html similarity index 100% rename from Clover/app/src/main/assets/captcha/captcha.html rename to Clover/app/src/main/assets/captcha/captcha2.html diff --git a/Clover/app/src/main/java/org/floens/chan/Chan.java b/Clover/app/src/main/java/org/floens/chan/Chan.java index 15d8d89f..f10d7718 100644 --- a/Clover/app/src/main/java/org/floens/chan/Chan.java +++ b/Clover/app/src/main/java/org/floens/chan/Chan.java @@ -25,6 +25,7 @@ import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.os.StrictMode; +import android.webkit.WebView; import org.codejargon.feather.Feather; import org.floens.chan.core.database.DatabaseManager; @@ -115,7 +116,7 @@ public class Chan extends Application implements UserAgentProvider, Application. //noinspection PointlessBooleanExpression if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { -// WebView.setWebContentsDebuggingEnabled(true); + WebView.setWebContentsDebuggingEnabled(true); } } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/orm/SiteModel.java b/Clover/app/src/main/java/org/floens/chan/core/model/orm/SiteModel.java index cf9a256b..79252bee 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/model/orm/SiteModel.java +++ b/Clover/app/src/main/java/org/floens/chan/core/model/orm/SiteModel.java @@ -24,14 +24,15 @@ import com.google.gson.GsonBuilder; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; +import org.floens.chan.core.model.json.site.SiteConfig; import org.floens.chan.core.settings.json.BooleanJsonSetting; -import org.floens.chan.core.settings.json.LongJsonSetting; -import org.floens.chan.core.settings.json.RuntimeTypeAdapterFactory; import org.floens.chan.core.settings.json.IntegerJsonSetting; -import org.floens.chan.core.model.json.site.SiteConfig; import org.floens.chan.core.settings.json.JsonSetting; import org.floens.chan.core.settings.json.JsonSettings; +import org.floens.chan.core.settings.json.LongJsonSetting; +import org.floens.chan.core.settings.json.RuntimeTypeAdapterFactory; import org.floens.chan.core.settings.json.StringJsonSetting; +import org.floens.chan.utils.Logger; @DatabaseTable(tableName = "site") public class SiteModel { @@ -68,6 +69,7 @@ public class SiteModel { public void storeUserSettings(JsonSettings userSettings) { this.userSettings = gson.toJson(userSettings); + Logger.test("userSettings = " + this.userSettings); } public Pair loadConfigFields() { diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/SiteSetupPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/SiteSetupPresenter.java index 3c028420..2a9ae74c 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/SiteSetupPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/SiteSetupPresenter.java @@ -1,8 +1,11 @@ package org.floens.chan.core.presenter; import org.floens.chan.core.database.DatabaseManager; +import org.floens.chan.core.settings.Setting; import org.floens.chan.core.site.Site; +import java.util.List; + import javax.inject.Inject; public class SiteSetupPresenter { @@ -25,6 +28,11 @@ public class SiteSetupPresenter { if (hasLogin) { callback.showLogin(); } + + List> settings = site.settings(); + if (!settings.isEmpty()) { + callback.showSettings(settings); + } } public void show() { @@ -48,5 +56,7 @@ public class SiteSetupPresenter { void showLogin(); void setIsLoggedIn(boolean isLoggedIn); + + void showSettings(List> settings); } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java b/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java index 44ec5928..ca13c3bc 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java +++ b/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java @@ -49,7 +49,7 @@ public class ChanSettings { } @Override - public String getName() { + public String getKey() { return name; } } @@ -65,7 +65,7 @@ public class ChanSettings { } @Override - public String getName() { + public String getKey() { return name; } } @@ -83,7 +83,7 @@ public class ChanSettings { } @Override - public String getName() { + public String getKey() { return name; } } @@ -162,7 +162,7 @@ public class ChanSettings { theme = new StringSetting(p, "preference_theme", "yotsuba"); - layoutMode = new OptionsSetting<>(p, "preference_layout_mode", LayoutMode.values(), LayoutMode.AUTO); + layoutMode = new OptionsSetting<>(p, "preference_layout_mode", LayoutMode.class, LayoutMode.AUTO); boolean tablet = AndroidUtils.getRes().getBoolean(R.bool.is_tablet); @@ -171,12 +171,12 @@ public class ChanSettings { openLinkConfirmation = new BooleanSetting(p, "preference_open_link_confirmation", false); autoRefreshThread = new BooleanSetting(p, "preference_auto_refresh_thread", true); // imageAutoLoad = new BooleanSetting(p, "preference_image_auto_load", true); - imageAutoLoadNetwork = new OptionsSetting<>(p, "preference_image_auto_load_network", MediaAutoLoadMode.values(), MediaAutoLoadMode.WIFI); - videoAutoLoadNetwork = new OptionsSetting<>(p, "preference_video_auto_load_network", MediaAutoLoadMode.values(), MediaAutoLoadMode.WIFI); + imageAutoLoadNetwork = new OptionsSetting<>(p, "preference_image_auto_load_network", MediaAutoLoadMode.class, MediaAutoLoadMode.WIFI); + videoAutoLoadNetwork = new OptionsSetting<>(p, "preference_video_auto_load_network", MediaAutoLoadMode.class, MediaAutoLoadMode.WIFI); videoOpenExternal = new BooleanSetting(p, "preference_video_external", false); textOnly = new BooleanSetting(p, "preference_text_only", false); videoErrorIgnore = new BooleanSetting(p, "preference_video_error_ignore", false); - boardViewMode = new OptionsSetting<>(p, "preference_board_view_mode", PostViewMode.values(), PostViewMode.LIST); + boardViewMode = new OptionsSetting<>(p, "preference_board_view_mode", PostViewMode.class, PostViewMode.LIST); boardGridSpanCount = new IntegerSetting(p, "preference_board_grid_span_count", 0); boardOrder = new StringSetting(p, "preference_board_order", PostsFilter.Order.BUMP.name); diff --git a/Clover/app/src/main/java/org/floens/chan/core/settings/OptionSettingItem.java b/Clover/app/src/main/java/org/floens/chan/core/settings/OptionSettingItem.java index 7df7dea0..1dd5667e 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/settings/OptionSettingItem.java +++ b/Clover/app/src/main/java/org/floens/chan/core/settings/OptionSettingItem.java @@ -18,5 +18,5 @@ package org.floens.chan.core.settings; public interface OptionSettingItem { - String getName(); + String getKey(); } diff --git a/Clover/app/src/main/java/org/floens/chan/core/settings/OptionsSetting.java b/Clover/app/src/main/java/org/floens/chan/core/settings/OptionsSetting.java index 8814d381..7a2e7113 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/settings/OptionsSetting.java +++ b/Clover/app/src/main/java/org/floens/chan/core/settings/OptionsSetting.java @@ -17,14 +17,23 @@ */ package org.floens.chan.core.settings; -public class OptionsSetting extends Setting { +public class OptionsSetting extends Setting { private boolean hasCached = false; + + private Class clazz; + private T cached; private T[] items; - public OptionsSetting(SettingProvider settingProvider, String key, T[] items, T def) { + public OptionsSetting(SettingProvider settingProvider, String key, Class clazz, T def) { super(settingProvider, key, def); - this.items = items; + + this.clazz = clazz; + this.items = clazz.getEnumConstants(); + } + + public T[] getItems() { + return items; } @Override @@ -32,10 +41,10 @@ public class OptionsSetting extends Setting { if (hasCached) { return cached; } else { - String itemName = settingProvider.getString(key, def.getName()); + String itemName = settingProvider.getString(key, def.getKey()); T selectedItem = null; for (T item : items) { - if (item.getName().equals(itemName)) { + if (item.getKey().equals(itemName)) { selectedItem = item; } } @@ -52,7 +61,7 @@ public class OptionsSetting extends Setting { @Override public void set(T value) { if (!value.equals(get())) { - settingProvider.putString(key, value.getName()); + settingProvider.putString(key, value.getKey()); cached = value; onValueChanged(); } diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/Authentication.java b/Clover/app/src/main/java/org/floens/chan/core/site/Authentication.java index c03a20b0..70efb0c5 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/Authentication.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/Authentication.java @@ -22,6 +22,7 @@ public class Authentication { NONE, CAPTCHA1, CAPTCHA2, + CAPTCHA2_NOJS, GENERIC_WEBVIEW } @@ -43,6 +44,13 @@ public class Authentication { return a; } + public static Authentication fromCaptcha2nojs(String siteKey, String baseUrl) { + Authentication a = new Authentication(Type.CAPTCHA2_NOJS); + a.siteKey = siteKey; + a.baseUrl = baseUrl; + return a; + } + public static Authentication fromUrl(String url, String retryText, String successText) { Authentication a = new Authentication(Type.GENERIC_WEBVIEW); a.url = url; diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/Site.java b/Clover/app/src/main/java/org/floens/chan/core/site/Site.java index 1f44203e..39672dac 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/Site.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/Site.java @@ -21,9 +21,10 @@ import android.support.annotation.Nullable; import org.floens.chan.core.model.Post; import org.floens.chan.core.model.json.site.SiteConfig; -import org.floens.chan.core.settings.json.JsonSettings; import org.floens.chan.core.model.orm.Board; import org.floens.chan.core.model.orm.Loadable; +import org.floens.chan.core.settings.Setting; +import org.floens.chan.core.settings.json.JsonSettings; import org.floens.chan.core.site.common.ChanReader; import org.floens.chan.core.site.http.DeleteRequest; import org.floens.chan.core.site.http.DeleteResponse; @@ -33,6 +34,8 @@ import org.floens.chan.core.site.http.LoginResponse; import org.floens.chan.core.site.http.Reply; import org.floens.chan.core.site.http.ReplyResponse; +import java.util.List; + import okhttp3.HttpUrl; public interface Site { @@ -139,6 +142,8 @@ public interface Site { boolean boardFeature(BoardFeature boardFeature, Board board); + List> settings(); + SiteEndpoints endpoints(); SiteRequestModifier requestModifier(); diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/SiteBase.java b/Clover/app/src/main/java/org/floens/chan/core/site/SiteBase.java index 8ac63a74..e35e8069 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/SiteBase.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/SiteBase.java @@ -25,12 +25,15 @@ import org.floens.chan.core.database.LoadableProvider; import org.floens.chan.core.manager.BoardManager; import org.floens.chan.core.model.json.site.SiteConfig; import org.floens.chan.core.model.orm.Board; +import org.floens.chan.core.settings.Setting; import org.floens.chan.core.settings.SettingProvider; import org.floens.chan.core.settings.json.JsonSettings; import org.floens.chan.core.settings.json.JsonSettingsProvider; import org.floens.chan.core.site.http.HttpCallManager; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import static org.floens.chan.Chan.injector; @@ -66,6 +69,8 @@ public abstract class SiteBase implements Site { siteManager.updateUserSettings(this, userSettings); }); + initializeSettings(); + if (boardsType() == BoardsType.DYNAMIC) { boards(boards -> boardManager.createAll(boards.boards)); } @@ -81,6 +86,14 @@ public abstract class SiteBase implements Site { return boardManager.getBoard(this, code); } + @Override + public List> settings() { + return new ArrayList<>(); + } + + public void initializeSettings() { + } + @Override public Board createBoard(String name, String code) { Board existing = board(code); diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java index 5e6318cf..1a633051 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java @@ -24,7 +24,9 @@ import android.webkit.WebView; import org.floens.chan.core.model.Post; import org.floens.chan.core.model.orm.Board; import org.floens.chan.core.model.orm.Loadable; -import org.floens.chan.core.settings.ChanSettings; +import org.floens.chan.core.settings.OptionSettingItem; +import org.floens.chan.core.settings.OptionsSetting; +import org.floens.chan.core.settings.Setting; import org.floens.chan.core.settings.SettingProvider; import org.floens.chan.core.settings.SharedPreferencesSettingProvider; import org.floens.chan.core.settings.StringSetting; @@ -48,6 +50,7 @@ import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.Logger; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -253,6 +256,24 @@ public class Chan4 extends SiteBase { private final StringSetting passPass; private final StringSetting passToken; + public enum CaptchaType implements OptionSettingItem { + V2JS("v2js"), + V2NOJS("v2nojs"); + + String name; + + CaptchaType(String name) { + this.name = name; + } + + @Override + public String getKey() { + return name; + } + } + + private OptionsSetting captchaType; + public Chan4() { // we used these before multisite, and lets keep using them. SettingProvider p = new SharedPreferencesSettingProvider(AndroidUtils.getPreferences()); @@ -263,6 +284,21 @@ public class Chan4 extends SiteBase { passToken = new StringSetting(p, "preference_pass_id", ""); } + @Override + public void initializeSettings() { + super.initializeSettings(); + + captchaType = new OptionsSetting<>(settingsProvider, "preference_captcha_type", + CaptchaType.class, CaptchaType.V2NOJS); + } + + @Override + public List> settings() { + return Arrays.asList( + captchaType + ); + } + @Override public String name() { return "4chan"; @@ -442,10 +478,13 @@ public class Chan4 extends SiteBase { if (isLoggedIn()) { return Authentication.fromNone(); } else { - if (ChanSettings.postNewCaptcha.get()) { - return Authentication.fromCaptcha2(CAPTCHA_KEY, "https://boards.4chan.org"); - } else { - return Authentication.fromCaptcha1(CAPTCHA_KEY, "https://boards.4chan.org"); + switch (captchaType.get()) { + case V2JS: + return Authentication.fromCaptcha2(CAPTCHA_KEY, "https://boards.4chan.org"); + case V2NOJS: + return Authentication.fromCaptcha2nojs(CAPTCHA_KEY, "https://boards.4chan.org"); + default: + throw new IllegalArgumentException(); } } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/captcha/CaptchaLayout.java b/Clover/app/src/main/java/org/floens/chan/ui/captcha/CaptchaLayout.java index 2ae092b8..7ffd7079 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/captcha/CaptchaLayout.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/captcha/CaptchaLayout.java @@ -23,7 +23,6 @@ import android.net.Uri; import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.AttributeSet; -import android.util.Log; import android.webkit.ConsoleMessage; import android.webkit.JavascriptInterface; import android.webkit.WebChromeClient; @@ -35,6 +34,7 @@ import org.floens.chan.core.site.Authentication; import org.floens.chan.core.site.Site; import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.IOUtils; +import org.floens.chan.utils.Logger; import static org.floens.chan.ui.theme.ThemeHelper.theme; @@ -80,7 +80,8 @@ public class CaptchaLayout extends WebView implements AuthenticationLayoutInterf setWebChromeClient(new WebChromeClient() { @Override public boolean onConsoleMessage(@NonNull ConsoleMessage consoleMessage) { - Log.i(TAG, consoleMessage.lineNumber() + ":" + consoleMessage.message() + " " + consoleMessage.sourceId()); + Logger.i(TAG, consoleMessage.lineNumber() + ":" + consoleMessage.message() + + " " + consoleMessage.sourceId()); return true; } }); @@ -113,7 +114,7 @@ public class CaptchaLayout extends WebView implements AuthenticationLayoutInterf public void hardReset() { loaded = true; - String html = IOUtils.assetAsString(getContext(), "captcha/captcha.html"); + String html = IOUtils.assetAsString(getContext(), "captcha/captcha2.html"); html = html.replace("__site_key__", siteKey); html = html.replace("__theme__", lightTheme ? "light" : "dark"); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/captcha/CaptchaNojsLayout.java b/Clover/app/src/main/java/org/floens/chan/ui/captcha/CaptchaNojsLayout.java new file mode 100644 index 00000000..4b8555ff --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/ui/captcha/CaptchaNojsLayout.java @@ -0,0 +1,191 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * 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 . + */ +package org.floens.chan.ui.captcha; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.webkit.ConsoleMessage; +import android.webkit.JavascriptInterface; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import org.floens.chan.core.site.Authentication; +import org.floens.chan.core.site.Site; +import org.floens.chan.utils.AndroidUtils; +import org.floens.chan.utils.Logger; + +import java.io.IOException; + +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; + +/** + * It directly loads the captcha2 fallback url into a webview, and on each requests it executes + * some javascript that will tell the callback if the token is there. + */ +public class CaptchaNojsLayout extends WebView implements AuthenticationLayoutInterface { + private static final String TAG = "CaptchaNojsLayout"; + + private AuthenticationLayoutCallback callback; + private String baseUrl; + private String siteKey; + + private OkHttpClient okHttpClient = new OkHttpClient(); + + private String webviewUserAgent; + + public CaptchaNojsLayout(Context context) { + super(context); + } + + public CaptchaNojsLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CaptchaNojsLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface"}) + @Override + public void initialize(Site site, AuthenticationLayoutCallback callback) { + this.callback = callback; + + Authentication authentication = site.postAuthenticate(); + + this.siteKey = authentication.siteKey; + this.baseUrl = authentication.baseUrl; + + requestDisallowInterceptTouchEvent(true); + + WebSettings settings = getSettings(); + settings.setJavaScriptEnabled(true); + webviewUserAgent = settings.getUserAgentString(); + + setWebChromeClient(new WebChromeClient() { + @Override + public boolean onConsoleMessage(@NonNull ConsoleMessage consoleMessage) { + Logger.i(TAG, consoleMessage.lineNumber() + ":" + consoleMessage.message() + + " " + consoleMessage.sourceId()); + return true; + } + }); + + setWebViewClient(new WebViewClient() { + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + + // Fails if there is no token yet, which is ok. + final String setResponseJavascript = "CaptchaCallback.onCaptchaEntered(" + + "document.querySelector('.fbc-verification-token textarea').value);"; + view.loadUrl("javascript:" + setResponseJavascript); + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + String host = Uri.parse(url).getHost(); + if (host == null) { + return false; + } + + if (host.equals(Uri.parse(CaptchaNojsLayout.this.baseUrl).getHost())) { + return false; + } else { + AndroidUtils.openLink(url); + return true; + } + } + }); + setBackgroundColor(0x00000000); + + addJavascriptInterface(new CaptchaInterface(this), "CaptchaCallback"); + } + + public void reset() { + hardReset(); + } + + @Override + public void hardReset() { + loadRecaptchaAndSetWebViewData(); + } + + private void loadRecaptchaAndSetWebViewData() { + final String recaptchaUrl = "https://www.google.com/recaptcha/api/fallback?k=" + siteKey; + + Request request = new Request.Builder() + .url(recaptchaUrl) + .header("User-Agent", webviewUserAgent) + .header("Referer", baseUrl) + .build(); + okHttpClient.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + ResponseBody body = response.body(); + if (body == null) throw new IOException(); + String responseHtml = body.string(); + + post(() -> { + loadDataWithBaseURL(recaptchaUrl, + responseHtml, "text/html", "UTF-8", null); + }); + } + }); + } + + private void onCaptchaEntered(String response) { + if (TextUtils.isEmpty(response)) { + reset(); + } else { + callback.onAuthenticationComplete(this, null, response); + } + } + + public static class CaptchaInterface { + private final CaptchaNojsLayout layout; + + public CaptchaInterface(CaptchaNojsLayout layout) { + this.layout = layout; + } + + @JavascriptInterface + public void onCaptchaEntered(final String response) { + AndroidUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + layout.onCaptchaEntered(response); + } + }); + } + } +} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/MediaSettingsController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/MediaSettingsController.java index 285ed2e4..66b10d55 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/MediaSettingsController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/MediaSettingsController.java @@ -165,7 +165,7 @@ public class MediaSettingsController extends SettingsController { boolean enabled = false; boolean resetVideoMode = false; for (int i = 0; i < modes.length; i++) { - if (modes[i].getName().equals(currentImageLoadMode.getName())) { + if (modes[i].getKey().equals(currentImageLoadMode.getKey())) { enabled = true; if (resetVideoMode) { ChanSettings.videoAutoLoadNetwork.set(modes[i]); @@ -174,8 +174,8 @@ public class MediaSettingsController extends SettingsController { } } videoAutoLoadView.items.get(i).enabled = enabled; - if (!enabled && ChanSettings.videoAutoLoadNetwork.get().getName() - .equals(modes[i].getName())) { + if (!enabled && ChanSettings.videoAutoLoadNetwork.get().getKey() + .equals(modes[i].getKey())) { resetVideoMode = true; } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/SiteSetupController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/SiteSetupController.java index e884196d..a7a88e37 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/SiteSetupController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/SiteSetupController.java @@ -21,11 +21,17 @@ import android.content.Context; import org.floens.chan.R; import org.floens.chan.core.presenter.SiteSetupPresenter; +import org.floens.chan.core.settings.OptionsSetting; +import org.floens.chan.core.settings.Setting; import org.floens.chan.core.site.Site; import org.floens.chan.ui.settings.LinkSettingView; +import org.floens.chan.ui.settings.ListSettingView; import org.floens.chan.ui.settings.SettingsController; import org.floens.chan.ui.settings.SettingsGroup; +import java.util.ArrayList; +import java.util.List; + import javax.inject.Inject; import static org.floens.chan.Chan.inject; @@ -91,6 +97,30 @@ public class SiteSetupController extends SettingsController implements SiteSetup loginLink.setDescription(text); } + @Override + public void showSettings(List> settings) { + SettingsGroup group = new SettingsGroup("Additional settings"); + + for (Setting setting : settings) { + if (setting instanceof OptionsSetting) { + OptionsSetting optionsSetting = (OptionsSetting) setting; + + List> items = new ArrayList<>(); + for (Enum anEnum : optionsSetting.getItems()) { + items.add(new ListSettingView.Item<>(anEnum.name(), anEnum)); + } + + String name = optionsSetting.getItems()[0].getDeclaringClass().getSimpleName(); + ListSettingView v = new ListSettingView(this, + optionsSetting, name, items); + + group.add(v); + } + } + + groups.add(group); + } + @Override public void showLogin() { SettingsGroup login = new SettingsGroup(R.string.setup_site_group_login); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/layout/ReplyLayout.java b/Clover/app/src/main/java/org/floens/chan/ui/layout/ReplyLayout.java index 0ad96269..76acb698 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/layout/ReplyLayout.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/layout/ReplyLayout.java @@ -49,6 +49,7 @@ import org.floens.chan.ui.activity.StartActivity; import org.floens.chan.ui.captcha.AuthenticationLayoutCallback; import org.floens.chan.ui.captcha.AuthenticationLayoutInterface; import org.floens.chan.ui.captcha.CaptchaLayout; +import org.floens.chan.ui.captcha.CaptchaNojsLayout; import org.floens.chan.ui.captcha.GenericWebViewAuthenticationLayout; import org.floens.chan.ui.captcha.LegacyCaptchaLayout; import org.floens.chan.ui.drawable.DropdownArrowDrawable; @@ -267,6 +268,9 @@ public class ReplyLayout extends LoadView implements View.OnClickListener, Reply authenticationLayout = new CaptchaLayout(getContext()); break; } + case CAPTCHA2_NOJS: + authenticationLayout = new CaptchaNojsLayout(getContext()); + break; case GENERIC_WEBVIEW: { GenericWebViewAuthenticationLayout view = new GenericWebViewAuthenticationLayout(getContext());