I am creating a web based iOS app.
Simply say, my system is like below.
A user input his name on the app
the app POST it to "destination.php"
"destination.php" stores the received POST to a DB
On the app side, Swift code will be like below.
let strData = parameter.dataUsingEncoding(NSUTF8StringEncoding)
let url = NSURL(string:"http://example.com/destination.php")
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
request.HTTPBody = strData
NSURLConnection.sendAsynchronousRequest(request, queue:NSOperationQueue.mainQueue()){(res, data, err) in
//do something
}
I already confirmed that it works well, but from a security point of view, I'm not comfortable with this, because there are no security authorization between the app and "destination.php". In other words, if someone evil finds the URL of "destination.php", he can easily mess up the system with some scripts (posting tons of data to the php, for example).
Is there any good ways to make this kind of connection secure?
Set up Basic authentication on your server and use something like this to build your request.
func request(url: NSURL) -> NSURLRequest {
var request = NSMutableURLRequest(URL: url)
request.setValue(self.authorisation(), forHTTPHeaderField: "Authorization")
request.HTTPMethod = "GET"
return request
}
func authorisation() -> String {
let string = "stuff".stringByAppendingFormat(":%#", "password")
let data = string.dataUsingEncoding(NSASCIIStringEncoding)
let encodedString = data?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding76CharacterLineLength)
let returnValue = "Basic".stringByAppendingFormat(" %#", encodedString!)
return returnValue
}
Related
I'm trying to create a URL Request in Swift to send an HTTP POST request to a Discord Webhook, and the request completes in a failure defined as 'responseProblem'. I'm not sure where the response problem is originating from.
Discord should technically be able to accept HTTP requests, and a bunch of research into the issue has led me nowhere. I've worked with Discord webhooks before, but I've never played around with this kind of stuff before, so I'm kinda stuck for what I should do now.
import Foundation
enum APIError:Error {
case responseProblem
case decodingProblem
case encodingProblem
}
struct APIRequest {
let resourceURL: URL
init(endpoint: String) {
let resourceString = "<discord-webhook-url-removed-for-privacy>"
guard let resourceURL = URL(string: resourceString) else {fatalError()}
self.resourceURL = resourceURL
}
func save (_ messageToSave:Message, completion: #escaping(Result<Message, APIError>) -> Void ) {
do {
var urlRequest = URLRequest(url: resourceURL)
urlRequest.httpMethod = "POST"
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.httpBody = try JSONEncoder().encode(messageToSave)
let dataTask = URLSession.shared.dataTask(with: urlRequest) { data, response, _ in
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200, let
jsonData = data else {
completion(.failure(.responseProblem)) // <<< 'responseProblem' is outputted in console as the error
return
}
do {
let messageData = try JSONDecoder().decode(Message.self, from: jsonData)
completion(.success(messageData))
} catch {
completion(.failure(.decodingProblem))
}
}
dataTask.resume()
} catch {
completion(.failure(.encodingProblem))
}
}
}
When I run this Swift program, I expected it to send a request to the Discord Webhook to send a message into it's designated channel. However, the only error outputted into the console is responseProblem. Please let me know if there is anything further I need to add to get the root cause of the problem (I'm still semi-fresh to Swift, and I normally work with JavaScript, so I'm not sure how to properly debug in Swift and Xcode.)
Swift app is built in iOS 12.2 because Xcode doesn't like this stuff in iOS 13
This is a simplified version of how I post to a Discord webhook with Swift. From your post I can't see how you're converting your custom Message struct into a JSON dictionary, but you need at least the key/value pair for "content" to successfully post a Discord Webhook. And of course the posts can be customized in many other ways (with a custom "username" etc.).
var messageString: String = ""
guard let url = URL(string: "your-full-discord-webhook-url") else { return }
let messageJson: [String: Any] = ["content": messageString]
let jsonData = try? JSONSerialization.data(withJSONObject: messageJson)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "content-type")
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request)
task.resume()
I cannot for the life of me figure out this problem. And I hope you guys can.
I want to send a username and a password over a HTTPS POST. Problem is, I cannot make it work.
The code I am trying to make work right now is:
import UIKit
import Foundation
import PlaygroundSupport
let url:URL = URL(string: "https://mywebsite.com/myAPI")!
let session = URLSession.shared
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let paramString = "username=Pleasework&password=itwont"
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest) {
(
data, response, error) in
guard let data = data, let _:URLResponse = response, error == nil else {
print("error")
return
}
let dataString = String(data: data, encoding: String.Encoding.utf8)
print(dataString ?? "Got nothing")
}
task.resume()
Looking at my server logs, this request goes through, but it is supposed to create a file containing said params. I tried using a Chrome extension called "Request Maker", and the file was created. (The file is created with PHP, and is irrelevant to this question)I found that the file was only created once the content type was specified, so I tried that in Swift.
I am using Swift 3 and Xcode 8, I hope you guys can help me send a simple post request with a content type to a URL, all of the other answers on Stackoverflow have not helped me.
Thanks
I am trying to make an HTTP request to the Imgur API. I am trying to retrieve all images associated with the tag "cats." The url, according to the Imgur API is: https://api.imgur.com/3/gallery/t/cats
the Imgur API states the following about the authorization needed to make get requests:
For public read-only and anonymous resources, such as getting image
info, looking up user comments, etc. all you need to do is send an
authorization header with your client_id in your requests. This also
works if you'd like to upload images anonymously (without the image
being tied to an account), or if you'd like to create an anonymous
album. This lets us know which application is accessing the API.
Authorization: Client-ID YOUR_CLIENT_ID
I've looked at the following questions and tried things suggested there, but none of them have helped.
JSON NSURLRequest with credentials
Swift GET request with parameters
How to make a Http get and set httpHeader in Swift?
My current code is this:
let string = "https://api.imgur.com/3/gallery/t/cats"
let url = NSURL(string: string)
let request = NSMutableURLRequest(URL: url!)
request.setValue("clientIDhere", forHTTPHeaderField: "Authorization")
//request.addValue("clientIDhere", forHTTPHeaderField: "Authorization")
request.HTTPMethod = "GET"
let session = NSURLSession.sharedSession()
let tache = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if let antwort = response as? NSHTTPURLResponse {
let code = antwort.statusCode
print(code)
}
}
tache.resume()
But I continually get a status code of 403, meaning authorization is required. What am I doing wrong?
I think you need to prepend Client-ID string to your actual client ID as for the header value:
request.setValue("Client-ID <your_client_id>", forHTTPHeaderField: "Authorization")
Updated for swift 4 :
func fetchPhotoRequest(YOUR_CLIENT_ID: String) {
let string = "https://photoslibrary.googleapis.com/v1/albums"
let url = NSURL(string: string)
let request = NSMutableURLRequest(url: url! as URL)
request.setValue(YOUR_CLIENT_ID, forHTTPHeaderField: "Authorization") //**
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let mData = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
if let res = response as? HTTPURLResponse {
print("res: \(String(describing: res))")
print("Response: \(String(describing: response))")
}else{
print("Error: \(String(describing: error))")
}
}
mData.resume()
}
I am using Fabric SDK to add the twitter login button in my app.......
i add the authentication header in my URL but still it is showing Bad authentication error while executing.
Suggest me how to add Header in the URL in Swift.
let twitter = Twitter.sharedInstance()
let oauthSigning = TWTROAuthSigning(authConfig:twitter.authConfig, authSession:twitter.session())
let authHeaders = oauthSigning.OAuthEchoHeadersToVerifyCredentials()
let request = NSMutableURLRequest(URL: NSURL(string: "https://api.twitter.com/1.1/search/tweets.json?q=Himan_dhawan")!)
request.allHTTPHeaderFields = authHeaders
println(request)
var session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
if((error) != nil) {
println(error.localizedDescription)
}
var strData = NSString(data: data, encoding: NSASCIIStringEncoding)
println(strData)
})
task.resume()
It's to do with the way that you're setting the headers on the request.
The Fabric doc's don't quite give you the full picture about creating the OAuth signing headers when wanting to use your own NSMutableURLRequest.
let authHeaders = oauthSigning.OAuthEchoHeadersToVerifyCredentials()
The return [NSObject : AnyObject]! dictionary gives you the values you need for the request. However, what it provides for the headers are different to what needs to be sent with the NSMutableURLRequest.
This is how you should be setting the headers for this request:
let twitter = Twitter.sharedInstance()
let oauthSigning = TWTROAuthSigning(authConfig:twitter.authConfig, authSession:twitter.session())
let authHeaders = oauthSigning.OAuthEchoHeadersToVerifyCredentials()
let mutableUrlWithUsableUrlAddress = NSMutableURLRequest(URL: usableUrlForRequest)
mutableUrlWithUsableUrlAddress.addValue(authHeaders[TWTROAuthEchoAuthorizationHeaderKey] as? String, forHTTPHeaderField: "Authorization")
This sets the required Authorisation Key as a value for the "Authorization" header on the request, opposed to when you pass in the authHeaders dictionary, it gets set for "X-Verify-Credentials-Authorization".
The Fabric doc's do go into this, but it's slightly more tucked away than it should be.
I send the same HTTP message from a HTTP proxy client and with NSURLRequest + NSURLConnection, and get back different result. It is an authentication request. From HTTP proxy authentication request is accepted, sending from app not. Why? Accepted means after redirection HTML will contains no Oops substring.
let url = NSURL(string: "http://www.swisshttp.weact.ch/en/user/login")
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let email2 = (viewController!.email.text as NSString).stringByReplacingOccurrencesOfString("#", withString: "%40")
let str = "name=\(email2)&pass=\(viewController!.password.text)&form_id=user_login" as NSString
let d = str.dataUsingEncoding(NSUTF8StringEncoding)
if let d2 = d {
request.HTTPBody = d2
let urlConnection = NSURLConnection(request: request, delegate: self)
}
UPDATE
I have put #teamnorge's code below into playground and into an empty Single View Application project. Returned HTML in project contains the Oops substring, code used in playground not containes it, any idea what is going on, why same request produce different HTML result? I get failed message also from iOS device and from simulator too.
UPDATE
Removed NSURLRequest cache like here recommended, but still not works as expected. And here.
UPDATE
Tried to remove all the credentials like here, but didn't help, no credential was found.
It looks like when you receive HTTP 302 and new Location URL, iOS does automatically fetch the page by this URL, so I guess your response is in fact the HTML content of the redirection page. Please verify.
UPDATE:
import UIKit
import XCPlayground
let url = NSURL(string: "http://www.swisshttp.weact.ch/en/user/login")
let request = NSMutableURLRequest(URL: url!)
let str = "name=kukodajanos%40icloud.com&pass=jelszo&form_id=user_login" as NSString
let d = str.dataUsingEncoding(NSUTF8StringEncoding)
request.HTTPBody = d
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.currentQueue()) { response, maybeData, error in
if let data = maybeData {
let contents = NSString(data:data, encoding:NSUTF8StringEncoding)
println(contents)
if contents!.rangeOfString("Oops").length == 0 {
println("success")
} else {
println("failed")
}
} else {
println(error.localizedDescription)
}
}
XCPSetExecutionShouldContinueIndefinitely()