diff --git a/README.md b/README.md index e34ce62..241cb94 100644 --- a/README.md +++ b/README.md @@ -483,6 +483,20 @@ certificatePinningAdd("mydomain.com", ["DCU5TkA8n3L8+QM7dyTjfRlxWibigF+1cxMzRhlJ certificatePinningClear(); ``` +### Disable SSL validation + +You can disable SSL validations + +```typescript +import { disableSSLValidation } from "@klippa/nativescript-http"; + +/** + * Disable SSL validations + * @param disable true/false + */ +disableSSLValidation(true); +``` + ## Roadmap * Cache control * Allowing self signed certificates (WIP in feature/self-signed) diff --git a/src/http.android.ts b/src/http.android.ts index 4a36baf..9aa692d 100644 --- a/src/http.android.ts +++ b/src/http.android.ts @@ -496,6 +496,10 @@ export function clearCookies() { com.klippa.NativeScriptHTTP.Async.Http.ClearCookies(); } +export function disableSSLValidation(disable: boolean) { + com.klippa.NativeScriptHTTP.Async.Http.DisableSSLValidation(disable); +} + export function setUserAgent(userAgent?: string) { customUserAgent = userAgent; } diff --git a/src/http.ios.ts b/src/http.ios.ts index 48d6acd..de6cdd3 100644 --- a/src/http.ios.ts +++ b/src/http.ios.ts @@ -28,6 +28,9 @@ let certificatePinningInstance: TrustKit = null; let certificatePinningConfig: NSDictionary = null; let certificatePinningDomainList: NSDictionary = null; +// Is SSL validation disabled +let isSSLValidationDisabled: boolean = false; + function parseJSON(source: string): any { const src = source.trim(); if (src.lastIndexOf(")") === src.length - 1) { @@ -42,6 +45,15 @@ class NSURLSessionTaskDelegateImpl extends NSObject implements NSURLSessionTaskD public static ObjCProtocols = [NSURLSessionTaskDelegate]; public URLSessionTaskDidReceiveChallengeCompletionHandler(session: NSURLSession, task: NSURLSessionTask, challenge: NSURLAuthenticationChallenge, completionHandler: (p1: NSURLSessionAuthChallengeDisposition, p2: NSURLCredential) => void) { + if (isSSLValidationDisabled) { + const trust = challenge.protectionSpace.serverTrust; + if (trust != null) { + const credential = NSURLCredential.credentialForTrust(trust); + completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential); + return; + } + } + // Default behaviour when we don't want certificate pinning. if (certificatePinningInstance == null) { completionHandler(NSURLSessionAuthChallengeDisposition.PerformDefaultHandling, null); @@ -67,6 +79,15 @@ class NoRedirectNSURLSessionTaskDelegateImpl extends NSObject implements NSURLSe public static ObjCProtocols = [NSURLSessionTaskDelegate]; public URLSessionTaskDidReceiveChallengeCompletionHandler(session: NSURLSession, task: NSURLSessionTask, challenge: NSURLAuthenticationChallenge, completionHandler: (p1: NSURLSessionAuthChallengeDisposition, p2: NSURLCredential) => void) { + if (isSSLValidationDisabled) { + const trust = challenge.protectionSpace.serverTrust; + if (trust != null) { + const credential = NSURLCredential.credentialForTrust(trust); + completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential); + return; + } + } + // Default behaviour when we don't want certificate pinning. if (certificatePinningInstance == null) { completionHandler(NSURLSessionAuthChallengeDisposition.PerformDefaultHandling, null); @@ -461,6 +482,12 @@ export function setImageParseMethod(imageParseMethod: ImageParseMethod) { // Doesn't do anything for iOS. } +export function disableSSLValidation(disable: boolean) { + defaultSession = null; + sessionNotFollowingRedirects = null; + isSSLValidationDisabled = disable; +} + export function setConcurrencyLimits(maxRequests: number, maxRequestsPerHost: number) { sessionConfig.HTTPMaximumConnectionsPerHost = maxRequestsPerHost; } diff --git a/src/index.d.ts b/src/index.d.ts index 1192bc8..f4322ca 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -112,6 +112,12 @@ export declare function setConcurrencyLimits(maxRequests: number, maxRequestsPer */ export declare function clearCookies(): void; +/** + * Disable SSL validation + * @param disable true/false + */ +export declare function disableSSLValidation(disable: boolean): void; + /** * Set a global user agent. * @param userAgent The new user agent. Set to null to use the default again. diff --git a/src/package.json b/src/package.json index 6a02197..e80acd4 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "@klippa/nativescript-http", - "version": "3.0.4", + "version": "3.0.5", "description": "The best way to do HTTP requests in NativeScript, a drop-in replacement for the core HTTP with important improvements and additions like proper connection pooling, form data support and certificate pinning", "main": "http", "typings": "index.d.ts", diff --git a/src/platforms/android/java/com/klippa/NativeScriptHTTP/Async.java b/src/platforms/android/java/com/klippa/NativeScriptHTTP/Async.java index da9e96b..890c195 100644 --- a/src/platforms/android/java/com/klippa/NativeScriptHTTP/Async.java +++ b/src/platforms/android/java/com/klippa/NativeScriptHTTP/Async.java @@ -89,6 +89,7 @@ public static class Http { private static MemoryCookieJar cookieJar; private static CertificatePinner.Builder certificatePinnerBuilder; private static ImageParseMethod imageParseMethod = ImageParseMethod.CONTENTTYPE; + private static boolean disableSslValidation = false; public static void InitClient() { if (cookieJar == null) { @@ -96,12 +97,47 @@ public static void InitClient() { } if (client == null) { - client = new OkHttpClient.Builder() - .writeTimeout(60, TimeUnit.SECONDS) - .readTimeout(60, TimeUnit.SECONDS) - .connectTimeout(60, TimeUnit.SECONDS) - .cookieJar(cookieJar) - .build(); + OkHttpClient.Builder builder = new OkHttpClient.Builder() + .writeTimeout(60, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .connectTimeout(60, TimeUnit.SECONDS) + .cookieJar(cookieJar); + + if (disableSslValidation) { + // Disable ssl validations + try { + javax.net.ssl.TrustManager TRUST_ALL_CERTS = new javax.net.ssl.X509TrustManager() { + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) { + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) { + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[] {}; + } + }; + + javax.net.ssl.SSLContext sslContext = javax.net.ssl.SSLContext.getInstance("SSL"); + sslContext.init(null, new javax.net.ssl.TrustManager[] { TRUST_ALL_CERTS }, new java.security.SecureRandom()); + builder.sslSocketFactory(sslContext.getSocketFactory(), (javax.net.ssl.X509TrustManager) TRUST_ALL_CERTS) + .hostnameVerifier(new javax.net.ssl.HostnameVerifier() { + @Override + public boolean verify(String hostname, javax.net.ssl.SSLSession session) { + return true; + } + }); + } catch (java.security.KeyManagementException e) { + e.printStackTrace(); + } catch (java.security.NoSuchAlgorithmException e) { + e.printStackTrace(); + } + } + + client = builder.build(); } } @@ -188,6 +224,12 @@ public static void ClearCookies() { } } + public static void DisableSSLValidation(boolean disable) { + client = null; + disableSslValidation = disable; + InitClient(); + } + public static void SetImageParseMethod(ImageParseMethod newImageParseMethod) { imageParseMethod = newImageParseMethod; } diff --git a/src/typings/android.d.ts b/src/typings/android.d.ts index 1b83891..8e51616 100644 --- a/src/typings/android.d.ts +++ b/src/typings/android.d.ts @@ -25,6 +25,7 @@ declare module com { public static class: java.lang.Class; public static SetConcurrencyLimits(param0: number, param1: number): void; public static ClearCookies(): void; + public static DisableSSLValidation(param0: boolean): void; public static MakeRequest(param0: com.klippa.NativeScriptHTTP.Async.Http.RequestOptions, param1: com.klippa.NativeScriptHTTP.Async.CompleteCallback, param2: any): void; public constructor(); public static InitClient(): void;