mirror of https://github.com/kurisufriend/Clover
parent
2af30b3be1
commit
9137f5f32f
@ -0,0 +1,68 @@ |
|||||||
|
/* |
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/ |
||||||
|
package org.floens.chan.core.site; |
||||||
|
|
||||||
|
public class Authentication { |
||||||
|
public enum Type { |
||||||
|
NONE, |
||||||
|
CAPTCHA1, |
||||||
|
CAPTCHA2, |
||||||
|
GENERIC_WEBVIEW |
||||||
|
} |
||||||
|
|
||||||
|
public static Authentication fromNone() { |
||||||
|
return new Authentication(Type.NONE); |
||||||
|
} |
||||||
|
|
||||||
|
public static Authentication fromCaptcha1(String siteKey, String baseUrl) { |
||||||
|
Authentication a = new Authentication(Type.CAPTCHA1); |
||||||
|
a.siteKey = siteKey; |
||||||
|
a.baseUrl = baseUrl; |
||||||
|
return a; |
||||||
|
} |
||||||
|
|
||||||
|
public static Authentication fromCaptcha2(String siteKey, String baseUrl) { |
||||||
|
Authentication a = new Authentication(Type.CAPTCHA2); |
||||||
|
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; |
||||||
|
a.retryText = retryText; |
||||||
|
a.successText = successText; |
||||||
|
return a; |
||||||
|
} |
||||||
|
|
||||||
|
public final Type type; |
||||||
|
|
||||||
|
// captcha1 & captcha2
|
||||||
|
public String siteKey; |
||||||
|
public String baseUrl; |
||||||
|
|
||||||
|
// generic webview
|
||||||
|
public String url; |
||||||
|
public String retryText; |
||||||
|
public String successText; |
||||||
|
|
||||||
|
private Authentication(Type type) { |
||||||
|
this.type = type; |
||||||
|
} |
||||||
|
} |
@ -1,10 +0,0 @@ |
|||||||
package org.floens.chan.core.site; |
|
||||||
|
|
||||||
|
|
||||||
public interface SiteAuthentication { |
|
||||||
enum AuthenticationRequestType { |
|
||||||
POSTING |
|
||||||
} |
|
||||||
|
|
||||||
boolean requireAuthentication(AuthenticationRequestType type); |
|
||||||
} |
|
@ -0,0 +1,158 @@ |
|||||||
|
/* |
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/ |
||||||
|
package org.floens.chan.ui.captcha; |
||||||
|
|
||||||
|
import android.annotation.SuppressLint; |
||||||
|
import android.content.Context; |
||||||
|
import android.os.Build; |
||||||
|
import android.os.Handler; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.webkit.JavascriptInterface; |
||||||
|
import android.webkit.WebSettings; |
||||||
|
import android.webkit.WebView; |
||||||
|
|
||||||
|
import org.floens.chan.core.site.Authentication; |
||||||
|
import org.floens.chan.core.site.Site; |
||||||
|
import org.floens.chan.utils.AndroidUtils; |
||||||
|
|
||||||
|
public class GenericWebViewAuthenticationLayout extends WebView implements AuthenticationLayoutInterface { |
||||||
|
public static final int CHECK_INTERVAL = 800; |
||||||
|
|
||||||
|
private final Handler handler = new Handler(); |
||||||
|
private boolean attachedToWindow = false; |
||||||
|
|
||||||
|
private Site site; |
||||||
|
private AuthenticationLayoutCallback callback; |
||||||
|
private Authentication authentication; |
||||||
|
private boolean resettingFromFoundText = false; |
||||||
|
|
||||||
|
public GenericWebViewAuthenticationLayout(Context context) { |
||||||
|
this(context, null); |
||||||
|
} |
||||||
|
|
||||||
|
public GenericWebViewAuthenticationLayout(Context context, AttributeSet attrs) { |
||||||
|
this(context, attrs, 0); |
||||||
|
} |
||||||
|
|
||||||
|
public GenericWebViewAuthenticationLayout(Context context, AttributeSet attrs, int defStyle) { |
||||||
|
super(context, attrs, defStyle); |
||||||
|
|
||||||
|
setFocusableInTouchMode(true); |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface"}) |
||||||
|
@Override |
||||||
|
public void initialize(Site site, AuthenticationLayoutCallback callback) { |
||||||
|
this.site = site; |
||||||
|
this.callback = callback; |
||||||
|
|
||||||
|
authentication = site.postAuthenticate(); |
||||||
|
|
||||||
|
// Older versions just have to manually go back or something.
|
||||||
|
if (Build.VERSION.SDK_INT >= 17) { |
||||||
|
WebSettings settings = getSettings(); |
||||||
|
settings.setJavaScriptEnabled(true); |
||||||
|
addJavascriptInterface(new WebInterface(this), "WebInterface"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void reset() { |
||||||
|
loadUrl(authentication.url); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void hardReset() { |
||||||
|
} |
||||||
|
|
||||||
|
private void checkText() { |
||||||
|
loadUrl("javascript:WebInterface.onAllText(document.documentElement.textContent)"); |
||||||
|
} |
||||||
|
|
||||||
|
private void onAllText(String text) { |
||||||
|
boolean retry = text.contains(authentication.retryText); |
||||||
|
boolean success = text.contains(authentication.successText); |
||||||
|
|
||||||
|
if (retry) { |
||||||
|
if (!resettingFromFoundText) { |
||||||
|
resettingFromFoundText = true; |
||||||
|
postDelayed(() -> { |
||||||
|
resettingFromFoundText = false; |
||||||
|
reset(); |
||||||
|
}, 1000); |
||||||
|
} |
||||||
|
} else if (success) { |
||||||
|
callback.onAuthenticationComplete(this, "", ""); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onAttachedToWindow() { |
||||||
|
super.onAttachedToWindow(); |
||||||
|
|
||||||
|
attachedToWindow = true; |
||||||
|
handler.postDelayed(checkTextRunnable, CHECK_INTERVAL); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onDetachedFromWindow() { |
||||||
|
super.onDetachedFromWindow(); |
||||||
|
|
||||||
|
attachedToWindow = false; |
||||||
|
handler.removeCallbacks(checkTextRunnable); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onWindowFocusChanged(boolean hasWindowFocus) { |
||||||
|
super.onWindowFocusChanged(hasWindowFocus); |
||||||
|
|
||||||
|
handler.removeCallbacks(checkTextRunnable); |
||||||
|
|
||||||
|
if (hasWindowFocus) { |
||||||
|
handler.postDelayed(checkTextRunnable, CHECK_INTERVAL); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private final Runnable checkTextRunnable = new Runnable() { |
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
checkText(); |
||||||
|
reschedule(); |
||||||
|
} |
||||||
|
|
||||||
|
private void reschedule() { |
||||||
|
handler.removeCallbacks(checkTextRunnable); |
||||||
|
if (attachedToWindow && hasWindowFocus()) { |
||||||
|
handler.postDelayed(checkTextRunnable, CHECK_INTERVAL); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public static class WebInterface { |
||||||
|
private final GenericWebViewAuthenticationLayout layout; |
||||||
|
|
||||||
|
public WebInterface(GenericWebViewAuthenticationLayout layout) { |
||||||
|
this.layout = layout; |
||||||
|
} |
||||||
|
|
||||||
|
@JavascriptInterface |
||||||
|
public void onAllText(String text) { |
||||||
|
AndroidUtils.runOnUiThread(() -> layout.onAllText(text)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue