Alamofire cert pinning doesn't blocking requests - ios

I've some trouble about SSL Pinning in Alamofire. I've examine all the document that I can found but I couldn't manage to handle it. I might get it wrong.
Currently, I am working on an example
https://github.com/antekarin/ios-ssl-pinning
I converted it to swift 3 and updated the pods to the latest version of Alamofire.
To make it clear; the project is use "github.com.cer" certificate, and because I define domain (like below) I expect to get success when I go to "https://github.com" and to get failure when I enter (in example) "https://twitter.com". But in every condition my request return some value and does not block other requests.
self.serverTrustPolicies = [
"github.com": self.serverTrustPolicy!
]
Code:
let githubCert = "github.com"
let corruptedCert = "corrupted"
var urlSession: Foundation.URLSession!
var serverTrustPolicy: ServerTrustPolicy!
var serverTrustPolicies: [String: ServerTrustPolicy]!
var afManager: SessionManager!
var isSimulatingCertificateCorruption = false
override func viewDidLoad() {
super.viewDidLoad()
self.configureAlamoFireSSLPinning()
self.configureURLSession()
self.activityIndicator.hidesWhenStopped = true
}
// MARK: SSL Config
func configureAlamoFireSSLPinning() {
let pathToCert = Bundle.main.path(forResource: githubCert, ofType: "cer")
let localCertificate:NSData = NSData(contentsOfFile: pathToCert!)!
self.serverTrustPolicy = ServerTrustPolicy.pinCertificates(
certificates: [SecCertificateCreateWithData(nil, localCertificate)!],
validateCertificateChain: true,
validateHost: true
)
self.serverTrustPolicies = [
"github.com": self.serverTrustPolicy!
]
self.afManager = SessionManager(
configuration: URLSessionConfiguration.default,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: self.serverTrustPolicies)
)
}
// MARK: Button actions
#IBAction func alamoFireRequestHandler(_ sender: UIButton) {
self.activityIndicator.startAnimating()
if let urlText = self.urlTextField.text {
self.afManager.request(urlText).responseString { response in
guard let data = response.data, response.error == nil else {
self.responseTextView.text = response.error.debugDescription
self.responseTextView.textColor = UIColor.red
return
}
self.responseTextView.text = String(data: data, encoding: String.Encoding.utf8)!
self.responseTextView.textColor = UIColor.black
}
}
}

Related

Send Text and Link to Snapchat from my Swift app without the SDK

I am integrating sharing options from my app to Snapchat.
I have a dynamic URL obtained in an object and clicking the Snapchat's share button directly opens the app if Snapchat is there on the device and show the text with the link. I am using the below code to share which gives an error on Snapchat. Below is my Code.
func shareTextOnSnapchat(obj:VideoData) {
let shaUrl = URL(string: obj.share_url ?? "")
if let myURL:URL = shaUrl{
let promoText = "Check out this great new video from \(obj.name ?? ""), I found on talent app"
let shareString = "snapchat://text=\(promoText)&url=\(myURL)"
let escapedShareString = shareString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
let url = URL(string: escapedShareString)
UIApplication.shared.openURL(url!)
}
}
I have used this to post video to snapchat. You have option to either post text or a video.
Pod used
pod 'SnapSDK', :subspecs => ['SCSDKCreativeKit']
import SCSDKCreativeKit
var scInstalled = false
override func viewDidLoad() {
super.viewDidLoad()
scInstalled = schemeAvailable(scheme: "snapchat://")
}
func ShowSnapchat(){
if scInstalled {
//shareTextOnSnapchat(obj:videoObj ?? VideoData())
shareFileOnSnapchat(obj:videoObj ?? VideoData())
}else{
downloadSharingAppAlert(appName:"Snapchat")
}
}
func shareTextOnSnapchat(obj:VideoData) {
let shaUrl = URL(string: obj.share_url ?? "")
if let myURL:URL = shaUrl{
let originalString = "\(myURL)"
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters:CharacterSet.urlQueryAllowed)
//let url = URL(string: "snapchat://snap?text=\(escapedString!)")
let url = URL(string: "https://www.snapchat.com/send?text=\(escapedString!)")
if UIApplication.shared.canOpenURL(url! as URL)
{
UIApplication.shared.open(url! as URL, options: [:], completionHandler: nil)
}
}
}
func shareFileOnSnapchat(obj:VideoData){
//// SHARE VIDEO
LoadingOverlay.shared.showLoaderView(view: self.view)
let shaUrl = URL(string: obj.output_vid ?? "")
if let myURL:URL = shaUrl{
let snapVideo = SCSDKSnapVideo(videoUrl: myURL)
let snapContent = SCSDKVideoSnapContent(snapVideo: snapVideo)
// Send it over to Snapchat
snapAPI.startSending(snapContent) { (error) in
if let error = error {
print(error.localizedDescription)
LoadingOverlay.shared.hideLoaderView()
MyCustomAlert.sharedInstance.ShowAlert(vc: self, myTitle: "", myMessage: StringClass.sharedInstance.lcStr_oopsSomethingWentwrong)
} else {
// success
print("Posted to snapchat")
LoadingOverlay.shared.hideLoaderView()
MyCustomAlert.sharedInstance.ShowAlert(vc: self, myTitle: "", myMessage: StringClass.sharedInstance.lcStr_postedToSnapchat)
}
}
}
}
}
func downloadSharingAppAlert(appName:String){
var appStoreURL = "https://apps.apple.com/in/app/snapchat/id447188370"
//Open Appstore for Download
}

TURN server not added in libjingle_peerconnection library

Iam using libjingle_peerconnection library for webrtc connection,
this is the init of rtc connection, i works for the same network,
not for other networks
what i need to do for turn server to work???
func initalizeWebRTC() -> Void {
RTCPeerConnectionFactory.initializeSSL()
self.webRtcClient = RTCPeerConnectionFactory.init()
let stunServer = self.defaultStunServer()
let turnServer = self.getTurn()
let defaultConstraint = self.createDefaultConstraint()
let array = [turnServer, stunServer]
print(array)
self.peerConnection = self.webRtcClient?.peerConnection(withICEServers: array, constraints: defaultConstraint, delegate: self)
print(peerConnection)
self.localVideoView.delegate = self
self.remoteVideoView.delegate = self
// webrtc initalized local rendering of video on
self.addLocalMediaStrem()
}
func defaultStunServer() -> RTCICEServer {
let url = URL.init(string: "stun:stun.l.google.com:19302");
let iceServer = RTCICEServer.init(uri: url, username: "", password: "")
return iceServer!
}
func getTurn() -> RTCICEServer {
let url = URL.init(string: "turn:xxx.xxx.xx.xxx:xxxx");
let iceServer = RTCICEServer.init(uri: url, username: "xxxx", password: "xxxxxxxxxxxx")
return iceServer!
}

WKWebView setting Cookie not possible (iOS 11+)

I am desperately trying to add a custom cookie to a WKWebView instance (without using Javascript or similar workarounds).
From iOS 11 and upwards, Apple provides an API to do this: The WKWebViews WKWebsiteDataStore has a property httpCookieStore.
Here is my (example) code:
import UIKit
import WebKit
class ViewController: UIViewController {
var webView: WKWebView!
override func viewDidLoad() {
webView = WKWebView()
view.addSubview(webView)
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let cookie = HTTPCookie(properties: [
HTTPCookiePropertyKey.domain : "google.com",
HTTPCookiePropertyKey.path : "/",
HTTPCookiePropertyKey.secure : true,
HTTPCookiePropertyKey.name : "someCookieKey",
HTTPCookiePropertyKey.value : "someCookieValue"])!
let cookieStore = webView.configuration.websiteDataStore.httpCookieStore
cookieStore.setCookie(cookie) {
DispatchQueue.main.async {
self.webView.load(URLRequest(url: URL(string: "https://google.com")!))
}
}
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
webView.frame = view.bounds
}
}
After this, if I use webView.configuration.websiteDataStore.httpCookieStore.getAllCookies(completionHandler:) I see that my cookie is in the list of cookies.
However, when inspecting the webview using Safari's developer tools (using a iOS Simulator of course) the cookie does not show up.
I also tried to inspect the traffic using a HTTP proxy (Charles in my case) to see if the cookie in included in my HTTP requests. It is not.
What am I doing wrong here? How can I add a cookie to WKWebView (on iOS versions 11 and up)?
A bit late but I want to share a solution that worked for me, I hope it helps someone facing the same issue on iOS 12 as well.
Here is the simplified workflow I used:
Instantiate a WKWebsiteDataStore object
Set the custom cookie to its httpCookieStore
Wait for the cookie to be set
Instantiate the WKWebView
Load the request
To do that I have created an extension of WKWebViewConfiguration:
extension WKWebViewConfiguration {
static func includeCookie(cookie:HTTPCookie, preferences:WKPreferences, completion: #escaping (WKWebViewConfiguration?) -> Void) {
let config = WKWebViewConfiguration()
config.preferences = preferences
let dataStore = WKWebsiteDataStore.nonPersistent()
DispatchQueue.main.async {
let waitGroup = DispatchGroup()
waitGroup.enter()
dataStore.httpCookieStore.setCookie(cookie) {
waitGroup.leave()
}
waitGroup.notify(queue: DispatchQueue.main) {
config.websiteDataStore = dataStore
completion(config)
}
}
}
And for my example I have used it as follows:
override func viewDidLoad() {
self.AddWebView()
}
private func addWebView(){
let preferences = WKPreferences()
preferences.javaScriptEnabled = true
preferences.javaScriptCanOpenWindowsAutomatically = true
let cookie = HTTPCookie(properties: [
.domain: COOKIE_DOMAIN,
.path: "/",
.name: COOKIE_NAME,
.value: myCookieValue,
.secure: "TRUE",
.expires: NSDate(timeIntervalSinceNow: 3600)
])
//Makes sure the cookie is set before instantiating the webview and initiating the request
if let myCookie = cookie {
WKWebViewConfiguration.includeCookie(cookie: myCookie, preferences: preferences, completion: {
[weak self] config in
if let `self` = self {
if let configuration = config {
self.webView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width , height: self.view.frame.height), configuration: configuration)
self.view.addSubview(self.webView)
self.webView.load(self.customRequest)
}
}
}
}
Any request to google.com redirects to www.google.com.
You would need to add www. to the domain field of the cookie. If the domain or the path doesn't match the request, the cookie won't be sent.
You can add the cookies explicitly.
let url = URL(string: "https://www.google.com")!
var request = URLRequest(url: url)
if let cookies = HTTPCookieStorage.shared.cookies(for: url) {
request.allHTTPHeaderFields = HTTPCookie.requestHeaderFields(with: cookies)
}
self.webView.load(request)
For iOS 11+ you really don't need to worry about cookies part it is very simple. Create your cookie like this. Don't make it secure true
let newcookie = HTTPCookie(properties: [
.domain: "domain",
.path: "/",
.name: "name",
.value: "vale",
.secure: "FALSE",
.expires: NSDate(timeIntervalSinceNow: 31556926)
])!
self.webview.configuration.websiteDataStore.httpCookieStore.setCookie(newcookie, completionHandler: {
// completion load your url request here. Better to add cookie in Request as well. like this way
request.addCookies()
//enable cookie through request
request.httpShouldHandleCookies = true
//load request in your webview.
})
Request extention add after cookie value ";"
extension URLRequest {
internal mutating func addCookies() {
var cookiesStr: String = ""
let mutableRequest = ((self as NSURLRequest).mutableCopy() as? NSMutableURLRequest)!
cookiesStr += cookie.name + "=" + cookie.value + ";"
mutableRequest.setValue(cookiesStr, forHTTPHeaderField: "Cookie")
self = mutableRequest as URLRequest
}
}
Also i can see your are not setting WKWebViewConfiguration of wkwebview. Set configuration of your wkwebview. Also implement WKHTTPCookieStoreObserver and implement function.
func cookiesDidChange(in cookieStore: WKHTTPCookieStore) {
// Must implement otherwise wkwebview cookie not sync properly
self.httpCookieStore.getAllCookies { (cookies) in
cookies.forEach({ (cookie) in
})
}
}
Hope so this will work.

UIWebView not loading a new url

Everytime I try to load another URL on a UIWebView i get the same error:
SendDelegateMessage(NSInvocation *): delegate (webView:decidePolicyForNavigationAction:request:frame:decisionListener:) failed to return after waiting 10 seconds.
My code about the webView is like:
#IBAction func changeUrl(sender: UIButton) {
if LEDON {
let urlStr = NSString(format: "%#/?Led=0", self.url)
let req = URLRequest(url: URL(string: urlStr as String)!)
webView.loadRequest(req)
while(webView.isLoading) {
sender.isEnabled = false
}
sender.isEnabled = true
LEDON = false;
} else {
let urlStr = NSString(format: "%#/?Led=1", self.url)
let req = URLRequest(url: URL(string: urlStr as String)!)
webView.loadRequest(req)
while(webView.isLoading) {
sender.isEnabled = false
}
sender.isEnabled = true
LEDON = true;
}
}
If I press the UIButton the first time the code works perfectly, but when I tap it again I get that error.
Where am I doing wrong?
"url" variable in the code is a global var and I already check that is correct.
Problem in
while(webView.isLoading) {
sender.isEnabled = false
}
You have frozen main thread and webView:decidePolicyForNavigationAction:request:frame:decisionListener: can't be invoke.
Try to use this:
func viewDidLoad()
{
...
webView.delegate = self;//UIWebView
//webView. navigationDelegate = self;//WKWebView
}
#IBAction func changeUrl(sender: UIButton) {
if LEDON {
let urlStr = NSString(format: "%#/?Led=0", self.url)
let req = URLRequest(url: URL(string: urlStr as String)!)
webView.loadRequest(req)
sender.isEnabled = false
LEDON = false;
} else {
let urlStr = NSString(format: "%#/?Led=1", self.url)
let req = URLRequest(url: URL(string: urlStr as String)!)
webView.loadRequest(req)
sender.isEnabled = false
LEDON = true;
}
}
For UIWebView you need to use
func webViewDidFinishLoad(UIWebView)
{
yourButton.isEnabled = true
}
For WKWebView
func webView(_ webView: WKWebView,
didFinish navigation: WKNavigation!)
{
yourButton.isEnabled = true
}
======================================
If you want use while loop try to change it for this:
while(webView.isLoading) {
sender.isEnabled = false
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.5))
}
You need to allow http and https on your app :
In your info.plist :
In Info.plist file add a dictionary with key 'NSAppTransportSecurity'
Add another element inside dictionary with key 'Allow Arbitrary Loads'

