From 69194e2800eef450498ac8b2f570a67060006299 Mon Sep 17 00:00:00 2001 From: 0xboobface <0xboobface@gmail.com> Date: Tue, 6 Nov 2018 00:17:41 +0100 Subject: [PATCH] Add login dialog for BongaCams --- .../java/ctbrec/sites/bonga/BongaCams.java | 6 +- .../sites/bonga/BongaCamsHttpClient.java | 192 ++++++++++++++++-- .../sites/bonga/BongaCamsLoginDialog.java | 118 +++++++++++ src/main/java/ctbrec/ui/ThumbCell.java | 2 +- 4 files changed, 297 insertions(+), 21 deletions(-) create mode 100644 src/main/java/ctbrec/sites/bonga/BongaCamsLoginDialog.java diff --git a/src/main/java/ctbrec/sites/bonga/BongaCams.java b/src/main/java/ctbrec/sites/bonga/BongaCams.java index d152a46c..075c83b0 100644 --- a/src/main/java/ctbrec/sites/bonga/BongaCams.java +++ b/src/main/java/ctbrec/sites/bonga/BongaCams.java @@ -78,8 +78,9 @@ public class BongaCams extends AbstractSite { try(Response response = getHttpClient().execute(request, true)) { if(response.isSuccessful()) { JSONObject json = new JSONObject(response.body().string()); - if(json.optString("status").equals("success")) { - System.out.println(json.toString(2)); + if(json.optString("status").equals("online")) { + JSONObject userData = json.getJSONObject("userData"); + return userData.getInt("balance"); } else { throw new IOException("Request was not successful: " + json.toString(2)); } @@ -87,7 +88,6 @@ public class BongaCams extends AbstractSite { throw new IOException(response.code() + " " + response.message()); } } - return 0; } @Override diff --git a/src/main/java/ctbrec/sites/bonga/BongaCamsHttpClient.java b/src/main/java/ctbrec/sites/bonga/BongaCamsHttpClient.java index 35be111d..4a16ff98 100644 --- a/src/main/java/ctbrec/sites/bonga/BongaCamsHttpClient.java +++ b/src/main/java/ctbrec/sites/bonga/BongaCamsHttpClient.java @@ -1,53 +1,156 @@ package ctbrec.sites.bonga; import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Date; +import java.net.HttpCookie; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ctbrec.Config; import ctbrec.io.HttpClient; +import javafx.application.Platform; +import okhttp3.Cookie; import okhttp3.FormBody; +import okhttp3.HttpUrl; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; +import okio.ByteString; public class BongaCamsHttpClient extends HttpClient { private static final transient Logger LOG = LoggerFactory.getLogger(BongaCamsHttpClient.class); @Override - public boolean login() throws IOException { - String url = BongaCams.BASE_URL + "/login"; - String dateTime = new SimpleDateFormat("d.MM.yyyy', 'HH:mm:ss").format(new Date()); + public synchronized boolean login() throws IOException { + if(loggedIn) { + return true; + } + + BlockingQueue queue = new LinkedBlockingQueue<>(); + + Runnable showDialog = () -> { + // login with javafx WebView + BongaCamsLoginDialog loginDialog = new BongaCamsLoginDialog(); + + // 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(); + createWebSocket(); + return loggedIn; + } + + private void createWebSocket() { + // $.noticeSocket = new SocketAdapter('wss://notice.bcrncdn.com:443/ws'); + // $.noticeSocket.onopen = function(){ + // this.send({type: 'identify', data: '0387db666178a863395c49f5f912cf070055482716514804'}); + // $(document).trigger('onNoticeSocketOpen'); + // }; + // $.noticeSocket.onmessage = function(e){$(document).trigger('onNoticeSocketMessage', [e])}; + // $(function() { + // window.setTimeout($.checkAuth, 3600 * 5 * 1000); + // if ($('#email_confirmed_popup').length > 0) { + // $('#email_confirmed_popup').show(); + // setTimeout(function() { $('#email_confirmed_popup').fadeOut('fast');}, 5000); + // } + // }); + Request req = new Request.Builder() + .url("wss://notice.bcrncdn.com:443/ws") + .build(); + LOG.debug("Creating websocket"); + WebSocket ws = super.client.newWebSocket(req, new WebSocketListener() { + @Override + public void onOpen(WebSocket webSocket, Response response) { + super.onOpen(webSocket, response); + try { + LOG.trace("open: [{}]", response.body().string()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void onClosed(WebSocket webSocket, int code, String reason) { + super.onClosed(webSocket, code, reason); + LOG.info("Bonga websocket closed: {} {}", code, reason); + } + + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + super.onFailure(webSocket, t, response); + LOG.error("Bonga websocket failure: {} {}", response.code(), response.message(), t); + } + + @Override + public void onMessage(WebSocket webSocket, String text) { + super.onMessage(webSocket, text); + LOG.debug("onMessage {}", text); + } + + @Override + public void onMessage(WebSocket webSocket, ByteString bytes) { + super.onMessage(webSocket, bytes); + LOG.debug("msgb: {}", bytes.hex()); + } + }); + } + + + /** + * check, if the login by sending a ping request + * @throws IOException + */ + private boolean checkLoginSuccess() throws IOException { + String url = BongaCams.BASE_URL + "/tools/amf.php"; RequestBody body = new FormBody.Builder() - .add("security_log_additional_info","{\"language\":\"en\",\"cookieEnabled\":true,\"javaEnabled\":false,\"flashVersion\":\"31.0.0\",\"dateTime\":\""+dateTime+"\",\"ips\":[\"192.168.0.1\"]}") - .add("log_in[username]", Config.getInstance().getSettings().bongaUsername) - .add("log_in[password]", Config.getInstance().getSettings().bongaPassword) - .add("log_in[remember]", "1") - .add("log_in[bfpt]", "") - .add("header_form", "1") + // .add("method", "getRoomData") + // .add("args[]", name) + // .add("args[]", "false") + .add("method", "ping") + .add("args[]", "66050808") // TODO where to get the userId .build(); Request request = new Request.Builder() .url(url) - .post(body) .addHeader("User-Agent", "Mozilla/5.0 (Android 9.0; Mobile; rv:61.0) Gecko/61.0 Firefox/61.0") - .addHeader("Accept","application/json") + .addHeader("Accept", "application/json, text/javascript, */*") .addHeader("Accept-Language", "en") .addHeader("Referer", BongaCams.BASE_URL) .addHeader("X-Requested-With", "XMLHttpRequest") + .post(body) .build(); try(Response response = execute(request)) { if(response.isSuccessful()) { JSONObject json = new JSONObject(response.body().string()); - if(json.optString("status").equals("success")) { + if(json.optString("status").equals("online")) { return true; } else { - LOG.debug("Login response: {}", json.toString(2)); - throw new IOException("Login not successful"); + throw new IOException("Request was not successful: " + json.toString(2)); } } else { throw new IOException(response.code() + " " + response.message()); @@ -55,4 +158,59 @@ public class BongaCamsHttpClient extends HttpClient { } } + private void transferCookies(BongaCamsLoginDialog 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(BongaCamsLoginDialog.URL); + cookies = new ArrayList<>(); + for (HttpCookie webViewCookie : loginDialog.getCookies()) { + Cookie cookie = Cookie.parse(origUrl, webViewCookie.toString()); + cookies.add(cookie); + } + cookieJar.saveFromResponse(origUrl, cookies); + } + + // @Override + // public boolean login() throws IOException { + // String url = BongaCams.BASE_URL + "/login"; + // String dateTime = new SimpleDateFormat("d.MM.yyyy', 'HH:mm:ss").format(new Date()); + // RequestBody body = new FormBody.Builder() + // .add("security_log_additional_info","{\"language\":\"en\",\"cookieEnabled\":true,\"javaEnabled\":false,\"flashVersion\":\"31.0.0\",\"dateTime\":\""+dateTime+"\",\"ips\":[\"192.168.0.1\"]}") + // .add("log_in[username]", Config.getInstance().getSettings().bongaUsername) + // .add("log_in[password]", Config.getInstance().getSettings().bongaPassword) + // .add("log_in[remember]", "1") + // .add("log_in[bfpt]", "") + // .add("header_form", "1") + // .build(); + // Request request = new Request.Builder() + // .url(url) + // .post(body) + // .addHeader("User-Agent", "Mozilla/5.0 (Android 9.0; Mobile; rv:61.0) Gecko/61.0 Firefox/61.0") + // .addHeader("Accept","application/json") + // .addHeader("Accept-Language", "en") + // .addHeader("Referer", BongaCams.BASE_URL) + // .addHeader("X-Requested-With", "XMLHttpRequest") + // .build(); + // try(Response response = execute(request)) { + // if(response.isSuccessful()) { + // JSONObject json = new JSONObject(response.body().string()); + // if(json.optString("status").equals("success")) { + // return true; + // } else { + // LOG.debug("Login response: {}", json.toString(2)); + // Platform.runLater(() -> new BongaCamsLoginDialog()); + // throw new IOException("Login not successful"); + // } + // } else { + // throw new IOException(response.code() + " " + response.message()); + // } + // } + // } + } diff --git a/src/main/java/ctbrec/sites/bonga/BongaCamsLoginDialog.java b/src/main/java/ctbrec/sites/bonga/BongaCamsLoginDialog.java new file mode 100644 index 00000000..0d609311 --- /dev/null +++ b/src/main/java/ctbrec/sites/bonga/BongaCamsLoginDialog.java @@ -0,0 +1,118 @@ +package ctbrec.sites.bonga; + +import java.io.File; +import java.io.InputStream; +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 ctbrec.OS; +import javafx.concurrent.Worker.State; +import javafx.scene.Scene; +import javafx.scene.control.ProgressIndicator; +import javafx.scene.image.Image; +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 BongaCamsLoginDialog { + + private static final transient Logger LOG = LoggerFactory.getLogger(BongaCamsLoginDialog.class); + public static final String URL = BongaCams.BASE_URL + "/login"; + private List cookies = null; + private String url; + private Region veil; + private ProgressIndicator p; + + public BongaCamsLoginDialog() { + Stage stage = new Stage(); + stage.setTitle("BongaCams Login"); + InputStream icon = getClass().getResourceAsStream("/icon.png"); + stage.getIcons().add(new Image(icon)); + 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)"); + p = new ProgressIndicator(); + p.setMaxSize(140, 140); + + StackPane stackPane = new StackPane(); + stackPane.getChildren().addAll(webView, veil, p); + + stage.setScene(new Scene(stackPane, 640, 480)); + 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) -> { + if (newState == State.SUCCEEDED) { + veil.setVisible(false); + p.setVisible(false); + //System.out.println("############# " + webEngine.getLocation()); + //System.out.println(webEngine.getDocument().getDocumentElement().getTextContent()); + try { + String username = Config.getInstance().getSettings().bongaUsername; + if (username != null && !username.trim().isEmpty()) { + webEngine.executeScript("$('input[name=\"log_in[username]\"]').attr('value','" + username + "')"); + } + String password = Config.getInstance().getSettings().bongaPassword; + if (password != null && !password.trim().isEmpty()) { + webEngine.executeScript("$('input[name=\"log_in[password]\"]').attr('value','" + password + "')"); + } + webEngine.executeScript("$('div[class~=\"fancybox-overlay\"]').css('display','none')"); + webEngine.executeScript("$('div#header').css('display','none')"); + webEngine.executeScript("$('div.footer').css('display','none')"); + webEngine.executeScript("$('div.footer_copy').css('display','none')"); + webEngine.executeScript("$('div[class~=\"banner_top_index\"]').css('display','none')"); + webEngine.executeScript("$('td.menu_container').css('display','none')"); + } catch(Exception e) { + LOG.warn("Couldn't auto fill username and password for BongaCams", e); + } + } else if (newState == State.CANCELLED || newState == State.FAILED) { + veil.setVisible(false); + p.setVisible(false); + } + }); + webEngine.setUserDataDirectory(new File(OS.getConfigDir(), "webengine")); + webEngine.load(URL); + return browser; + } + + public List getCookies() { + // for (HttpCookie httpCookie : cookies) { + // LOG.debug("Cookie: {}", httpCookie); + // } + return cookies; + } + + public String getUrl() { + return url; + } +} diff --git a/src/main/java/ctbrec/ui/ThumbCell.java b/src/main/java/ctbrec/ui/ThumbCell.java index f579a948..133d37a2 100644 --- a/src/main/java/ctbrec/ui/ThumbCell.java +++ b/src/main/java/ctbrec/ui/ThumbCell.java @@ -208,7 +208,7 @@ public class ThumbCell extends StackPane { LOG.trace("Removing invalid resolution value for {}", model.getName()); model.invalidateCacheEntries(); } - + Thread.sleep(500); } catch (IOException | InterruptedException e1) { LOG.warn("Couldn't update resolution tag for model {}", model.getName(), e1);