/* * Copyright (C) 2013 Sasha Vasko <sasha at aftercode dot net> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.wifiafterconnect.handlers; import java.net.URL; import java.util.HashMap; import com.wifiafterconnect.Constants; import com.wifiafterconnect.ParsedHttpInput; import com.wifiafterconnect.WifiAuthParams; import android.util.Log; import com.wifiafterconnect.html.HtmlForm; import com.wifiafterconnect.html.HtmlInput; import com.wifiafterconnect.html.HtmlPage; import com.wifiafterconnect.util.HttpInput; public abstract class CaptivePageHandler { public interface Detection { public Boolean detect(HttpInput input); } // Strictly speaking we don't really need a map here for now // May add methods for listing available handlers in future private static HashMap <String,Class<? extends Detection>> registeredHandlers = null; // Using Reflection and package listing is way too much trouble private static final String[] standardHandlers = new String[] { "CiscoHandler", "UniFiHandler", "WanderingWifiHandler", "SwitchURLHandler", // "AttHandler", Can be handled by GenericHandler "WiNGHandler", "NNUHandler", "HiltonHandler", "NSTreinHandler" }; @SuppressWarnings("unchecked") private static void registerStandardHandlers() { if (registeredHandlers != null) return; registeredHandlers = new HashMap<String,Class<? extends Detection>>(); for (String handlerName : standardHandlers) { Log.d(Constants.TAG, "registering standard handler " + handlerName); try { Log.d(Constants.TAG, "Class " + (Class<? extends Detection>)Class.forName(CaptivePageHandler.class.getPackage().getName() + '.' + handlerName)); registerHandler ((Class<? extends Detection>)Class.forName(CaptivePageHandler.class.getPackage().getName() + '.' + handlerName)); } catch (ClassNotFoundException e) {// don't care e.printStackTrace(); } } } /** * Register new Captive Portal handler at runtime. * * @param handler - class of the handler to be registered. * Must extend CaptivePageHandler and implement CaptivePageHandler.Detection */ public static void registerHandler (Class<? extends Detection> handler) { if (registeredHandlers == null) registerStandardHandlers(); registeredHandlers.put (handler.getName(), handler); } // THE FACTORY public static CaptivePageHandler autodetect (HttpInput input) { if (input == null) return null; if (registeredHandlers == null) registerStandardHandlers(); CaptivePageHandler handler = null; for (Class<? extends Detection> handlerClass : registeredHandlers.values()) { try { Log.d(Constants.TAG, "detecting " + handlerClass.getName()); handler = (CaptivePageHandler) handlerClass.newInstance(); //Method m = handlerClass.getMethod("detect", HtmlPage.class); //Boolean result = (Boolean)m.invoke(handler, page); Detection d = (Detection)handler; Boolean result = d.detect(input); Log.d(Constants.TAG, " result = " + result); if (result) break; handler = null; // } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); return null; } catch (IllegalAccessException e) { e.printStackTrace(); return null; } catch (IllegalArgumentException e) { e.printStackTrace(); // } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NullPointerException e) { // ignore e.printStackTrace(); } } if (handler == null) handler = new GenericHandler(); handler.setPage(input); return handler; } public enum States { Normal, HandleRedirects, HandleRedirectsAll, Failed, Success; } protected HttpInput page = null; protected States state = States.Normal; protected void setPage (HttpInput page) { this.page = page; } protected void setState (States state) { this.state = state; } public States getState () { return state; } public boolean checkParamsMissing (WifiAuthParams params){ WifiAuthParams allParams = addMissingParams(params); if (allParams != null) { for (HtmlInput i : allParams.getFields()) { if (i.getValue().isEmpty()) return true; } } return false; } public void validateLoginForm (WifiAuthParams params, HtmlForm form){ for (HtmlInput i : form.getInputs()) { if (!i.isHidden() && i.matchType(HtmlInput.TYPE_CHECKBOX) && i.getValue().isEmpty()) i.setValue("yes"); } } public String getPostData (WifiAuthParams params) { HtmlForm form = getLoginForm(); Log.d (Constants.TAG, "LoginForm = " + form); if (form != null) { form.fillInputs(params); validateLoginForm (params, form); return form.formatPostData(); } return null; } protected HtmlPage getHtmlPage() { return (page != null && page instanceof HtmlPage) ? (HtmlPage)page : null; } public HtmlForm getLoginForm () { Log.d (Constants.TAG, "Page = " + page); return HtmlPage.getForm(page); } /* * Possibly to be overriden in subclasses */ public URL getPostURL () { HtmlForm form = getLoginForm(); if (form != null) return form.formatActionURL (page.getURL()); return page.getURL(); }; public boolean checkUsernamePasswordMissing (WifiAuthParams params){ HtmlForm form = getLoginForm(); Log.d(Constants.TAG, "Checking for missing params. Form = " + form); return (form != null && form.isParamMissing(params, WifiAuthParams.USERNAME)||form.isParamMissing(params, WifiAuthParams.PASSWORD)); } public WifiAuthParams addMissingParams (WifiAuthParams params) { HtmlForm form = getLoginForm(); Log.d(Constants.TAG, "Adding missing params. Form = " + form); if (params == null) params = new WifiAuthParams(); if (form != null) params = form.fillParams (params); return params; } public ParsedHttpInput authenticate(ParsedHttpInput parsedPage, WifiAuthParams authParams) { // this works for most captive portals. The weird ones should override this method. ParsedHttpInput result = parsedPage.postForm (authParams); setState (result!=null ? States.Success : States.Failed); return result; } }