diff --git a/README.md b/README.md index 1aac9d3..eda3bb5 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ Option | Description `certificate: string` | The uri path to your `.cer` certificate file. `allowInvalidCertificates?: boolean` | Default: `false`. This should **always** be `false` if you are using SSL pinning. Set this to `true` if you're using a self-signed certificate. `validatesDomainName?: boolean` | Default: `true`. Determines if the domain name should be validated with your pinned certificate. +`useLegacy?: boolean` | Default: `false`. [IOS only] set to true in order to get the response data (when status >= 300)in the `content` directly instead of `response.body.content`. ## Webpack / bundling Since you're probably shipping a certificate with your app (like [our demo does](https://github.com/EddyVerbruggen/nativescript-https/tree/master/demo/app/assets)), diff --git a/src/https.common.d.ts b/src/https.common.d.ts new file mode 100644 index 0000000..f2f9bac --- /dev/null +++ b/src/https.common.d.ts @@ -0,0 +1,29 @@ +import { Headers } from 'tns-core-modules/http'; +export interface HttpsSSLPinningOptions { + host: string; + certificate: string; + allowInvalidCertificates?: boolean; + validatesDomainName?: boolean; + commonName?: string; + useLegacy?: boolean; +} +export interface HttpsRequestObject { + [key: string]: string | number; +} +export interface HttpsRequestOptions { + url: string; + method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD'; + headers?: Headers; + params?: HttpsRequestObject; + body?: HttpsRequestObject; + allowLargeResponse?: boolean; + timeout?: number; +} +export interface HttpsResponse { + headers?: Headers; + statusCode?: number; + content?: any; + reason?: string; + reject?: boolean; + failure?: any; +} diff --git a/src/https.common.ts b/src/https.common.ts index 99e17cd..f23c0ad 100644 --- a/src/https.common.ts +++ b/src/https.common.ts @@ -6,6 +6,7 @@ export interface HttpsSSLPinningOptions { allowInvalidCertificates?: boolean; validatesDomainName?: boolean; commonName?: string; + useLegacy?: boolean; } export interface HttpsRequestObject { @@ -36,4 +37,5 @@ export interface HttpsResponse { content?: any; reason?: string; reject?: boolean; + failure?: any; } diff --git a/src/https.ios.ts b/src/https.ios.ts index e08f26f..8999a93 100644 --- a/src/https.ios.ts +++ b/src/https.ios.ts @@ -7,6 +7,8 @@ interface Ipolicies { secure?: AFSecurityPolicy; } +let useLegacy: boolean = false; + let policies: Ipolicies = { def: AFSecurityPolicy.defaultPolicy(), secured: false, @@ -23,6 +25,7 @@ export function enableSSLPinning(options: Https.HttpsSSLPinningOptions) { let data = NSData.dataWithContentsOfFile(options.certificate); policies.secure.pinnedCertificates = NSSet.setWithObject(data); } + useLegacy = (isDefined(options.useLegacy)) ? options.useLegacy : false; policies.secured = true; console.log('nativescript-https > Enabled SSL pinning'); } @@ -35,51 +38,41 @@ export function disableSSLPinning() { console.info('nativescript-https > Disabled SSL pinning by default'); function AFSuccess(resolve, task: NSURLSessionDataTask, data?: NSDictionary & NSData & NSArray) { - let content: any; - if (data && data.class) { - if (data.enumerateKeysAndObjectsUsingBlock || (data) instanceof NSArray) { - let serial = NSJSONSerialization.dataWithJSONObjectOptionsError(data, NSJSONWritingOptions.PrettyPrinted); - content = NSString.alloc().initWithDataEncoding(serial, NSUTF8StringEncoding).toString(); - } else if ((data) instanceof NSData) { - content = NSString.alloc().initWithDataEncoding(data, NSASCIIStringEncoding).toString(); - } else { - content = data; - } - - try { - content = JSON.parse(content); - } catch (ignore) { - } - - } else { - content = data; - } - + let content = getData(data); resolve({task, content}); } function AFFailure(resolve, reject, task: NSURLSessionDataTask, error: NSError) { - let data: NSData = error.userInfo.valueForKey(AFNetworkingOperationFailingURLResponseDataErrorKey); - let body = NSString.alloc().initWithDataEncoding(data, NSUTF8StringEncoding).toString(); - - try { - body = JSON.parse(body); - } catch (ignore) { - } - - let content: any = { - body, - description: error.description, - reason: error.localizedDescription, - url: error.userInfo.objectForKey('NSErrorFailingURLKey').description - }; - - if (policies.secured === true) { - content.description = 'nativescript-https > Invalid SSL certificate! ' + content.description; - } + let data: NSDictionary & NSData & NSArray = error.userInfo.valueForKey(AFNetworkingOperationFailingURLResponseDataErrorKey); + let parsedData = getData(data); + if (useLegacy) { + let failure: any = { + body: parsedData, + description: error.description, + reason: error.localizedDescription, + url: error.userInfo.objectForKey('NSErrorFailingURLKey').description + }; + if (policies.secured === true) { + failure.description = 'nativescript-https > Invalid SSL certificate! ' + error.description; + } + let reason = error.localizedDescription; + let content = parsedData; + resolve({task: task, content: content, reason: reason, failure: failure}); + } else { + let content: any = { + body: parsedData, + description: error.description, + reason: error.localizedDescription, + url: error.userInfo.objectForKey('NSErrorFailingURLKey').description + }; + + if (policies.secured === true) { + content.description = 'nativescript-https > Invalid SSL certificate! ' + content.description; + } - let reason = error.localizedDescription; - resolve({task, content, reason}); + let reason = error.localizedDescription; + resolve({task, content, reason}); + } } export function request(opts: Https.HttpsRequestOptions): Promise { @@ -174,3 +167,25 @@ export function request(opts: Https.HttpsRequestOptions): Promisedata) instanceof NSArray) { + let serial = NSJSONSerialization.dataWithJSONObjectOptionsError(data, NSJSONWritingOptions.PrettyPrinted); + content = NSString.alloc().initWithDataEncoding(serial, NSUTF8StringEncoding).toString(); + } else if ((data) instanceof NSData) { + content = NSString.alloc().initWithDataEncoding(data, NSASCIIStringEncoding).toString(); + } else { + content = data; + } + + try { + content = JSON.parse(content); + } catch (e) { + } + } else { + content = data; + } + return content; +} \ No newline at end of file