package ctbrec.sites.camsoda; import java.io.IOException; import java.net.HttpCookie; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import org.json.JSONObject; import org.jsoup.nodes.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ctbrec.Config; import ctbrec.io.HttpClient; import ctbrec.io.HttpException; import ctbrec.sites.cam4.Cam4LoginDialog; import ctbrec.ui.HtmlParser; import javafx.application.Platform; import okhttp3.Cookie; import okhttp3.FormBody; import okhttp3.HttpUrl; import okhttp3.Request; import okhttp3.Response; public class CamsodaHttpClient extends HttpClient { private static final transient Logger LOG = LoggerFactory.getLogger(CamsodaHttpClient.class); private String csrfToken = null; public CamsodaHttpClient() { super("camsoda"); } @Override public boolean login() throws IOException { if(loggedIn) { return true; } // persisted cookies might let us log in if(checkLoginSuccess()) { loggedIn = true; LOG.debug("Logged in with cookies"); return true; } String url = Camsoda.BASE_URI + "/api/v1/auth/login"; FormBody body = new FormBody.Builder() .add("username", Config.getInstance().getSettings().camsodaUsername) .add("password", Config.getInstance().getSettings().camsodaPassword) .build(); Request request = new Request.Builder() .url(url) .post(body) .build(); try (Response response = execute(request)) { if (response.isSuccessful()) { JSONObject resp = new JSONObject(response.body().string()); if (resp.has("error")) { String error = resp.getString("error"); if (Objects.equals(error, "Please confirm that you are not a robot.")) { // return loginWithDialog(); throw new IOException("CamSoda requested to solve a captcha. Please try again in a while (maybe 15 min)."); } else { throw new IOException(resp.getString("error")); } } else { return true; } } else { throw new HttpException(response.code(), response.message()); } } } @SuppressWarnings("unused") private boolean loginWithDialog() throws IOException { BlockingQueue queue = new LinkedBlockingQueue<>(); Runnable showDialog = () -> { // login with javafx WebView CamsodaLoginDialog loginDialog = new CamsodaLoginDialog(); // transfer cookies from WebView to OkHttp cookie jar transferCookies(loginDialog); try { queue.put(true); } catch (InterruptedException e) { LOG.error("Error while signaling termination", e); } }; if(Platform.isFxApplicationThread()) { showDialog.run(); } else { Platform.runLater(showDialog); try { queue.take(); } catch (InterruptedException e) { LOG.error("Error while waiting for login dialog to close", e); throw new IOException(e); } } loggedIn = checkLoginSuccess(); return loggedIn; } /** * check, if the login worked * @throws IOException */ private boolean checkLoginSuccess() throws IOException { String url = Camsoda.BASE_URI + "/api/v1/user/current"; Request request = new Request.Builder().url(url).build(); try(Response response = execute(request)) { if(response.isSuccessful()) { JSONObject resp = new JSONObject(response.body().string()); return resp.optBoolean("status"); } else { return false; } } } private void transferCookies(CamsodaLoginDialog loginDialog) { HttpUrl redirectedUrl = HttpUrl.parse(loginDialog.getUrl()); List cookies = new ArrayList<>(); for (HttpCookie webViewCookie : loginDialog.getCookies()) { Cookie cookie = Cookie.parse(redirectedUrl, webViewCookie.toString()); cookies.add(cookie); } cookieJar.saveFromResponse(redirectedUrl, cookies); HttpUrl origUrl = HttpUrl.parse(Cam4LoginDialog.URL); cookies = new ArrayList<>(); for (HttpCookie webViewCookie : loginDialog.getCookies()) { Cookie cookie = Cookie.parse(origUrl, webViewCookie.toString()); cookies.add(cookie); } cookieJar.saveFromResponse(origUrl, cookies); } protected String getCsrfToken() throws IOException { if(csrfToken == null) { String url = Camsoda.BASE_URI; Request request = new Request.Builder().url(url).build(); try(Response response = execute(request, true)) { if(response.isSuccessful()) { Element meta = HtmlParser.getTag(response.body().string(), "meta[name=\"_token\"]"); csrfToken = meta.attr("content"); } else { throw new HttpException(response.code(), response.message()); } } } return csrfToken; } }