From 4e524396d2993c0c6568b8a11c9835bd8108cd23 Mon Sep 17 00:00:00 2001 From: reusedname <155286845+reusedname@users.noreply.github.com> Date: Mon, 24 Feb 2025 19:06:56 +0500 Subject: [PATCH] fix Stripchat login --- .../sites/stripchat/StripchatHttpClient.java | 115 +++++++++++++----- 1 file changed, 85 insertions(+), 30 deletions(-) diff --git a/common/src/main/java/ctbrec/sites/stripchat/StripchatHttpClient.java b/common/src/main/java/ctbrec/sites/stripchat/StripchatHttpClient.java index 8c5b1c6a..768c1410 100644 --- a/common/src/main/java/ctbrec/sites/stripchat/StripchatHttpClient.java +++ b/common/src/main/java/ctbrec/sites/stripchat/StripchatHttpClient.java @@ -10,6 +10,9 @@ import okhttp3.*; import org.json.JSONException; import org.json.JSONObject; +import java.time.Instant; +import java.util.Base64; +import java.nio.charset.StandardCharsets; import java.io.IOException; import java.net.URLDecoder; @@ -21,9 +24,7 @@ public class StripchatHttpClient extends HttpClient { public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - private long userId; - - @Getter + private long userId = 0; private String csrfToken; @Getter private String csrfTimestamp; @@ -31,6 +32,7 @@ public class StripchatHttpClient extends HttpClient { private String csrfNotifyTimestamp; @Getter private String jwtToken; + private Instant jwtTokenExp; public StripchatHttpClient(Config config) { super("stripchat", config); @@ -38,26 +40,21 @@ public class StripchatHttpClient extends HttpClient { @Override public boolean login() throws IOException { - if (loggedIn) { - if (csrfToken == null) { - loadCsrfToken(); - } + // refresh token if needed + getCsrfToken(); + + // already logged in + if (loggedIn && isJwtTokenValid()) { return true; } - + // persisted cookies might let us log in if (checkLoginSuccess()) { loggedIn = true; log.debug("Logged in with cookies"); - if (csrfToken == null) { - loadCsrfToken(); - } return true; } - if (csrfToken == null) { - loadCsrfToken(); - } String url = Stripchat.getBaseUri() + "/api/front/auth/login"; JSONObject requestParams = new JSONObject(); @@ -95,7 +92,7 @@ public class StripchatHttpClient extends HttpClient { } private void loadCsrfToken() throws IOException { - String url = Stripchat.getBaseUri() + "/api/front/v2/config/data?requestPath=%2F&timezoneOffset=0"; + 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) @@ -107,10 +104,11 @@ public class StripchatHttpClient extends HttpClient { try (Response response = execute(request)) { if (response.isSuccessful()) { JSONObject resp = new JSONObject(response.body().string()); - JSONObject data = resp.getJSONObject("data"); + 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 { throw new HttpException(response.code(), response.message()); } @@ -118,7 +116,7 @@ public class StripchatHttpClient extends HttpClient { } private void loadJwtToken() throws IOException { - String url = Stripchat.getBaseUri() + "/api/front/v2/config?requestPath=%2F&timezoneOffset=0"; + String url = Stripchat.getBaseUri() + "/api/front/v3/config/dynamic"; Request request = new Request.Builder() .url(url) .header(ACCEPT, MIMETYPE_APPLICATION_JSON) @@ -130,8 +128,17 @@ public class StripchatHttpClient extends HttpClient { try (Response response = execute(request)) { if (response.isSuccessful()) { JSONObject resp = new JSONObject(response.body().string()); - JSONObject config = resp.getJSONObject("config"); - jwtToken = config.optString("jwtToken"); + 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 token JWT: {} [{}]", jwtToken, jwtTokenExp); } else { throw new HttpException(response.code(), response.message()); } @@ -139,19 +146,15 @@ public class StripchatHttpClient extends HttpClient { } /** - * check, if the login worked + * check, if the login worked + * @throws IOException */ public boolean checkLoginSuccess() throws IOException { - try { - loadJwtToken(); - } catch (Exception e) { - log.info("Login check returned unsuccessful: {}", e.getLocalizedMessage()); - jwtToken = ""; - return false; - } - return StringUtil.isNotBlank(jwtToken); + 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; @@ -176,7 +179,7 @@ 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); @@ -186,4 +189,56 @@ public class StripchatHttpClient extends HttpClient { return new JSONObject(); } } + + public String getCsrfNotifyTimestamp() { + return csrfNotifyTimestamp; + } + + public String getCsrfTimestamp() { + return csrfTimestamp; + } + + public String getCsrfToken() { + try { + if (!isTokenValid()) { + loadCsrfToken(); + } + } catch (Exception e) { + log.debug("Invalid CSRF Token {}: {}", csrfToken, e.getMessage()); + csrfToken = ""; + } + return csrfToken; + } + + public String getJwtToken() { + try { + if (!isJwtTokenValid()) { + loadJwtToken(); + } + } catch (Exception e) { + log.debug("Invalid JWT Token {}: {}", jwtToken, e.getMessage()); + jwtToken = ""; + } + return jwtToken; + } + + private boolean isJwtTokenValid() { + if (StringUtil.isBlank(jwtToken) || jwtTokenExp == null) { + return false; + } + return jwtTokenExp.isAfter(Instant.now()); + } + + 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 false; + } + } + }