diff --git a/src/main/java/ctbrec/Settings.java b/src/main/java/ctbrec/Settings.java index 97b8bcd4..1da9aaf6 100644 --- a/src/main/java/ctbrec/Settings.java +++ b/src/main/java/ctbrec/Settings.java @@ -24,6 +24,8 @@ public class Settings { public String password = ""; // chaturbate password TODO maybe rename this onetime public String mfcUsername = ""; public String mfcPassword = ""; + public String cam4Username; + public String cam4Password; public String lastDownloadDir = ""; public List models = new ArrayList(); diff --git a/src/main/java/ctbrec/sites/cam4/Cam4.java b/src/main/java/ctbrec/sites/cam4/Cam4.java index 9198aa87..34c9572b 100644 --- a/src/main/java/ctbrec/sites/cam4/Cam4.java +++ b/src/main/java/ctbrec/sites/cam4/Cam4.java @@ -62,17 +62,13 @@ public class Cam4 extends AbstractSite { @Override public void login() throws IOException { + getHttpClient().login(); } @Override public HttpClient getHttpClient() { if(httpClient == null) { - httpClient = new HttpClient() { - @Override - public boolean login() throws IOException { - return false; - } - }; + httpClient = new Cam4HttpClient(); } return httpClient; } diff --git a/src/main/java/ctbrec/sites/cam4/Cam4HttpClient.java b/src/main/java/ctbrec/sites/cam4/Cam4HttpClient.java new file mode 100644 index 00000000..0e4dbbb1 --- /dev/null +++ b/src/main/java/ctbrec/sites/cam4/Cam4HttpClient.java @@ -0,0 +1,64 @@ +package ctbrec.sites.cam4; + +import java.io.IOException; +import java.net.HttpCookie; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.json.JSONObject; + +import ctbrec.io.HttpClient; +import okhttp3.Cookie; +import okhttp3.HttpUrl; +import okhttp3.Request; +import okhttp3.Response; + +public class Cam4HttpClient extends HttpClient { + + @Override + public boolean login() throws IOException { + // login with javafx WebView + Cam4LoginDialog loginDialog = new Cam4LoginDialog(); + + // transfer cookies from WebView to OkHttp cookie jar + transferCookies(loginDialog); + + return checkLoginSuccess(); + } + + /** + * check, if the login worked by requesting unchecked mail + * @throws IOException + */ + private boolean checkLoginSuccess() throws IOException { + String mailUrl = "https://www.cam4.de.com/mail/unreadThreads"; + Request req = new Request.Builder().url(mailUrl).build(); + Response response = execute(req); + if(response.isSuccessful()) { + JSONObject json = new JSONObject(response.body().string()); + return json.has("status") && Objects.equals("success", json.getString("status")); + } else { + response.close(); + return false; + } + } + + private void transferCookies(Cam4LoginDialog 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); + } +} diff --git a/src/main/java/ctbrec/sites/cam4/Cam4LoginDialog.java b/src/main/java/ctbrec/sites/cam4/Cam4LoginDialog.java new file mode 100644 index 00000000..d10bfec0 --- /dev/null +++ b/src/main/java/ctbrec/sites/cam4/Cam4LoginDialog.java @@ -0,0 +1,101 @@ +package ctbrec.sites.cam4; + +import java.net.CookieHandler; +import java.net.CookieManager; +import java.net.HttpCookie; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.Objects; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ctbrec.Config; +import javafx.concurrent.Worker.State; +import javafx.scene.Scene; +import javafx.scene.control.ProgressIndicator; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebView; +import javafx.stage.Stage; + +public class Cam4LoginDialog { + + private static final transient Logger LOG = LoggerFactory.getLogger(Cam4LoginDialog.class); + public static final String URL = Cam4.BASE_URI + "/login"; + private List cookies = null; + private String url; + private Region veil; + private ProgressIndicator p; + + public Cam4LoginDialog() { + Stage stage = new Stage(); + stage.setTitle("Cam4 Login"); + CookieManager cookieManager = new CookieManager(); + CookieHandler.setDefault(cookieManager); + WebView webView = createWebView(stage); + + veil = new Region(); + veil.setStyle("-fx-background-color: rgba(0, 0, 0, 0.4)"); + //veil.setPrefSize(240, 160); + p = new ProgressIndicator(); + p.setMaxSize(140, 140); + + StackPane stackPane = new StackPane(); + stackPane.getChildren().addAll(webView, veil, p); + + stage.setScene(new Scene(stackPane, 480, 854)); + stage.showAndWait(); + cookies = cookieManager.getCookieStore().getCookies(); + } + + private WebView createWebView(Stage stage) { + WebView browser = new WebView(); + WebEngine webEngine = browser.getEngine(); + webEngine.setJavaScriptEnabled(true); + webEngine.locationProperty().addListener((obs, oldV, newV) -> { + try { + URL _url = new URL(newV); + if (Objects.equals(_url.getPath(), "/")) { + stage.close(); + } + } catch (MalformedURLException e) { + LOG.error("Couldn't parse new url {}", newV, e); + } + url = newV.toString(); + }); + webEngine.getLoadWorker().stateProperty().addListener((observable, oldState, newState) -> { + System.out.println(newState); + if (newState == State.SUCCEEDED) { + String username = Config.getInstance().getSettings().cam4Username; + if (username != null && !username.trim().isEmpty()) { + webEngine.executeScript("$('input[name=username]').attr('value','" + username + "')"); + } + String password = Config.getInstance().getSettings().cam4Password; + if (password != null && !password.trim().isEmpty()) { + webEngine.executeScript("$('input[name=password]').attr('value','" + password + "')"); + } + webEngine.executeScript("$('div[class~=navbar]').css('display','none')"); + webEngine.executeScript("$('div#footer').css('display','none')"); + webEngine.executeScript("$('div#content').css('padding','0')"); + veil.setVisible(false); + p.setVisible(false); + } else if (newState == State.CANCELLED || newState == State.FAILED) { + veil.setVisible(false); + p.setVisible(false); + } + }); + webEngine.load(URL); + return browser; + } + + public List getCookies() { + return cookies; + } + + public String getUrl() { + return url; + } +} diff --git a/src/main/java/ctbrec/ui/CookieJarImpl.java b/src/main/java/ctbrec/ui/CookieJarImpl.java index e0bee9ee..ce18ea4d 100644 --- a/src/main/java/ctbrec/ui/CookieJarImpl.java +++ b/src/main/java/ctbrec/ui/CookieJarImpl.java @@ -6,6 +6,7 @@ import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,7 +51,11 @@ public class CookieJarImpl implements CookieJar { public List loadForRequest(HttpUrl url) { String host = getHost(url); List cookies = cookieStore.get(host); - LOG.debug("Cookies for {}: {}", url.host(), cookies); + LOG.debug("Cookies for {}", url); + Optional.ofNullable(cookies).ifPresent(cookiez -> cookiez.forEach(c -> { + LOG.debug(" {} expires on:{}", c, c.expiresAt()); + })); + //LOG.debug("Cookies for {}: {}", url.host(), cookies); return cookies != null ? cookies : new ArrayList(); }