SWIFT - Https call to private restfull api is failing - ios

I need to convert my SWIFT code to fit HTTPS requests on private API.
I just need to understand how to make the request in Swift, at the moment changed the URL from http://...:_port/... to https://...:_port/... but I am getting those errors:
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9814)
nw_coretls_callback_handshake_message_block_invoke_3 tls_handshake_continue: [-9814]
nw_coretls_callback_handshake_message_block_invoke_3 tls_handshake_continue: [-9814]
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9814)
I also update my info.plist to this, but still getting errors
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>domain.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>
</plist>
And this is the code
let task = session.dataTask(with: requestType as URLRequest) { (data, response, error) in
guard let _: Data = data, let _: URLResponse = response, error == nil else {
return
}
self.list = try! JSONDecoder().decode(_myObj.self, from:data!)
}
task.resume()

Related

TIC SSL Trust Error while trying to read a txt file

I'm having this problem with reading from a txt file from a website without a certificate even though I have allowed it in Info.plist.
My Swift code looks like this:
let url = URL(string: "http://newskit.matsworld.io/domaci/text.txt")!
let task = URLSession.shared.downloadTask(with: url) { localURL, urlResponse, error in
if let localURL = localURL {
if let string = try? String(contentsOf: localURL) {
print(string)
}
}
}
task.resume()
And the Info.plist looks like this:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>http://newskit.matsworld.io</key>
<dict>
<key>ExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>IncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
I'm stuck with this and can't figure it out. Thanks for help!
The domain key is supposed to be just the domain without the scheme (http) and without subdomains if IncludesSubdomains is specified
<key>matsworld.io</key>

NSURLSession - DownloadTask doesn't work with some URL [duplicate]

This question already has answers here:
NSURLSession/NSURLConnection HTTP load failed on iOS 9
(13 answers)
Closed 6 years ago.
Here the code:
let url = NSURL(string: "http://a337.phobos.apple.com/us/r30/Music/d5/a8/6b/mzi.msfqeogi.aac.p.m4a")
let downloadTask = self.downloadSession.downloadTaskWithURL(url!)
downloadTask.resume()
-> OK
Replace the URL with:
http://s1mp3.r41s223.vcdn.vn/d3f549abeeef07b15efe/2937387453157939420?key=c2WuQChtsmR9yfdz9I-jnw&expires=1480695588&filename=Only%20Love%20-%20Trademark.mp3
-> it doesn't work; nothing happens
By default starting in iOS 9 all connections must be https. If the website for the second URL doesn't support https:// then the download would fail.
I suggest checking the error code you get back from the Download
If you want to use url with HTTP connection, then in your info.plist file add the following
App Transport Security Setting and in that add subsection Allow Arbitrary Loads and set the value to YES.
Please add in Plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>akamaihd.net</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>facebook.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>fbcdn.net</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>graph.facebook.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
</plist>
Then using Alamofire 4.0 Swift 3.0
Using below method, you can download any thing, ex. PDF
// Mark:- Download File
func DownloadFile(strFileUrl : String, strFileName : String, success:#escaping (_ strResultURL: String) -> Void , failure:#escaping (_ responseObject:AnyObject) -> Void) {
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fileURL = documentsURL.appendingPathComponent("\(strFileName)")
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
Alamofire.download(strFileUrl, to: destination).response { response in
if SVProgressHUD.isVisible() {
SVProgressHUD.dismiss()
}
if response.error == nil {
success("\(response.destinationURL!)")
}
else {
failure(response.error as AnyObject)
}
}.downloadProgress { (progress) in
print("Download Progress: \(progress.fractionCompleted)")
SVProgressHUD.showProgress(Float(progress.fractionCompleted), status: AppAlertMsg.KDownloadingPDFs)
}
}

Apple Watch Device crashing with SandboxViolation deny(1) network-outbound

Im having an issue on the Apple Watch when making network calls.
It works fine on the simulator but when deployed to the device I see this in the device logs:
MyAppleWatch kernel(Sandbox)[0] : SandboxViolation: MyWatchApp(203) deny(1) network-outbound /private/var/run/mDNSResponder
The code for making the call is done using refit and works on the simulator so I would imagine it is not the cause but I will post it if necessary.
I have set these values in the Info.plist of the WatchExtensionApp (and not set them in the WatchApp as these keys )
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>my.domain.com</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<true/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
I set the WatchApp and WatchExtensionApp to:
Just at a bit of loss as to what to try next. Any help would be greatly appreciated.
Ok I got it working, Firstly I changed my Info.plist to:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>my.domain.com</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
I had to change all my network calls to us NSUrlSession rather than using Refit + HttpClient. So I assume there is something in the HttpClient that watchOS doesn't like or watchos only works with NSUrlSession. Anyway here is a sample of one of my calls:
public async Task<HttpResponse> MakeCall(NSMutableUrlRequest request)
{
var result = new HttpResponse();
var config = NSUrlSessionConfiguration.DefaultSessionConfiguration;
var session = NSUrlSession.FromConfiguration(config);
var resultUser = await session.CreateDataTaskAsync(request);
var response = resultUser.Response as NSHttpUrlResponse;
if (response != null)
{
result.StatusCode = (int)response.StatusCode;
result.Content = NSString.FromData(resultUser.Data, NSStringEncoding.UTF8).ToString();
}
return result;
}
public async Task<HttpResponse> GetStuffWithParameter(string parameter, string authorization)
{
var url = new NSUrl($"https://www.domain.com/api/stuff/{parameter}");
var header = new NSMutableDictionary();
header.SetValueForKey(new NSString(authorization), new NSString("Authorization"));
header.SetValueForKey(new NSString("application/json"), new NSString("Content-Type"));
var request = new NSMutableUrlRequest(url)
{
Headers = header,
HttpMethod = "GET"
};
return await MakeCall(request);
}
public class HttpResponse
{
public int StatusCode { get; set; }
public object Content { get; set; }
}
Hope this helps.

Error consuming REST API using swift on iOS