How do i exactly export a csv file from iOS written in swift?

I am trying to export an cvs file.
With the following code i manage to get the file
let fileName = "sample.csv"//"sample.txt"
#IBAction func createFile(sender: AnyObject) {
let path = tmpDir.stringByAppendingPathComponent(fileName)
let contentsOfFile = "No,President Name,Wikipedia URL,Took office,Left office,Party,Home State\n1,George Washington,http://en.wikipedia.org/wiki/George_Washington,30/04/1789,4/03/1797,Independent,Virginia\n2,John Adams,http://en.wikipedia.org/wiki/John_Adams,4/03/1797,4/03/1801,Federalist,Massachusetts\n3,Thomas Jefferson,http://en.wikipedia.org/wiki/Thomas_Jefferson,4/03/1801,4/03/1809,Democratic-Republican,Virginia\n4,James Madison,http://en.wikipedia.org/wiki/James_Madison,4/03/1809,4/03/1817,Democratic-Republican,Virginia\n5,James Monroe,http://en.wikipedia.org/wiki/James_Monroe,4/03/1817,4/03/1825,Democratic-Republican,Virginia\n6,John Quincy Adams,http://en.wikipedia.org/wiki/John_Quincy_Adams,4/03/1825,4/03/1829,Democratic-Republican/National Republican,Massachusetts"
//"Sample Text repacement for future cvs data"content to save
// Write File
do {
try contentsOfFile.writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding)
print("File sample.txt created at tmp directory")
} catch {
print("Failed to create file")
print("\(error)")
}
}
// Share button
#IBAction func shareDoc(sender: AnyObject) {
print("test share file")
docController.UTI = "public.comma-separated-values-text"
docController.delegate = self//delegate
docController.name = "Export Data"
docController.presentOptionsMenuFromBarButtonItem(sender as! UIBarButtonItem, animated: true)
//}
}
When i click the share file button in the simulator i see the following:
and with quick look it shows
So the next thing i did was testing with my iphone 5 and i tried to email sample.csv but i am only getting the message body and not the csv file???
how can i actually email the .csv file?
which export possibilities are there?
In order to email the .csv file, you can do the following:
Add this import to the top of the class. It allows you to use MFMailComposeViewController, which is a way to send emails.
import MessageUI
Generate your data, a sample I have done is:
// Creating a string.
var mailString = NSMutableString()
mailString.appendString("Column A, Column B\n")
mailString.appendString("Row 1 Column A, Row 1 Column B\n")
mailString.appendString("Row 2 Column A, Row 2 Column B\n")
// Converting it to NSData.
let data = mailString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
// Unwrapping the optional.
if let content = data {
print("NSData: \(content)")
}
Generate the MFMailComposeViewController
// Generating the email controller.
func configuredMailComposeViewController() -> MFMailComposeViewController {
let emailController = MFMailComposeViewController()
emailController.mailComposeDelegate = self
emailController.setSubject("CSV File")
emailController.setMessageBody("", isHTML: false)
// Attaching the .CSV file to the email.
emailController.addAttachmentData(data!, mimeType: "text/csv", fileName: "Sample.csv")
return emailController
}
// If the view controller can send the email.
// This will show an email-style popup that allows you to enter
// Who to send the email to, the subject, the cc's and the message.
// As the .CSV is already attached, you can simply add an email
// and press send.
let emailViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.presentViewController(emailViewController, animated: true, completion: nil)
}
In your case, as you have already created the file, you can simply attach that directly by changing the line where the CSV is attached to the mail for:
emailController.addAttachmentData(NSData(contentsOfFile: "YourFile")!, mimeType: "text/csv", fileName: "Sample.csv")
Answer based on: Attach csv to email xcode ,
Create CSV file in Swift and write to file
Creating CSV file in Swift
class ViewController: UIViewController {
var taskArr = [Task]()
var task: Task!
override func viewDidLoad() {
super.viewDidLoad()
task = Task()
for _ in 0..<5 {
task.name = "Raj"
task.date = "\(Date())"
task.startTime = "Start \(Date())"
task.endTime = "End \(Date())"
taskArr.append(task!)
}
creatCSV()
}
// MARK: CSV file creating
func creatCSV() -> Void {
let fileName = "Tasks.csv"
let path = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
var csvText = "Date,Task Name,Time Started,Time Ended\n"
for task in taskArr {
let newLine = "\(task.date),\(task.name),\(task.startTime),\(task.endTime)\n"
csvText.append(newLine)
}
do {
try csvText.write(to: path!, atomically: true, encoding: String.Encoding.utf8)
} catch {
print("Failed to create file")
print("\(error)")
}
print(path ?? "not found")
}
}
Task Model class
class Task: NSObject {
var date: String = ""
var name: String = ""
var startTime: String = ""
var endTime: String = ""
}
CSV output show as below format
SWIFT 5
func creatCSV() {
let fileName = "exportar_serv.csv"
/* CREAR UN ARCHIVO NUEVO EN EL DIRECTORIO PRINCIPAL */
guard let path = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(fileName) as NSURL else {
return }
var csvText = "id,name,imageName\n"
for task in taskArr {
let x : Int64 = task.id!
let id2 = String(x)
let newLine = "\(id2),\(task.name),\(task.imageName)\n"
csvText.append(newLine)
} // for
do {
try csvText.write(to: path as URL, atomically: true, encoding: String.Encoding.utf8)
print("DATOS GUARDADOS")
} catch {
print("Failed to create file")
print("\(error)")
} // catch
} // CreateCSV
Swift 5.0.1, Xcode 10.2.1 version
private func injectExportButton() {
var csvIcon: UIImage
switch self.theme {
case .dark:
csvIcon = UIImage(named: "csv-export.dark", in: Bundle.framework)!
case .light:
csvIcon = UIImage(named: "csv-export.light", in: Bundle.framework)!
}
let imgWidth = csvIcon.size.width
let imgHeight = csvIcon.size.height
let button: UIButton = UIButton(frame: CGRect(x: 0, y: 0, width: imgWidth, height: imgHeight))
button.setBackgroundImage(csvIcon, for: UIControl.State())
button.alpha = 0
button.addTarget(self, action: #selector(csvExportButtonClicked), for: .touchUpInside)
UIView.animate(withDuration: 0.5) {
button.alpha = 1
}
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
}
#objc private func csvExportButtonClicked() {
debugPrint("export clicked")
createCSV()
}
private func createCSV() -> Void {
let fileName = getDocumentsDirectory().appendingPathComponent("OutputD.csv")
var csvOutputText = "Result, Date, Name\n"
history.results.forEach { result in
let newLine = "\(String(describing: result.value)),\(String(describing: result.date)),\(String(describing: result.name))\n"
csvOutputText.append(newLine)
}
do {
try csvOutputText.write(to: fileName, atomically: true, encoding: String.Encoding.utf8)
} catch {
print("Failed to create file")
print("\(error)")
}
let activity = UIActivityViewController(activityItems: ["your results", fileName], applicationActivities: nil)
present(activity, animated: true)
}
private func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}

Resources