I am attempting to bind a proxy to a particular http request. So I have created a proxy class as outlined below which grabs a proxy and binds it using the kCF properties.
class Proxy {
func configureProxy(proxy: String) -> NSURLSessionConfiguration {
let proxyArr = proxy.componentsSeparatedByString(":")
let host = proxyArr[0]
let port = proxyArr[1].toInt()
if let p = port{
return newSession(host, port: p)
}
return NSURLSessionConfiguration.defaultSessionConfiguration()
}
func newSession(host: String, port: Int) -> NSURLSessionConfiguration {
let proxyInfo = [
kCFStreamPropertyHTTPProxyHost : host as NSString,
kCFStreamPropertyHTTPProxyPort : port,
kCFNetworkProxiesHTTPEnable as NSString : true
]
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
config.connectionProxyDictionary = proxyInfo
return config
}
}
This is my service class which receives a request from any service class which extends it. E.G (HttpBin : Service). Once all setup is done including the correct router (which is just a mutableUrlRequest), the service class is responsible for sending the http request. For testing purposes the configuration is done during the initialization of the Service class.
class Service {
var res = ResponseHandler()
var alamofireManager : Alamofire.Manager?
init(){
let ipconfig = Proxy()
let config = ipconfig.configureProxy(VALIDPROXY)
alamofireManager = Alamofire.Manager(configuration: config)
}
func createRequest(Router : routes, type : String, completion:(response: ResponseHandler) -> Void){
if let manager = alamofireManager {
println(manager.session.configuration.connectionProxyDictionary)
switch(type){
case "download":
manager.request(Router).responseImage() {
(_, _, image, error) in
self.res.image = image
self.res.success = true
completion(response: self.res)
}
break;
case "upload":
manager.upload(Router, data: uploadData)
.responseJSON { (request,response, JSON, error) in
self.res = self.getResponse(JSON, error : error)
}.responseString{ (_,_,string,error) in
if (error != nil){
println(error)
}
self.res.responseString = string
completion(response: self.res)
}
default:
manager.request(Router)
.responseJSON { (request,response, JSON, error) in
self.res = self.getResponse(JSON, error : error)
}.responseString{ (_,_,string,error) in
self.res.responseString = string
println(error)
println(string)
completion(response: self.res)
}
}
}
}
func getResponse(serverData : AnyObject?, error: NSError?)-> ResponseHandler{
if let data: AnyObject = serverData {
self.res.response = SwiftyJSON.JSON(data.0)
if(error == nil){
self.res.success = true
}
else{
self.res.error = error
println(error)
}
}
return self.res
}
}
Upon hitting my test api, the client ip from the request appears to be my ip & not the one created from the proxyInfo dictionary. manager.session.configuration.connectionProxyDictionary prints the values set in the dictionary. Any ideas if something in the Alamofire framework prevents this or if it is my implementation that is wrong?
EDIT:
I am trying some stuff by implementing NSURLProtocol and using the CFReadStreamSetProperty functions to intercept requests before they are sent. So far no luck.
Edit1:
:(
Related
App upload through the interface to the server, the server and then upload the picture to the storage space.I know my method is not the best If there are good ways to thank share
code look like this:
with main.swift
let config = try Config()
try config.addProvider(PostgreSQLProvider.Provider.self)
let drop = try Droplet(config)
let fleCrl = FileController();
fleCrl.addRoutest(drop: drop);
drop.resource("files", fleCrl);
with FileController.swift
final class FileController: ResourceRepresentable{
var drop:Droplet?;
public func addRoutest(drop: Droplet) -> Void {
self.drop = drop;
let d = drop.grouped("file");
d.post("updateFile", handler: updateFile)
}
func updateFile(req:Request) throws -> ResponseRepresentable {
let picName = req.data["name"]?.string ?? String();
let bytes:[UInt8] = (req.data["data"]?.bytes)!;
let request = Request(method:.post,uri:"http://up.qiniu.com");
let t = "image/\(picName)";
let token = req.data["token"]?.bytes;
request.formData = [
"token":Field(name:"token",filename:nil,part:Part(headers:[:], body: token!)),
"file":Field(name:"file",filename:t,part:Part(headers:["Content-Type": "vnd.apple.mpegURL"],body:bytes)),
"key":Field(name:"key",filename:t,part:Part(headers:[:],body:t.bytes))
]
let resp = try self.drop?.client.respond(to: request);
return resp?.data["info"]?.string;
}
}
with client
let data = try Data.init(contentsOf: URL.init(string: "video.m3u8")!);
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(data!, withName: "data", fileName: "video", mimeType:"application/x-mpegURL")
multipartFormData.append("videoName".data(using: .utf8)!, withName: "name")
}, to: "http://0.0.0.0:8083/file/updateFile") { (encodingResult) in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
}
case .failure(let encodingError):
print(encodingError)
}
}
The server console is reported as follows
[Stream Error: The stream is closed] [Identifier: Transport.StreamError.closed]
I'm trying to test encryption using the iOS keychain.
Domain=com.apple.LocalAuthentication Code=-1009 "ACL operation is not allowed: 'od'" UserInfo={NSLocalizedDescription=ACL operation is not allowed: 'od'}
This is my test code:
func testEncrpytKeychain() {
let promise = expectation(description: "Unlock")
let data: Data! = self.sampleData
let text: String! = self.sampleText
wait(for: [promise], timeout: 30)
let chain = Keychain(account: "tester", serviceName: "testing2", access: .whenPasscodeSetThisDeviceOnly, accessGroup: nil)
chain.unlockChain { reply, error in
defer {
promise.fulfill()
}
guard error == nil else {
// ** FAILS ON THIS LINE WITH OSSTATUS ERROR **
XCTAssert(false, "Error: \(String(describing: error))")
return
}
guard let cipherData = try? chain.encrypt(data) else {
XCTAssert(false, "Cipher Data not created")
return
}
XCTAssertNotEqual(cipherData, data)
guard let clearData = try? chain.decrypt(cipherData) else {
XCTAssert(false, "Clear Data not decrypted")
return
}
XCTAssertEqual(clearData, data)
let clearText = String(data: clearData, encoding: .utf8)
XCTAssertEqual(clearText, text)
}
}
And this is the underlying async unlockChain code:
// context is a LAContext
func unlockChain(_ callback: #escaping (Bool, Error?) -> Void) {
var error: NSError? = nil
guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else {
callback(false, error)
return
}
context.evaluateAccessControl(control, operation: .createItem, localizedReason: "Access your Account") { (reply, error) in
self.context.evaluateAccessControl(self.control, operation: .useItem, localizedReason: "Access your Account") { (reply, error) in
self.unlocked = reply
callback(reply, error)
}
}
}
Here is how the context and control objects are made
init(account: String, serviceName: String = (Bundle.main.bundleIdentifier ?? ""), access: Accessibility = .whenUnlocked, accessGroup: String? = nil) {
self.account = account
self.serviceName = serviceName
self.accessGroup = accessGroup
self.access = access
var error: Unmanaged<CFError>? = nil
self.control = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
access.attrValue,
[.privateKeyUsage],
&error)
if let e: Error = error?.takeRetainedValue() {
Log.error(e)
}
self.context = LAContext()
}
I can't find a single bit of information about this error:
Domain=com.apple.LocalAuthentication Code=-1009
the OSStatus Code site doesn't contain anything for it either
any help is appreciated, thanks.
I solved the same issue by removing the previous private key before creating a new one.
I would guess that on iOS10 (11 was not showing up the error), when you SecKeyCreateRandomKey(...) with the same tag/size but not the same access settings, it would just return true but use the old one (feels odd but who knows)?
Here is a lazy C function I just made to remove it (just remember to set your ApplicationPrivateKeyTag:
void deletePrivateKey()
{
CFStringRef ApplicationPrivateKeyTag = CFSTR("your tag here");
const void* keys[] = {
kSecAttrApplicationTag,
kSecClass,
kSecAttrKeyClass,
kSecReturnRef,
};
const void* values[] = {
ApplicationPrivateKeyTag,
kSecClassKey,
kSecAttrKeyClassPrivate,
kCFBooleanTrue,
};
CFDictionaryRef params = CFDictionaryCreate(kCFAllocatorDefault, keys, values, (sizeof(keys)/sizeof(void*)), NULL, NULL);
OSStatus status = SecItemDelete(params);
if (params) CFRelease(params);
if (ApplicationPrivateKeyTag) CFRelease(ApplicationPrivateKeyTag);
if (status == errSecSuccess)
return true;
return false;
}
FWIW: it looks like apple updated their doc about the Security Framework and the SecureEnclave, it's a bit easier to understand now.
This is my very first program in Swift. I'm writing a basic command line (UDP) server/listener in swift using Xcode. I'm able to send data i.e. a string with characters 'testing' via the "sendData" call (verified through wireshark). However I can't seem to invoke any of the delegate callbacks. For "sendData", I've checked the implementation within #GCDAsyncUdpSocket's main file and I see that none of the delegates are called unless send we see a particular error (resolve error) in which case the "didNOTSendDataWithTag" is called.
But if "beginReceiving" is called, it does NOT invoke "didReceiveData" callback. I cant seem to find figure out why. Also "beginReceiving is suppose to be recursive (Calls itself forever I assume) according to its implementation. But my program exits quickly without any errors. Any help will be really appreciated.
import Cocoa
import CocoaAsyncSocket
class udpListener : GCDAsyncUdpSocketDelegate {
var udpSock : GCDAsyncUdpSocket?
let listenPort : UInt16 = 14000
let data = "testing".dataUsingEncoding(NSUTF8StringEncoding)
let toAddress = "127.0.0.1"
let connectPort : UInt16 = 14001
init () {
udpSock = GCDAsyncUdpSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
do {
try udpSock!.bindToPort(listenPort, interface: "lo0") // Swift automatically translates Objective-C methods that produce
// errors into methods that throw an error according to Swift’s native error handling functionality.
}
catch _ as NSError {
print("Issue with binding to Port")
return }
do {
try udpSock!.beginReceiving()
}
catch _ as NSError {
print("Issue with receciving data")
return }
}
func sendData() {
udpSock!.sendData(data, toHost: toAddress, port: connectPort, withTimeout: -1, tag: 0)
}
}
// Delegate CallBacks
#objc func udpSocket(sock: GCDAsyncUdpSocket!, didReceiveData data: NSData!, fromAddress address: NSData!, withFilterContext filterContext: AnyObject!) {
let str = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(str)
}
#objc func udpSocket(sock: GCDAsyncUdpSocket!, didSendDataWithTag tag: Int) {
print("didSendDataWithTag")
}
#objc func udpSocket(sock: GCDAsyncUdpSocket!, didNotSendDataWithTag tag: Int, dueToError error: NSError!) {
print("didNOTSendDataWithTag")
}
}
I'm instantiating an instance of the class from the main swift file and calling its methods in this order. Is this correct or am I missing something here
import Foundation
var dnsListener = udpListener()
dnsListener.sendData()
Here's the screenshot of the wireshark results
The main thread does not have any loop to keep it from exiting, so the execution is finished before the message is sent. If a loop or delay is added to main(), the message will be sent.
The other problem with this code is that the delegates are set to run on the main queue. The main queue is busy running the loop or delay, and can not execute the delegate code. By creating a new delegate queue, the code in the delegate functions will run.
The following code works in Swift 3.
Main code:
import Foundation
var dnsListener = UdpListener()
for i in 1...3 {
print("Sending data \(i)")
dnsListener.sendData()
sleep(3)
}
print("Execution finished")
UdpListener code:
import Foundation
import CocoaAsyncSocket
class UdpListener : NSObject, GCDAsyncUdpSocketDelegate {
var udpSock: GCDAsyncUdpSocket?
let listenPort: UInt16 = 14000
let data = "testing".data(using: String.Encoding.utf8)
let toAddress = "127.0.0.1"
let connectPort: UInt16 = 14001
override init() {
super.init()
let utilityQueue = DispatchQueue(label: "com.stackoverflow.UdpListener.utilityQueue", qos: .utility)
udpSock = GCDAsyncUdpSocket(delegate: self, delegateQueue: utilityQueue)
do {
try udpSock!.bind(toPort: listenPort, interface: "lo0")
} catch {
print("Issue with binding to Port")
return
}
do {
try udpSock!.beginReceiving()
} catch {
print("Issue with receciving data")
return
}
}
func sendData() {
udpSock!.send(data!, toHost: toAddress, port: connectPort, withTimeout: -1, tag: 0)
}
// Delegate CallBacks
func udpSocket(_ sock: GCDAsyncUdpSocket, didReceive data: Data, fromAddress address: Data, withFilterContext filterContext: Any?) {
let str = String(data: data, encoding: String.Encoding.utf8)
if let str = str {
print(str)
} else {
print("Could not decode received data")
}
}
func udpSocket(_ sock: GCDAsyncUdpSocket, didSendDataWithTag tag: Int) {
print("didSendDataWithTag")
}
func udpSocket(_ sock: GCDAsyncUdpSocket, didNotSendDataWithTag tag: Int, dueToError error: Error?) {
print("didNOTSendDataWithTag")
}
}
I'm trying to verify/validate url but when I do it always opens safari. Any of you know how can accomplish this without open safari. Here is my code:
func validateUrl (urlString: String?) -> Bool {
let url:NSURL = NSURL(string: urlString!)!
if NSWorkspace.sharedWorkspace().openURL(url) {
return true
}
return false
}
print (validateUrl("http://google.com"))
I'll really appreciate your help.
There's two things to check: if the URL itself is valid, and if the server responds without error.
In my example I'm using a HEAD request, it avoids downloading the whole page and takes almost no bandwidth.
func verifyURL(urlPath: String, completion: (isValid: Bool)->()) {
if let url = NSURL(string: urlPath) {
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "HEAD"
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { (_, response, error) in
if let httpResponse = response as? NSHTTPURLResponse where error == nil && httpResponse.statusCode == 200 {
completion(isValid: true)
} else {
completion(isValid: false)
}
}
task.resume()
} else {
completion(isValid: false)
}
}
Usage:
verifyURL("http://google.com") { (isValid) in
print(isValid)
}
For use in a Playground, don't forget to enable the asynchronous mode in order to be able to use NSURLSession:
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
You rather need to do following check:
func validateUrl (urlString: String?) -> Bool {
let url: NSURL? = NSURL(string: urlString!)
if url != nil {
return true
}
return false
}
print (validateUrl("http://google.com"))
print (validateUrl("http:/ /google.com"))
From the documentation and the 2.0 Migrate Guide I tried to use Response Serialization but I'm having the following errors. I can't seem to figure out the problems. I'm also having the same errors with ResponseCollectionSerializable.
You should use GenericResponseSerializer that conforms to ResponseSerializer:
public protocol ResponseObjectSerializable {
init?(response: NSHTTPURLResponse, representation: AnyObject)
}
extension Request {
public func responseObject<T: ResponseObjectSerializable>(completionHandler: (NSURLRequest?, NSHTTPURLResponse?, Result<T>) -> Void) -> Self {
let responseSerializer = GenericResponseSerializer<T> { request, response, data in
let JSONResponseSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
let result = JSONResponseSerializer.serializeResponse(request, response, data)
switch result {
case .Success(let value):
if let
response = response,
responseObject = T(response: response, representation: value)
{
return .Success(responseObject)
} else {
let failureReason = "JSON could not be serialized into response object: \(value)"
let error = Error.errorWithCode(.JSONSerializationFailed, failureReason: failureReason)
return .Failure(data, error)
}
case .Failure(let data, let error):
return .Failure(data, error)
}
}
return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
}
}
ResponseSerializer is the protocol in which all response serializers must conform to.