package fr.ydelouis.selfoss.config.model; import android.content.Context; import android.support.annotation.NonNull; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.RootContext; import org.androidannotations.annotations.rest.RestService; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import java.io.IOException; import fr.ydelouis.selfoss.R; import fr.ydelouis.selfoss.entity.Success; import fr.ydelouis.selfoss.rest.SelfossApiInterceptor; import fr.ydelouis.selfoss.rest.SelfossApiRequestFactory; import fr.ydelouis.selfoss.rest.SelfossRest; @EBean public class ConfigValidator { public interface UrlValidationCallback { void onUrlValidationSuccess(); void onUrlValidationFailed(Exception exception); } public interface AuthValidationCallback { void onAuthValidationSuccess(); void onAuthValidationFailed(Exception exception); } public class CertificateException extends Exception {} public class InvalidUsernameException extends Exception {} public class IncorrectPasswordException extends Exception {} @RootContext protected Context context; @RestService protected SelfossRest selfossRest; @Bean protected SelfossApiInterceptor interceptor; @Bean protected SelfossApiRequestFactory requestFactory; private Config config; private boolean requireAuth; public void setConfig(Config config) { this.config = config; interceptor.setConfig(config); requestFactory.setConfig(config); RestTemplate restTemplate = selfossRest.getRestTemplate(); restTemplate.getInterceptors().clear(); restTemplate.getInterceptors().add(interceptor); restTemplate.setRequestFactory(requestFactory); } // Url public void validateUrl(String url, @NonNull UrlValidationCallback callback) { if(isUrlValid(url)) { setUseHttps(url); String cleanUrl = cleanUrl(url); checkUrl(cleanUrl, false, callback); } else { callback.onUrlValidationFailed(new Exception(context.getString(R.string.error_urlEmpty))); } } public void validateUrlTrustingAllCertificates(String url, @NonNull UrlValidationCallback callback) { if(isUrlValid(url)) { String cleanUrl = cleanUrl(url); checkUrl(cleanUrl, true, callback); } else { callback.onUrlValidationFailed(new Exception(context.getString(R.string.error_urlEmpty))); } } private boolean isUrlValid(String url) { return !url.isEmpty(); } private void setUseHttps(String url) { config.setUseHttps(url.startsWith("https://")); } private String cleanUrl(String url) { String cleanedUrl = removeScheme(url); cleanedUrl = removeTrailingSlash(cleanedUrl); return cleanedUrl; } private String removeScheme(String url) { String schemeMark = "://"; int start = url.indexOf(schemeMark); if (start != -1) { return url.substring(start+schemeMark.length()); } return url; } private String removeTrailingSlash(String url) { String trailingSlash = "/"; if (url.endsWith(trailingSlash)) { return url.substring(0, url.length()-trailingSlash.length()); } return url; } private void checkUrl(String url, boolean trustAllCertificates, @NonNull UrlValidationCallback callback) { config.setUrl(url); config.setTrustAllCertificates(trustAllCertificates); requireAuth = false; try { Success success = selfossRest.login(); if (!success.isSuccess() && !isBecauseOfBugLogin()) { requireAuth = true; tryWithHttps(); } callback.onUrlValidationSuccess(); } catch (RestClientException e) { handleUrlException(e, callback); } } private boolean isBecauseOfBugLogin() { try { selfossRest.listTags(); return true; } catch (RestClientException e) { return false; } } private void tryWithHttps() { config.setUseHttps(true); try { selfossRest.login(); } catch (RestClientException e) { config.setUseHttps(false); } } private void handleUrlException(Exception exception, @NonNull UrlValidationCallback callback) { if (isCertificateException(exception)) { exception = new CertificateException(); } callback.onUrlValidationFailed(exception); } private boolean isCertificateException(Exception e) { return e.getCause() instanceof IOException && e.getMessage().contains("Hostname") && e.getMessage().contains("was not verified"); } // Auth public boolean requireAuth() { return requireAuth; } public void validateUsernameAndPassword(String username, String password, AuthValidationCallback callback) { if(isUsernameValid(username)) { config.setUsername(username); config.setPassword(password); checkAuth(callback); } else { callback.onAuthValidationFailed(new InvalidUsernameException()); } } private void checkAuth(AuthValidationCallback callback) { try { Success success = selfossRest.login(); if (success.isSuccess()) { callback.onAuthValidationSuccess(); } else { callback.onAuthValidationFailed(new IncorrectPasswordException()); } } catch (RestClientException exception) { callback.onAuthValidationFailed(exception); } } private boolean isUsernameValid(String username) { return !username.isEmpty(); } }