diff --git a/catvod/src/main/java/com/github/catvod/net/OkHttp.java b/catvod/src/main/java/com/github/catvod/net/OkHttp.java index 49cc26c85..12c2f174a 100644 --- a/catvod/src/main/java/com/github/catvod/net/OkHttp.java +++ b/catvod/src/main/java/com/github/catvod/net/OkHttp.java @@ -6,6 +6,7 @@ import android.text.TextUtils; import androidx.collection.ArrayMap; import com.github.catvod.bean.Doh; +import com.github.catvod.net.authenticator.CombineAuthenticator; import com.github.catvod.net.interceptor.RequestInterceptor; import com.github.catvod.net.interceptor.ResponseInterceptor; import com.github.catvod.utils.Path; @@ -187,7 +188,7 @@ public class OkHttp { } private static OkHttpClient.Builder getBuilder() { - OkHttpClient.Builder builder = new OkHttpClient.Builder().cookieJar(OkCookieJar.get()).addInterceptor(requestInterceptor()).addNetworkInterceptor(responseInterceptor()).connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS).readTimeout(TIMEOUT, TimeUnit.MILLISECONDS).writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS).dns(dns()).hostnameVerifier((hostname, session) -> true).sslSocketFactory(getSSLContext().getSocketFactory(), trustAllCertificates()); + OkHttpClient.Builder builder = new OkHttpClient.Builder().authenticator(new CombineAuthenticator()).cookieJar(OkCookieJar.get()).addInterceptor(requestInterceptor()).addNetworkInterceptor(responseInterceptor()).connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS).readTimeout(TIMEOUT, TimeUnit.MILLISECONDS).writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS).dns(dns()).hostnameVerifier((hostname, session) -> true).sslSocketFactory(getSSLContext().getSocketFactory(), trustAllCertificates()); HttpLoggingInterceptor logging = new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY); builder.proxySelector(get().proxy ? selector() : defaultSelector); //builder.addNetworkInterceptor(logging); diff --git a/catvod/src/main/java/com/github/catvod/net/authenticator/CombineAuthenticator.java b/catvod/src/main/java/com/github/catvod/net/authenticator/CombineAuthenticator.java new file mode 100644 index 000000000..72fa977e7 --- /dev/null +++ b/catvod/src/main/java/com/github/catvod/net/authenticator/CombineAuthenticator.java @@ -0,0 +1,89 @@ +package com.github.catvod.net.authenticator; + +import com.github.catvod.utils.Util; +import com.google.common.net.HttpHeaders; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import okhttp3.Authenticator; +import okhttp3.HttpUrl; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.Route; + +public class CombineAuthenticator implements Authenticator { + + private final Map authCache; + + public CombineAuthenticator() { + authCache = new ConcurrentHashMap<>(); + } + + @Override + public Request authenticate(Route route, Response response) { + if (response.code() != 401) return null; + + HttpUrl url = response.request().url(); + String userInfo = url.uri().getUserInfo(); + String host = response.request().url().host(); + String authHeader = response.header(HttpHeaders.WWW_AUTHENTICATE); + + if (authCache.containsKey(host)) { + return response.request().newBuilder().header(HttpHeaders.AUTHORIZATION, authCache.get(host)).build(); + } + + if (userInfo == null) { + return null; + } + + if (authHeader.startsWith("Digest")) { + Map params = parseAuthHeader(authHeader.substring(7)); + String realm = params.get("realm"); + String nonce = params.get("nonce"); + String opaque = params.get("opaque"); + String qop = params.get("qop"); + String uri = url.encodedPath(); + String method = response.request().method(); + String cnonce = Long.toHexString(System.currentTimeMillis()); + String[] parts = userInfo.split(":", 2); + String username = parts[0]; + String password = parts[1]; + String nc = "00000001"; + String digestAuth = getDigestAuth(username, password, realm, nonce, qop, opaque, method, uri, cnonce, nc); + authCache.put(host, digestAuth); + return response.request().newBuilder().header(HttpHeaders.AUTHORIZATION, digestAuth).build(); + } else { + String basicAuth = Util.basic(userInfo); + authCache.put(host, basicAuth); + return response.request().newBuilder().header(HttpHeaders.AUTHORIZATION, basicAuth).build(); + } + } + + private String getDigestAuth(String username, String password, String realm, String nonce, String qop, String opaque, String method, String uri, String cnonce, String nc) { + String ha1 = Util.md5(username + ":" + realm + ":" + password); + String ha2 = Util.md5(method + ":" + uri); + String responseDigest = Util.md5(ha1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + (qop != null ? qop : "") + ":" + ha2); + StringBuilder authValue = new StringBuilder("Digest "); + authValue.append("username=\"").append(username).append("\", "); + if (realm != null) authValue.append("realm=\"").append(realm).append("\", "); + if (nonce != null) authValue.append("nonce=\"").append(nonce).append("\", "); + authValue.append("uri=\"").append(uri).append("\", "); + authValue.append("cnonce=\"").append(cnonce).append("\", "); + authValue.append("nc=").append(nc).append(", "); + if (qop != null) authValue.append("qop=\"").append(qop).append("\", "); + authValue.append("response=\"").append(responseDigest).append("\""); + if (opaque != null) authValue.append(", opaque=\"").append(opaque).append("\""); + return authValue.toString(); + } + + private Map parseAuthHeader(String header) { + Map params = new HashMap<>(); + for (String part : header.split(",\\s*")) { + String[] kv = part.split("=", 2); + if (kv.length == 2) params.put(kv[0].trim(), kv[1].trim().replace("\"", "")); + } + return params; + } +} diff --git a/catvod/src/main/java/com/github/catvod/net/interceptor/RequestInterceptor.java b/catvod/src/main/java/com/github/catvod/net/interceptor/RequestInterceptor.java index 67d8cd7e9..c2b6f4f04 100644 --- a/catvod/src/main/java/com/github/catvod/net/interceptor/RequestInterceptor.java +++ b/catvod/src/main/java/com/github/catvod/net/interceptor/RequestInterceptor.java @@ -4,7 +4,6 @@ import androidx.annotation.NonNull; import com.github.catvod.net.OkCookieJar; import com.github.catvod.utils.Json; -import com.github.catvod.utils.Util; import com.google.common.net.HttpHeaders; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -21,12 +20,10 @@ import okhttp3.Response; public class RequestInterceptor implements Interceptor { - private final ConcurrentHashMap userMap; private final ConcurrentHashMap authMap; private final ConcurrentHashMap headerMap; public RequestInterceptor() { - this.userMap = new ConcurrentHashMap<>(); this.authMap = new ConcurrentHashMap<>(); this.headerMap = new ConcurrentHashMap<>(); } @@ -39,7 +36,6 @@ public class RequestInterceptor implements Interceptor { } public void clear() { - userMap.clear(); authMap.clear(); headerMap.clear(); } @@ -64,11 +60,8 @@ public class RequestInterceptor implements Interceptor { } private void checkAuthUser(HttpUrl url, Request.Builder builder) { - String user = url.uri().getUserInfo(); String auth = url.queryParameter("auth"); - if (user != null) userMap.put(url.host(), user); if (auth != null) authMap.put(url.host(), auth); - if (userMap.containsKey(url.host())) builder.header(HttpHeaders.AUTHORIZATION, Util.basic(userMap.get(url.host()))); if (authMap.containsKey(url.host()) && auth == null) builder.url(url.newBuilder().addQueryParameter("auth", authMap.get(url.host())).build()); } } diff --git a/catvod/src/main/java/com/github/catvod/net/interceptor/ResponseInterceptor.java b/catvod/src/main/java/com/github/catvod/net/interceptor/ResponseInterceptor.java index bcd654ef6..b661caa84 100644 --- a/catvod/src/main/java/com/github/catvod/net/interceptor/ResponseInterceptor.java +++ b/catvod/src/main/java/com/github/catvod/net/interceptor/ResponseInterceptor.java @@ -3,11 +3,9 @@ package com.github.catvod.net.interceptor; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.github.catvod.utils.Util; import com.google.common.net.HttpHeaders; import java.io.IOException; -import java.net.URI; import java.util.concurrent.ConcurrentHashMap; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; @@ -32,19 +30,13 @@ public class ResponseInterceptor implements Interceptor { @Override public Response intercept(@NonNull Chain chain) throws IOException { Request request = chain.request(); - Response response = chain.proceed(checkUser(request)); + Response response = chain.proceed(request); if ("deflate".equals(response.header(HttpHeaders.CONTENT_ENCODING))) return deflate(response); if (response.code() == 302) redirect.put(response.header(HttpHeaders.LOCATION), request.url().toString()); if (response.code() == 406 && redirect.containsKey(request.url().toString())) return redirect(request, response); return response; } - private Request checkUser(Request request) { - URI uri = request.url().uri(); - if (uri.getUserInfo() == null) return request; - return request.newBuilder().header(HttpHeaders.AUTHORIZATION, Util.basic(uri.getUserInfo())).build(); - } - private Response redirect(Request request, Response response) { return new Response.Builder().request(request).protocol(response.protocol()).code(302).message("Found").header(HttpHeaders.LOCATION, redirect.get(request.url().toString())).build(); }