Xcode Swift Quickbooks call - xcode

I want to do an API request to my Quickbooks company, but I'm having some issues. Every time I try to connect, I get an error saying "The operation can't be completed": error 1012. I searched it up, and this error has to do with the OAuth tokens being wrong. I do not know which tokens to put in the following headers:
var request = NSMutableURLRequest(URL: NSURL(string: "https://quickbooks.api.intuit.com/v3/company/myCompanyId/query?query=SELECT%2A%20FROM%20Customer")!)
request.HTTPMethod = "GET"
request.setValue("secret", forHTTPHeaderField: "oauth_token")
request.setValue("secret", forHTTPHeaderField: "app_token")
request.setValue("secret", forHTTPHeaderField: "oauth_consumer_key")
request.setValue("D3jdR1LMb5T2mF0yggcgHsYjVjs%3D", forHTTPHeaderField: "oauth_signature")
request.setValue("HMAC-SHA1", forHTTPHeaderField: "oauth_signature_method")
request.setValue("1424984263", forHTTPHeaderField: "oauth_timestamp")
request.setValue("1.0", forHTTPHeaderField: "oauth_version")
request.setValue("f3b666ee-2d2a-42a1-81b3-8370b74c4c3a", forHTTPHeaderField: "oauth_nonce")
println(request.allHTTPHeaderFields!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
(response, data, error) in
println(response)
println(error)
println(data)
if error == nil {
if let HTTPResponse = response as? NSHTTPURLResponse {
let statusCode = HTTPResponse.statusCode
if statusCode == 200 {
println("success")
println(response)
}
}
}
}
Can anybody tell me where to find the correct keys for these values? I can only find keys for app token, oauth consumer key, and oath consumer key secret. Where do these values go too?

Using consumerKey and consumerSecret , you can generate accessToken and accessSecret from the OAuthPlayground. https://appcenter.intuit.com/Playground/OAuth/IA
PN - After completing C2QB(OAuth) flow, you should use 'App Menu API Test.' option which will show you accessToken and accessSecret.

Related

How to implement graphql subscription using apollo ios client

I am trying to implement graphql subscription using apollo ios client. But not able to figure it out as lack of documentation examples.
Example given on apollo documentation is:
let apollo: ApolloClient = {
let configuration = URLSessionConfiguration.default
// Add additional headers as needed
configuration.httpAdditionalHeaders = ["Authorization": "Bearer <token>"] // Replace `<token>`
let url = URL(string: "http://localhost:8080/graphql")!
return ApolloClient(networkTransport: HTTPNetworkTransport(url: url, configuration: configuration))
}()
APOLLO IOS GUIDE: Creating a client
Implement the subscription in apollo ios graphql client by following below steps.
Using cocoapods:
pod 'Apollo'
pod 'Apollo/WebSocket'
pod install
To create client to support subscription and authentication. Add below code in AppDelegate.swift:
Websocket - we have to use WebSocketTransport and URLRequest
Authentication - we have to pass auth parameters in connection params connectingPayload to server. And for http we are passing it in headers as mentioned in question snippet.
SplitNetworkTransport- To combine both http and websocket to create client. we have to use httpNetworkTransport and webSocketNetworkTransport
lazy var apollo: ApolloClient = {
let authPayloads = [
"Authorization": "Bearer "
]
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = authPayloads
let map: GraphQLMap = authPayloads
let wsEndpointURL = URL(string: "ws://localhost:8080/subscriptions")!
let endpointURL = URL(string: "http://localhost:8080/api")!
let websocket = WebSocketTransport(request: URLRequest(url: wsEndpointURL), connectingPayload: map)
let splitNetworkTransport = SplitNetworkTransport(
httpNetworkTransport: HTTPNetworkTransport(
url: endpointURL,
configuration: configuration
),
webSocketNetworkTransport: websocket
)
return ApolloClient(networkTransport: splitNetworkTransport)
}()
I'm getting close. I was getting rejected for not having the correct headers in my Websocket upgrade. I ended up having to set them directly on the URLRequest object.
var apollo: ApolloClient? {
let authHeaders = ["X-Hasura-Access-Key": "<my_Key>", "Content-Type": "application/json"]
let configuration = URLSessionConfiguration.default
// Add additional headers as needed
configuration.httpAdditionalHeaders = authHeaders
//The string to my graph QL Server run by Hasure on AWS RDS.
let graphQLEndpoint = "http://<my_host>/v1alpha1/graphql"
let graphQLSubscriptionEndpoint = "ws://<my_host>/v1alpha1/graphql"
//Take my Ec2 Server string and make a URL for the graph QL and subscriptions
guard let httpURL = URL(string: graphQLEndpoint), let webSocketURL = URL(string: graphQLSubscriptionEndpoint) else {
return nil
}
let httpTransport = HTTPNetworkTransport(url: httpURL, configuration: configuration, sendOperationIdentifiers: false)
var request = URLRequest(url: webSocketURL)
request.setValue("<my_key>", forHTTPHeaderField: "X-Hasura-Access-Key")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let webSocketTransport = WebSocketTransport(request: request, sendOperationIdentifiers: false, connectingPayload: nil)
let splitTransport = SplitNetworkTransport(httpNetworkTransport: httpTransport, webSocketNetworkTransport: webSocketTransport)
//Initalize the APolloClient with that URL.
return ApolloClient(networkTransport: splitTransport)
}
The upgrade worked after that.
Here's my ApolloClient setup for just a web socket transport client:
let connectingPayload = ["authToken": accessToken]
let urlRequest = URLRequest(url: baseURL)
let webSocketTransport = WebSocketTransport(request: urlRequest, sendOperationIdentifiers: false, connectingPayload: connectingPayload)
let apollo = ApolloClient(networkTransport: webSocketTransport)

