diff --git a/common/src/main/java/ctbrec/sites/stripchat/Stripchat.java b/common/src/main/java/ctbrec/sites/stripchat/Stripchat.java index 4933f3d1..75e3eb39 100644 --- a/common/src/main/java/ctbrec/sites/stripchat/Stripchat.java +++ b/common/src/main/java/ctbrec/sites/stripchat/Stripchat.java @@ -28,7 +28,7 @@ public class Stripchat extends AbstractSite { @Getter @Setter(AccessLevel.PROTECTED) - private static String domain = "stripchat.com"; + public static String domain = "stripchat.com"; @Getter @Setter(AccessLevel.PROTECTED) private static String baseUri = "https://stripchat.com"; diff --git a/common/src/main/java/ctbrec/sites/stripchat/StripchatHttpClient.java b/common/src/main/java/ctbrec/sites/stripchat/StripchatHttpClient.java index 142dd6ca..fa108021 100644 --- a/common/src/main/java/ctbrec/sites/stripchat/StripchatHttpClient.java +++ b/common/src/main/java/ctbrec/sites/stripchat/StripchatHttpClient.java @@ -4,35 +4,35 @@ import ctbrec.Config; import ctbrec.StringUtil; import ctbrec.io.HttpClient; import ctbrec.io.HttpException; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import okhttp3.*; -import org.json.JSONException; -import org.json.JSONObject; - -import java.time.Instant; -import java.util.Base64; -import java.nio.charset.StandardCharsets; +// import ctbrec.sites.stripchat.Stripchat; +// import ctbrec.sites.stripchat.StripchatUtil; import java.io.IOException; import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Base64; +import okhttp3.Cookie; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.json.JSONException; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import static ctbrec.io.HttpConstants.*; -import static java.nio.charset.StandardCharsets.UTF_8; - -@Slf4j -public class StripchatHttpClient extends HttpClient { - - public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - - private long userId = 0; - private String csrfToken; - @Getter - private String csrfTimestamp; - @Getter - private String csrfNotifyTimestamp; - @Getter - private String jwtToken; - private Instant jwtTokenExp; +public class StripchatHttpClient +extends HttpClient { + private static final Logger LOG = LoggerFactory.getLogger(StripchatHttpClient.class); + public static final MediaType JSON = MediaType.parse((String)"application/json; charset=utf-8"); + private static long userId = 0L; + private static String csrfToken; + private static String csrfTimestamp; + private static String csrfNotifyTimestamp; + private static String jwtToken; + private static Instant jwtTokenExp; public StripchatHttpClient(Config config) { super("stripchat", config); @@ -40,138 +40,143 @@ public class StripchatHttpClient extends HttpClient { @Override public boolean login() throws IOException { - // refresh token if needed - getCsrfToken(); - - // already logged in - if (loggedIn && isJwtTokenValid()) { + this.getCsrfToken(); + if (this.loggedIn && this.isJwtTokenValid()) { return true; } - - // persisted cookies might let us log in - if (checkLoginSuccess()) { - loggedIn = true; - log.debug("Logged in with cookies"); + if (this.checkLoginSuccess()) { + this.loggedIn = true; + LOG.debug("Logged in with cookies"); return true; } - - String url = Stripchat.getBaseUri() + "/api/front/auth/login"; JSONObject requestParams = new JSONObject(); requestParams.put("loginOrEmail", config.getSettings().stripchatUsername); requestParams.put("password", config.getSettings().stripchatPassword); - requestParams.put("remember", true); - requestParams.put("csrfToken", csrfToken); + requestParams.put("remember", true).put("csrfToken", csrfToken); requestParams.put("csrfTimestamp", csrfTimestamp); requestParams.put("csrfNotifyTimestamp", csrfNotifyTimestamp); RequestBody body = RequestBody.Companion.create(requestParams.toString(), JSON); Request request = new Request.Builder() .url(url) - .header(ACCEPT, MIMETYPE_APPLICATION_JSON) - .header(USER_AGENT, config.getSettings().httpUserAgent) - .header(ORIGIN, Stripchat.getBaseUri()) - .header(REFERER, Stripchat.getBaseUri()) - .header(CONTENT_TYPE, MIMETYPE_APPLICATION_JSON) + .header("Accept", "application/json") + .header("User-Agent", config.getSettings().httpUserAgent) + .header("Origin", Stripchat.getBaseUri()).header("Referer", Stripchat.getBaseUri()) + .header("Content-Type", "application/json") .post(body) .build(); - try (Response response = execute(request)) { + try (Response response = this.execute(request);){ if (response.isSuccessful()) { JSONObject resp = new JSONObject(response.body().string()); if (resp.has("user")) { JSONObject user = resp.getJSONObject("user"); userId = user.optLong("id"); - return true; - } else { - return false; + boolean bl = true; + return bl; } - } else { - log.info("Auto-Login failed: {} {} {}", response.code(), response.message(), url); - return false; + boolean bl = false; + return bl; } + LOG.info("Auto-Login failed: {} {} {}", new Object[]{response.code(), response.message(), url}); + boolean bl = false; + return bl; } } private void loadCsrfToken() throws IOException { - String url = Stripchat.getBaseUri() + "/api/front/v3/config/initial?requestPath=%2F&timezoneOffset=0"; - Request request = new Request.Builder() - .url(url) - .header(ACCEPT, MIMETYPE_APPLICATION_JSON) - .header(USER_AGENT, config.getSettings().httpUserAgent) - .header(ORIGIN, Stripchat.getBaseUri()) - .header(REFERER, Stripchat.getBaseUri()) - .header(CONTENT_TYPE, MIMETYPE_APPLICATION_JSON) - .build(); - try (Response response = execute(request)) { - if (response.isSuccessful()) { - JSONObject resp = new JSONObject(response.body().string()); - JSONObject data = resp.getJSONObject("initial").getJSONObject("client"); - csrfToken = data.optString("csrfToken"); - csrfTimestamp = data.optString("csrfTimestamp"); - csrfNotifyTimestamp = data.optString("csrfNotifyTimestamp"); - log.debug("Stripchat token CSRF: {} [{}]", csrfToken, csrfNotifyTimestamp); - } else { + block9: { + csrfToken = ""; + csrfTimestamp = ""; + csrfNotifyTimestamp = ""; + String url = Stripchat.getBaseUri() + "/api/front/v3/config/initial?requestPath=%2F&timezoneOffset=0&disableClient=0&uniq=" + StripchatUtil.getUniq(); + Request request = new Request.Builder().url(url).header("Accept", "application/json") + .header("User-Agent", config.getSettings().httpUserAgent) + .header("Origin", Stripchat.getBaseUri()) + .header("Referer", Stripchat.getBaseUri()) + .header("Content-Type", "application/json") + .build(); + try (Response response = this.execute(request);){ + if (response.isSuccessful()) { + JSONObject initial; + JSONObject resp = new JSONObject(response.body().string()); + if (resp.has("initial") && (initial = resp.getJSONObject("initial")).has("client")) { + JSONObject client = initial.getJSONObject("client"); + csrfToken = client.optString("csrfToken"); + csrfTimestamp = client.optString("csrfTimestamp"); + csrfNotifyTimestamp = client.optString("csrfNotifyTimestamp"); + LOG.debug("Stripchat CSRF token: {} [{}]", (Object)csrfToken, (Object)csrfNotifyTimestamp); + } + if (StringUtil.isBlank(csrfToken)) { + LOG.debug("Stripchat CSRF token not found"); + } + break block9; + } throw new HttpException(response.code(), response.message()); } } } private void loadJwtToken() throws IOException { - String url = Stripchat.getBaseUri() + "/api/front/v3/config/dynamic"; - Request request = new Request.Builder() - .url(url) - .header(ACCEPT, MIMETYPE_APPLICATION_JSON) - .header(USER_AGENT, config.getSettings().httpUserAgent) - .header(ORIGIN, Stripchat.getBaseUri()) - .header(REFERER, Stripchat.getBaseUri()) - .header(CONTENT_TYPE, MIMETYPE_APPLICATION_JSON) - .build(); - try (Response response = execute(request)) { - if (response.isSuccessful()) { - JSONObject resp = new JSONObject(response.body().string()); - JSONObject dynamic = resp.getJSONObject("dynamic"); - jwtToken = dynamic.optString("jwtToken"); - if (StringUtil.isNotBlank(jwtToken)) { - String[] parts = jwtToken.split("\\."); - if (parts.length > 1) { - String decString = new String(Base64.getDecoder().decode(parts[1]), StandardCharsets.UTF_8); - JSONObject body = new JSONObject(decString); - jwtTokenExp = Instant.ofEpochSecond(body.optLong("exp")); + block11: { + jwtToken = ""; + String url = Stripchat.getBaseUri() + "/api/front/v3/config/dynamic?uniq=" + StripchatUtil.getUniq(); + Request request = new Request.Builder().url(url) + .header("Accept", "application/json") + .header("User-Agent", config.getSettings().httpUserAgent) + .header("Origin", Stripchat.getBaseUri()) + .header("Referer", Stripchat.getBaseUri()) + .header("Content-Type", "application/json") + .build(); + try (Response response = execute(request);){ + if (response.isSuccessful()) { + JSONObject resp = new JSONObject(response.body().string()); + if (resp.has("dynamic")) { + JSONObject dynamic = resp.getJSONObject("dynamic"); + jwtToken = dynamic.optString("jwtToken"); } + if (StringUtil.isNotBlank(jwtToken)) { + String[] parts = jwtToken.split("\\."); + if (parts.length > 1) { + String decString = new String(Base64.getDecoder().decode(parts[1]), StandardCharsets.UTF_8); + JSONObject body = new JSONObject(decString); + jwtTokenExp = Instant.ofEpochSecond(body.optLong("exp")); + } + LOG.debug("Stripchat JWT token: {} [{}]", (Object)jwtToken, (Object)jwtTokenExp); + } else { + LOG.debug("Stripchat JWT token not found"); + } + break block11; } - log.debug("Stripchat token JWT: {} [{}]", jwtToken, jwtTokenExp); - } else { throw new HttpException(response.code(), response.message()); } } } - /** - * check, if the login worked - * @throws IOException - */ public boolean checkLoginSuccess() throws IOException { getJwtToken(); getCsrfToken(); return StringUtil.isNotBlank(jwtToken) && StringUtil.isNotBlank(csrfToken); } - + public long getUserId() throws JSONException, IOException { - if (userId == 0) { - String url = Stripchat.getBaseUri() + "/api/front/users/username/" + config.getSettings().stripchatUsername; - Request request = new Request.Builder() - .url(url) - .header(ACCEPT, MIMETYPE_APPLICATION_JSON) - .header(USER_AGENT, config.getSettings().httpUserAgent) - .header(ORIGIN, Stripchat.getBaseUri()) - .header(REFERER, Stripchat.getBaseUri()) - .header(CONTENT_TYPE, MIMETYPE_APPLICATION_JSON) - .build(); - try (Response response = execute(request)) { - if (response.isSuccessful()) { - JSONObject resp = new JSONObject(response.body().string()); - JSONObject user = resp.getJSONObject("user"); - userId = user.optLong("id"); - } else { + block8: { + if (userId == 0L) { + String url = Stripchat.getBaseUri() + "/api/front/users/username/" + config.getSettings().stripchatUsername; + Request request = new Request.Builder() + .url(url) + .header("Accept", "application/json") + .header("User-Agent", config.getSettings().httpUserAgent) + .header("Origin", Stripchat.getBaseUri()) + .header("Referer", Stripchat.getBaseUri()) + .header("Content-Type", "application/json") + .build(); + try (Response response = execute(request);){ + if (response.isSuccessful()) { + JSONObject resp = new JSONObject(response.body().string()); + JSONObject user = resp.getJSONObject("user"); + userId = user.optLong("id"); + break block8; + } throw new HttpException(url, response.code(), response.message()); } } @@ -179,13 +184,15 @@ public class StripchatHttpClient extends HttpClient { return userId; } - public JSONObject getAmpl() { + public JSONObject getAmpl() { try { - Cookie cookie = getCookieJar().getCookie(HttpUrl.parse(Stripchat.getBaseUri()), "baseAmpl"); - String json = URLDecoder.decode(cookie.value(), UTF_8); + Cookie cookie = getCookieJar().getCookie(HttpUrl.parse((String)Stripchat.getBaseUri()), "baseAmpl"); + String json = URLDecoder.decode(cookie.value(), "utf-8"); JSONObject ampl = new JSONObject(json); + ampl.put("ep", (Object)new JSONObject()); return ampl; - } catch (Exception ex) { + } + catch (Exception ex) { return new JSONObject(); } } @@ -203,41 +210,45 @@ public class StripchatHttpClient extends HttpClient { if (!isTokenValid()) { loadCsrfToken(); } - } catch (Exception e) { - log.debug("Invalid CSRF Token {}: {}", csrfToken, e.getMessage()); + } + catch (Exception e) { + LOG.debug("Invalid CSRF Token {}: {}", (Object)csrfToken, (Object)e.getMessage()); csrfToken = ""; } return csrfToken; } - + public String getJwtToken() { try { if (!isJwtTokenValid()) { loadJwtToken(); } - } catch (Exception e) { - log.debug("Invalid JWT Token {}: {}", jwtToken, e.getMessage()); + } + catch (Exception e) { + LOG.debug("Invalid JWT Token {}: {}", (Object)jwtToken, (Object)e.getMessage()); jwtToken = ""; } return jwtToken; } - + private boolean isJwtTokenValid() { if (StringUtil.isBlank(jwtToken) || jwtTokenExp == null) { return false; } - return jwtTokenExp.isAfter(Instant.now()); + return jwtTokenExp.isAfter(Instant.now().minus(3L, ChronoUnit.HOURS)); } - + private boolean isTokenValid() { if (StringUtil.isBlank(csrfToken) || StringUtil.isBlank(csrfTimestamp) || StringUtil.isBlank(csrfNotifyTimestamp)) { return false; } try { Instant notifyTime = Instant.parse(csrfNotifyTimestamp); - return notifyTime.isAfter(Instant.now()); - } catch (Exception e) { + return notifyTime.isAfter(Instant.now().minus(3L, ChronoUnit.HOURS)); + } + catch (Exception e) { return false; } } } + diff --git a/common/src/main/java/ctbrec/sites/stripchat/StripchatUtil.java b/common/src/main/java/ctbrec/sites/stripchat/StripchatUtil.java new file mode 100644 index 00000000..67d8d8aa --- /dev/null +++ b/common/src/main/java/ctbrec/sites/stripchat/StripchatUtil.java @@ -0,0 +1,58 @@ +package ctbrec.sites.stripchat; + +// import ctbrec.sites.stripchat.Stripchat; +import java.text.MessageFormat; +import java.time.Instant; +import java.util.Random; +import org.json.JSONObject; + +public class StripchatUtil { + private static final Random RNG = new Random(); + private static final String HEX = "0123456789abcdef"; + private static final String ALPHA = "0123456789abcdefghijklmnopqrstuvwxyz"; + + public static String getUniq() { + return StripchatUtil.randomString(16, ALPHA); + } + + public static String randomString(int length, String dict) { + char[] text = new char[length]; + for (int i = 0; i < length; ++i) { + text[i] = dict.charAt(RNG.nextInt(dict.length())); + } + return new String(text); + } + + public static String getTabId() { + return StripchatUtil.randomString(60, HEX); + } + + public static String hexString(int length) { + return StripchatUtil.randomString(length, HEX); + } + + public static String alphaString(int length) { + return StripchatUtil.randomString(length, ALPHA); + } + + public static String getEventId() { + return MessageFormat.format("{0}-{1}-{2}-{3}-{4}", StripchatUtil.hexString(8), StripchatUtil.hexString(4), StripchatUtil.hexString(4), StripchatUtil.hexString(4), StripchatUtil.hexString(12)); + } + + public static JSONObject getEventData() { + JSONObject data = new JSONObject(); + data.put("ek.platformVersion", "10.92.4"); + data.put("ek.tabId", StripchatUtil.getTabId()); + data.put("ek.timestampCreated", Instant.now().getEpochSecond()); + data.put("ek.deviceFlags", "2073600|10001110000001000"); + data.put("ek.httpHost", Stripchat.domain); + data.put("ek.httpPath", "/"); + data.put("ek.isDocumentHidden", 0); + data.put("ek.isTabFocused", 1); + data.put("ek.pageClass", "viewcam"); + data.put("ek.contractVersion", "v0.2.1"); + data.put("ek.eventId", StripchatUtil.getEventId()); + return data; + } +} +