Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down
29 changes: 29 additions & 0 deletions src/https.common.d.ts
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 2 additions & 0 deletions src/https.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface HttpsSSLPinningOptions {
allowInvalidCertificates?: boolean;
validatesDomainName?: boolean;
commonName?: string;
useLegacy?: boolean;
}

export interface HttpsRequestObject {
Expand Down Expand Up @@ -36,4 +37,5 @@ export interface HttpsResponse {
content?: any;
reason?: string;
reject?: boolean;
failure?: any;
}
95 changes: 55 additions & 40 deletions src/https.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ interface Ipolicies {
secure?: AFSecurityPolicy;
}

let useLegacy: boolean = false;

let policies: Ipolicies = {
def: AFSecurityPolicy.defaultPolicy(),
secured: false,
Expand All @@ -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');
}
Expand All @@ -35,51 +38,41 @@ export function disableSSLPinning() {
console.info('nativescript-https > Disabled SSL pinning by default');

function AFSuccess(resolve, task: NSURLSessionDataTask, data?: NSDictionary<string, any> & NSData & NSArray<any>) {
let content: any;
if (data && data.class) {
if (data.enumerateKeysAndObjectsUsingBlock || (<any>data) instanceof NSArray) {
let serial = NSJSONSerialization.dataWithJSONObjectOptionsError(data, NSJSONWritingOptions.PrettyPrinted);
content = NSString.alloc().initWithDataEncoding(serial, NSUTF8StringEncoding).toString();
} else if ((<any>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<string, any> & NSData & NSArray<any> = 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<Https.HttpsResponse> {
Expand Down Expand Up @@ -174,3 +167,25 @@ export function request(opts: Https.HttpsRequestOptions): Promise<Https.HttpsRes
return Promise.resolve(sendi);
});
}

function getData(data) {
let content: any;
if (data && data.class) {
if (data.enumerateKeysAndObjectsUsingBlock || (<any>data) instanceof NSArray) {
let serial = NSJSONSerialization.dataWithJSONObjectOptionsError(data, NSJSONWritingOptions.PrettyPrinted);
content = NSString.alloc().initWithDataEncoding(serial, NSUTF8StringEncoding).toString();
} else if ((<any>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;
}