Swift 2 OSX How come session with proxy succeeds without authentication?

I'm making an NSURLRequest through a proxy host/port. It seems that the request is receiving the appropriate response. The only issue is that this proxy/port requires authentication. Why am I not being prompted to authenticate the proxy host?
func sendRequest() {
let request = NSMutableURLRequest(NSURL(string: "https://www.awebsite/login")
let params = "&username=\(username)&password=\(password)&okc_api=1"
request.HTTPBody = params.dataUsingEncoding(NSUTF8StringEncoding)
request.HTTPMethod = "POST"
let proxyDict:[NSObject:AnyObject] = [
kCFNetworkProxiesHTTPEnable: NSNumber(int: 1) as CFNumber,
kCFStreamPropertyHTTPProxyHost: "123.456.789.012",
kCFStreamPropertyHTTPProxyPort: 1234,
kCFStreamPropertyHTTPSProxyHost: "123.456.789.012",
kCFStreamPropertyHTTPSProxyPort: 1234,
kCFProxyTypeKey: kCFProxyTypeHTTP,
kCFProxyTypeKey: kCFProxyTypeHTTPS
]
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.connectionProxyDictionary = proxyDict
let operationQueue = NSOperationQueue()
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: operationQueue)
let task = session.dataTaskWithRequest(request) {
(data, response, error) in
do {
let responseHeaders = response as! NSHTTPURLResponse
let statusCode = responseHeaders.statusCode
let contentsOfURL = try NSString(contentsOfURL: URL, encoding: NSUTF8StringEncoding)
if contentsOfURL.containsString("p_home") {
print(statusCode)
print("LOGGED IN!")
} else {
print("FAILED LOGIN!")
}
print(statusCode)
} catch {
print(error)
}
}
task.resume()
}
The proxy's password is probably already stored in the system keychain already, so it isn't asking you again. To know for sure, you'd have to check in the proxy server's logs to see if the requests are coming in with proper authentication.

Upload image with URL parameters using Alamofire on iOS 9 issue