I'm new on iOS development, I was following this tutorial: https://grokswift.com/simple-rest-with-swift/ and I don't know why the following code always return "the placeholder" and I can't see errors on the console's output:
import Foundation
class Resolver{
func doSomething() -> String{
var result = "the placeholder"
print("inside doSomething")
let postEndpoint: String = "http://jsonplaceholder.typicode.com/posts/1"
guard let url = NSURL(string: postEndpoint) else {
print("Error: cannot create URL")
return "error here"
}
let urlRequest = NSURLRequest(URL: url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
print("another thing")
let task = session.dataTaskWithRequest(urlRequest, completionHandler: {
(data, response, error) in
guard let responseData = data else {
print("Error: did not receive data")
return
//return "error here"
}
print("hereeeeeee ############")
guard error == nil else {
print("error calling GET on /posts/1")
print(error)
return
//return "error here"
}
// parse the result as JSON, since that's what the API provides
let post: NSDictionary
do {
post = try NSJSONSerialization.JSONObjectWithData(responseData,
options: []) as! NSDictionary
} catch {
print("error trying to convert data to JSON")
return
//return "error here"
}
// now we have the post, let's just print it to prove we can access it
print("The post is: " + post.description)
result = post.description
// the post object is a dictionary
// so we just access the title using the "title" key
// so check for a title and print it if we have one
if let postTitle = post["title"] as? String {
print("The title is: " + postTitle)
}
})
task.resume()
return result
}
}
this is my info.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string></string>
<key>CFBundleExecutable</key>
<string></string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>LSApplicationCategoryType</key>
<string></string>
<key>CFBundleName</key>
<string></string>
<key>CFBundleDisplayName</key>
<string></string>
<key>CFBundleVersion</key>
<string></string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>httpbin.org</key>
<dict>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
<key>jsonplaceholder.typicode.com </key>
<dict>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>CFBundleShortVersionString</key>
<string></string>
<key>CFBundleGetInfoString</key>
<string></string>
</dict>
</plist>
When I run the test I see this output:
Test Suite 'RestTest' started at 2016-03-03 15:38:49.364
Test Case '-[FoodTrackerTests.RestTest testResolver]' started.
inside doSomething
another thing
// I want to see the result: the placeholder
Test Case '-[FoodTrackerTests.RestTest testResolver]' passed (0.061 seconds).
Test Suite 'RestTest' passed at 2016-03-03 15:38:49.425.
Executed 1 test, with 0 failures (0 unexpected) in 0.061 (0.062) seconds
Test Suite 'Selected tests' passed at 2016-03-03 15:38:49.426.
Executed 1 test, with 0 failures (0 unexpected) in 0.061 (0.063) seconds
Why the result variable doesn't contains the post.description value?
As suggested in the comments, it looks like tests are completing before the HTTP call is returned (because the HTTP request is asynchronous) and thus you aren't seeing the results of the API call before the test run ends.
Have a look at XCAsyncTestCase and set up your tests to wait for the async callback instead.
The doSomething() method returns "the placeholder" value before the asynchronous call is finished. That's why you see it.

Geting NSURLConnection error while calling HTTPS Soap service

I am trying to get data from Soap request but getting my app crashed with this error:
2016-02-08 11:12:11.524 Example[567:128898] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9843)
Response: nil
fatal error: unexpectedly found nil while unwrapping an Optional value
I have enabled Security settings in plist and calling other services successfully.
Note: The service is on HTTPS, am i getting this error because of this? is this required any certificate?
i am calling soap service for the first time, please also guide me on how to add email parameter in service: (https://[IP]:9897/JLIPolicyinfo.asmx?op=GetEmail_Poldetail)
here is my code that i get from here: (IOS Swift Call Web Service using SOAP)
let is_SoapMessage: String = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:cgs=\"http://www.cgsapi.com/\"><soapenv:Header/><soapenv:Body><cgs:GetSystemStatus/></soapenv:Body></soapenv:Envelope>"
let is_URL: String = "https://58.27.241.203:9897/JLIPolicyinfo.asmx"
let lobj_Request = NSMutableURLRequest(URL: NSURL(string: is_URL)!)
let session = NSURLSession.sharedSession()
let err: NSError?
lobj_Request.HTTPMethod = "POST"
lobj_Request.HTTPBody = is_SoapMessage.dataUsingEncoding(NSUTF8StringEncoding)
lobj_Request.addValue("58.27.241.203", forHTTPHeaderField: "Host")
lobj_Request.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
lobj_Request.addValue(String((is_SoapMessage.characters.count)), forHTTPHeaderField: "Content-Length")
//lobj_Request.addValue("223", forHTTPHeaderField: "Content-Length")
lobj_Request.addValue("http://tempuri.org/GetEmail_Poldetail", forHTTPHeaderField: "SOAPAction")
let task = session.dataTaskWithRequest(lobj_Request, completionHandler: {data, response, error -> Void in
print("Response: \(response)")
let strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Body: \(strData)")
if error != nil
{
print("Error: " + error!.description)
}
})
task.resume()
Here is my plist addition:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>https://58.27.241.203:9897/JLIPolicyinfo.asmx</key>
<dict>
<key>NSIncludesSubdomains</key>
<false/>
<key>NSExceptionAllowInsecureHTTPSLoads</key>
<false/>
<key>NSExceptionRequiresForwardSecrecy</key>
<true/>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
<key>NSThirdPartyExceptionAllowInsecureHTTPSLoads</key>
<false/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<true/>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
<key>NSRequiresCertificateTransparency</key>
<false/>
</dict>
</dict>
</dict>
You might have a self signed certificate that can be also a problem .
Solution:-
It will work if you renew your server's ssl certificate to use SHA2 and enabling TLS v1.2.
Possibly a solution:-
You have to add this in your info.plist file, so that it can allow non-secure connection:-
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Or even you can add like this:-
Edit:-
Add this in your info.plist for specific exception.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>testdomain.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<false/>
<key>NSExceptionAllowInsecureHTTPSLoads</key>
<false/>
<key>NSExceptionRequiresForwardSecrecy</key>
<true/>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
<key>NSThirdPartyExceptionAllowInsecureHTTPSLoads</key>
<false/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<true/>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
<key>NSRequiresCertificateTransparency</key>
<false/>
</dict>
</dict>
</dict>

Resources