I have an iOS app written in Swift 2.0 wich uploads images to Microsoft Azure Blob Storage. I use Alamofire for the requests.
On an device with iOS 8 everything works fine, but on iOS 9 it get errors on upload:
let AlamofireManager = Alamofire.Manager.sharedInstance
AlamofireManager.session.configuration.HTTPAdditionalHeaders = [
"Content-Type": "image/jpg",
"x-ms-blob-type": "BlockBlob"
]
AlamofireManager.upload(.PUT, uploadURL, data: imageData)
.responseJSON { (request, response, result) in
print("Request=\(request)")
print("response=\(response)")
print("result=\(result)")
if (response) != nil {
let statusString = String(stringInterpolationSegment: response!.statusCode)
let statusCode = self.getStatusCodeFromStatusString(statusString)
if (statusCode == 201) {
// MY SUCCESS CODE IS HERE
}
else {
// STATUSCODE != 201
}
}
else {
// OTHER ERROR
}
}
An sample URL for the upload (uploadURL) might be:
https://mystorage.blob.core.windows.net:443/thumbs/7346e38a-eb54-48ea-b0fe-89357100dd18.jpg?sv=2013-08-15&sr=b&sig=GYwHvnUc52GsajFJCAu1v4W5qG0wSBpaXvxncD%2FAt34%3D&st=2015-10-01T11%3A25%3A57Z&se=2015-10-01T11%3A40%3A57Z&sp=w
For Azure it is important, that:
a) The HTTP-Verb is PUT
b) The Url parameters are included in Url and not as multipart data (this is the access token for the upload).
Perhaps Alamofire has problems on creating the URL with parameters in combination with the PUT?
This solution does not work, because it´s based on multipart data upload: Upload image with parameters in Swift
Because I think about the URL parameter problem, I tried following:
let AlamofireManager = Alamofire.Manager.sharedInstance
AlamofireManager.session.configuration.HTTPAdditionalHeaders = [
"Content-Type": "image/jpg",
"x-ms-blob-type": "BlockBlob"
]
var URLRequest: NSMutableURLRequest {
let URL = NSURL(string: uploadURL)!
var mutableRequest = NSMutableURLRequest(URL: URL)
mutableRequest.HTTPMethod = Alamofire.Method.PUT.rawValue
return mutableRequest
}
AlamofireManager.upload(URLRequest, data: imageData)
:
: rest is same like above
:
But this does´t work, too. In both cases I always get an 400 error (in response.statusCode) from the server. result contains Failure and the information NSCocoaErrorDomain - code 3840 with description Invalid value around character 3.
But on iOS 8, the solution works like a charm :(
Any ideas, what the problem is and how to solve it?
Edit: Or could the port be the problem?
Got it on my own. Alamofire seems not to send the HTTP-Headers as expected with the AlamofireManager. I added the headers manually:
var URLRequest: NSMutableURLRequest {
let URL = NSURL(string: uploadURL)!
var mutableRequest = NSMutableURLRequest(URL: URL)
mutableRequest.HTTPMethod = Alamofire.Method.PUT.rawValue
mutableRequest.setValue("image/jpg", forHTTPHeaderField: "Content-Type")
mutableRequest.setValue("BlockBlob", forHTTPHeaderField: "x-ms-blob-type")
return mutableRequest
}
AlamofireManager.upload(URLRequest, data: imageData)
:
:

Swift 2.0 NSURLConnection sendSynchronousRequest

I am using the code below to check for an internet connection. It was working correctly but after the Swift 2.0 update I now see an error on the line var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: nil) as NSData? saying extra argument 'error' in call.
class func isConnectedToNetwork()->Bool{
var Status:Bool = false
let url = NSURL(string: "http://google.com/")
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "HEAD"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
request.timeoutInterval = 10.0
var response: NSURLResponse?
var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: nil) as NSData?
if let httpResponse = response as? NSHTTPURLResponse {
if httpResponse.statusCode == 200 {
Status = true
}
}
return Status
}
Do you have any ideas what I should change it to?
Thanks
If you look at apples documentation (https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/#//apple_ref/occ/clm/NSURLConnection/sendSynchronousRequest:returningResponse:error:) you'll see that the definition changed to this:
class func sendSynchronousRequest(_ request: NSURLRequest,
returningResponse response: AutoreleasingUnsafeMutablePointer<NSURLResponse?>) throws -> NSData
They have removed the error parameter and the method throws now an ErrorType, if the request fails. So this should work:
do {
let data = try NSURLConnection.sendSynchronousRequest(request, returningResponse: &response)
} catch (let e) {
print(e)
}
However you shouldn't use this method: It's deprecated in favor of NSURLSession since iOS 9 and OS X 10.11.

Making Amazon Web Services S3 POST request in Swift

I am trying to use AWS S3 service to host images of my iOS application in Swift language.
At this step I am just trying to simply post png image with POST request.
In any POST request for AWS S3 we need to make an authorization header which consists of the information that authenticate this request. To encode data with HMAC SHA256 which is required by Amazon I use GitHub project as my Subproject from this link: https://github.com/krzyzanowskim/CryptoSwift
This helped me to encrypt the signature however when I tried to send this request I received an error which says: "SignatureDoesNotMatchThe request signature we calculated does not match the signature you provided. Check your key and signing method."
Here is my code:
var img = UIImage(named: "myImage.png")
var imageData : NSData = UIImageJPEGRepresentation(img, 1.0)
let key = "mybucketname"
let url = NSURL(string:"http://mybucket.s3.amazonaws.com/")
var request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
let uniqueId = NSProcessInfo.processInfo().globallyUniqueString
var postBody:NSMutableData = NSMutableData()
var boundary:String = "------WebKitFormBoundary\(uniqueId)"
request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField:"Content-Type")
// I am trying to generate a date stamp compatible for request
let date = NSDate()
let formatter = NSDateFormatter()
formatter.timeStyle = .ShortStyle
formatter.stringFromDate(date)
var dateKey = ["AWS4"+"My AWSSecretKey","20150317"]
// Here is the signature that I'm trying to make
var signature = "My AWSSecretKey".sha256()?.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
request.addValue("AWS MYAWSACCESSKEYID:\(signature)", forHTTPHeaderField: "Authorization")
request.addValue("Wed, 18 Mar 2015 20:39:27 +0000", forHTTPHeaderField: "Date")
request.addValue(key, forHTTPHeaderField:"key")
request.addValue("\(postBody.length)", forHTTPHeaderField:"Content-Length")
postBody.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
postBody.appendData("Content-Type: image/png\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
postBody.appendData(imageData)
var postData = String()
postData += "\r\n"
postData += "\r\n--\(boundary)--\r\n"
postBody.appendData(postData.dataUsingEncoding(NSUTF8StringEncoding)!)
request.HTTPBody = postBody
var error: NSError?
let session = NSURLSession.sharedSession()
var task = session.dataTaskWithRequest(request, completionHandler: { (data, response, err) -> Void in
var stringData = NSString(data: data, encoding: NSUTF8StringEncoding)
var conversionError: NSError?
var jsonDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableLeaves, error: &conversionError) as? NSDictionary
})
task.resume()
I need to find out how to make a proper signature and how I should encrypt it since its my fire time using such tools.
You shouldn't have a secret key hard-coded in your app - this negates its security. I'd suggest generating the key from your own server (eg using the excellent S3Direct django module), then obtain the key like this:
let filename = "myfile.mp4"
let requestUrl = Constants.my_own_server+"/s3direct/get_upload_params/"
println("Uploading file of name ***" + filename + "***")
let defaults = NSUserDefaults.standardUserDefaults()
let authToken : String = defaults.stringForKey("token")!
let manager = Manager.sharedInstance
manager.session.configuration.HTTPAdditionalHeaders = [
"Authorization": "Token " + authToken
]
let parameters : [ String : AnyObject] = [
"type": "video/mp4",
"name": filename,
"dest": "vids"
]
Alamofire.request(.POST, requestUrl, parameters: parameters).response(serializer: Request.JSONResponseSerializer(), completionHandler: { (request, response, object, error) -> Void in
//println(object)
//println(error)
if (error == nil) {
self.uploadFile(videoData!, parameters: object as! [ String : String], filename: filename)
}
else {
print("Failed to sign file")
}
})
Good luck - I have found this particular stack unusually painful to get working.

Resources