SocketRocket and pinning certificate error? - objective-c

I'm working with SocketRocket, so far everything has been working fine and today I wanted to try to pin down a (self signed) certificate but I get an error:
- (void)connectWebSocket {
webSocket.delegate = nil;
webSocket = nil;
NSString *urlString = [NSString stringWithFormat: #"wss://%#:%#", server_ip, server_port];
//NSLog(#"%#", urlString);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy: NSURLRequestUseProtocolCachePolicy
timeoutInterval:5.0];
// pin down certificate
NSString *cerPath = [[NSBundle mainBundle] pathForResource:#"myOwnCertificate" ofType:#"cer"];
NSData *certData = [[NSData alloc] initWithContentsOfFile:cerPath];
CFDataRef certDataRef = (__bridge CFDataRef)certData;
SecCertificateRef certRef = SecCertificateCreateWithData(NULL, certDataRef);
id certificate = (__bridge id)certRef;
[request setSR_SSLPinnedCertificates:#[certificate]];
SRWebSocket *newWebSocket = [[SRWebSocket alloc] initWithURLRequest: request];
newWebSocket.delegate = self;
[newWebSocket open];
socketIsOpen = true;
}
Error: No visible #interface for 'NSURLRequest' declares the selector 'setSR_SSLPinnedCertificates:'
Am I missing something?
Thanks!

You need #import "SRWebSocket.h".
SR_SSLPinnedCertificates is a property on the NSURLRequest (CertificateAdditions) category in https://github.com/square/SocketRocket/blob/master/SocketRocket/SRWebSocket.h

The request needs to be a NSMutableURLRequest type. When your request is a NSURLRequest type, the SR_SSLPinnedCertificates is readonly, so you can NOT set it.
#pragma mark - NSURLRequest (CertificateAdditions)
#interface NSURLRequest (CertificateAdditions)
#property (nonatomic, retain, readonly) NSArray *SR_SSLPinnedCertificates;
#end
#pragma mark - NSMutableURLRequest (CertificateAdditions)
#interface NSMutableURLRequest (CertificateAdditions)
#property (nonatomic, retain) NSArray *SR_SSLPinnedCertificates;
#end
Change your code to this:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy: NSURLRequestUseProtocolCachePolicy
timeoutInterval:5.0];
This should works :)

Related

how to submit a password with special characters from app to a web-server by NSURLConnection

I have to login with my to a web-server.All works fine, but not generated passwords like |%<">{}¥^~ . How I have to encode passwords like this?
I create a User with password=|%<">{}¥^~
doset work
( for example a password like "user1234" works fine)
NSString *userName = self.usernameOutlet.text;
NSString *userPassword = self.passwordOutlet.text;
NSString *escapedString = [self.passwordOutlet.text stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
userPassword = escapedString;
NSString *post = [NSString stringWithFormat:#"login=%#&password=%#",userName,userPassword];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%lu",(unsigned long)[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http://XXXXXXXX/login"]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
with passwords like "user1234" I get a cookie
with passwords like "|%<">{}¥^~" I get no cookie
what am I doing wrong?
It’s tempting to want to use URLQueryAllowedCharacterSet, but that won’t work for all strings. Notably & and + will pass unescaped.
If you’re wondering why we must percent escape & and +, too, it’s because these two characters have a special meaning in x-www-form-urlencoded requests. The & is used to delimit key-value pairs in a x-www-form-urlencoded request, so it will truncate your password. And most web services translate a + to a space, so you’ll want to percent escape that, too.
So, let’s first define a character set that will work:
// NSCharacterSet+URLQueryValueAllowed.h
#interface NSCharacterSet (URLQueryValueAllowed)
#property (class, readonly, copy) NSCharacterSet *URLQueryValueAllowedCharacterSet;
#end
and
// NSCharacterSet+URLQueryValueAllowed.m
#implementation NSCharacterSet (URLQueryValueAllowed)
+ (NSCharacterSet *)URLQueryValueAllowedCharacterSet {
static dispatch_once_t onceToken;
static NSCharacterSet *queryValueAllowed;
dispatch_once(&onceToken, ^{
NSMutableCharacterSet *allowed = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
NSString *generalDelimitersToEncode = #":#[]#"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
NSString *subDelimitersToEncode = #"!$&'()*+,;=";
[allowed removeCharactersInString:generalDelimitersToEncode];
[allowed removeCharactersInString:subDelimitersToEncode];
queryValueAllowed = [allowed copy];
});
return queryValueAllowed;
}
#end
Then, to make life easier for us, let’s define NSDictionary category for percent encoding a dictionary:
// NSDictionary+PercentEncoded.h
#interface NSDictionary (PercentEncoded)
- (NSString *)percentEncodedString;
- (NSData *)percentEncodedData;
#end
and
// NSDictionary+PercentEncoded.m
#implementation NSDictionary (PercentEncoded)
- (NSString *)percentEncodedString {
NSMutableArray<NSString *> *results = [NSMutableArray array];
NSCharacterSet *allowed = [NSCharacterSet URLQueryValueAllowedCharacterSet];
for (NSString *key in self.allKeys) {
NSString *encodedKey = [key stringByAddingPercentEncodingWithAllowedCharacters:allowed];
NSString *value = [[self objectForKey:key] description];
NSString *encodedValue = [value stringByAddingPercentEncodingWithAllowedCharacters:allowed];
[results addObject:[NSString stringWithFormat:#"%#=%#", encodedKey, encodedValue]];
}
return [results componentsJoinedByString:#"&"];
}
- (NSData *)percentEncodedData {
return [[self percentEncodedString] dataUsingEncoding:NSUTF8StringEncoding];
}
#end
Then, your application code can do:
NSDictionary *dictionary = #{#"login": userName, #"password": userPassword};
NSData *body = [dictionary percentEncodedData];

Getting data from server in objective c class

Im trying to make a class where when I create an instance of that class and pass a username and password to the class it sends it to the server and gives whether its a valid password or whether theres an error. When I try to access the response variable from the instance I get null. I suspect that the methods begin called -(void)connectionDidFinishLoading:(NSURLConnection *)connection is happening before the variable is being accessed. Is there a better way to access the variable or call the method so it happens before the variable is accessed
Login View Controller.h
#interface LoginViewController : UIViewController
-(IBAction)Login:(id)sender;
#property (nonatomic, retain) IBOutlet UITextField *username;
#property (nonatomic, retain) IBOutlet UITextField *password;
#end
Login View Controller.m
#import "LoginViewController.h"
#import "Users.h"
#interface LoginViewController ()
#end
#implementation LoginViewController
#synthesize username, password;
/*
-(IBAction)Login:(id)sender{
Users *user = [[Users alloc] init];
[user Login:username.text :password.text];
if ([user.serverResponse isEqual: #"Status:Created"]) {
[self performSegueWithIdentifier:#"home" sender:nil];
}
else{
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#""
message:#"Username or Password is incorrect"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
[alert show];
}
NSLog(#"%#",user.serverResponse);
}
#end
Users Class.h
#import <Foundation/Foundation.h>
#interface Users : NSObject
- (void)Login:(NSString*)username :(NSString*)password;
- (void)Signup:(NSString*)username :(NSString*)password :(NSString*)password_confirmation :(NSString*)email;
#property (nonatomic, retain) NSMutableData *response;
#property (nonatomic, retain) NSString *serverResponse;
#end
Users Class.m
#import "Users.h"
#define loginURL #"linktoserver"
#define signupURL #"linktoserver"
#implementation Users
#synthesize response, serverResponse;
- (void)Login:(NSString*)username :(NSString*)password{
NSMutableData *data = [[NSMutableData alloc] init];
self.response = data;
NSURL *url = [NSURL URLWithString:loginURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[url standardizedURL]];
// Http Method
[request setHTTPMethod:#"POST"];
// Intializes Post Data
NSString *postData = [NSString stringWithFormat:#"username=%#&password=%#", username, password];
NSString *postLength = [NSString stringWithFormat:#"%lu", (unsigned long)[postData length]];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:[postData dataUsingEncoding:NSUTF8StringEncoding]];
// Intializes Connection Request
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
}
#pragma Connection
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data
{
[response appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
serverResponse = [[NSString alloc] initWithData:response
encoding:NSUTF8StringEncoding];
}
Use NSURLSession instead of NSURLConnection with delegates (to simplify the process):
[[[NSURLSession sharedSession] dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error && data){ // here you can check also response.statusCode if needed
NSString *serverResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
dispatch_async(dispatch_get_main_queue(), ^{
completion(serverResponse);
});
}else {
dispatch_async(dispatch_get_main_queue(), ^{
completion(nil);
//show some alert about no connection etc
});
}
}] resume];
add completion to your method
- (void) login:(NSString*)username
password:(NSString*)password
completion:(void (^)(NSSring *response))completion
and then compare response in the completion in the loginViewController
[user login:#"aaa" password:#"bbb" completion:^(NSString *response) {
if ([response isEqualToString:#"ccc"]){
// success!
}else{
// alert
}
};

capture a variable content and pass it to a second view controller

I have read so much on the subject of passing variable between ViewController in Xcode I am totally lost.
1:I have a members database on my server which is populated with members details
2: In xcode a have a "ViewController.h and .m" which run code allowing users to authenticate with the members data table on my sever. This works perfectly well, no issues.
What I want to do is capture the "login" and "password" into two variables and use the variables in a second "ViewController".
First ViewController.h:
#interface FirstViewController : UIViewController {
UITextField *txtUsername;
UITextField *txtPassword;
}
#property (nonatomic, retain) IBOutlet UITextField *txtUsername;
#property (nonatomic, retain) IBOutlet UITextField *txtPassword;
- (IBAction)loginClicked:(id)sender;
- (IBAction)backgroundClick:(id)sender;
First ViewController.m
#import "FirstViewController.h"
#import "WebViewController.h"
#import "SBJson.h"
#implementation FirstViewController
#synthesize txtPassword, txtUsername;
- (IBAction)loginClicked:(id)sender {
#try {
if([[txtUsername text] isEqualToString:#""] || [[txtPassword text] isEqualToString:#""] ) {
[self alertStatus:#"Please enter both Username and Password" :#"Login Failed!"];
} else {
NSString *post =[[NSString alloc] initWithFormat:#"login=%#&pass=%#",[txtUsername text],[txtPassword text]];
NSLog(#"PostData: %#",post);
NSURL *url=[NSURL URLWithString:#"http://www.mydomain.com/check1.php"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
//[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
NSError *error = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Response code: %d", [response statusCode]);
if ([response statusCode] >=200 && [response statusCode] <300)
{
NSString *responseData = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"Response ==> %#", responseData);
SBJsonParser *jsonParser = [SBJsonParser new];
NSDictionary *jsonData = (NSDictionary *) [jsonParser objectWithString:responseData error:nil];
NSLog(#"%#",jsonData);
NSInteger success = [(NSNumber *) [jsonData objectForKey:#"success"] integerValue];
NSLog(#"%d",success);
if(success == 1)
{
//NSLog(#"Login SUCCESS");
//[self alertStatus:#"Logged in Successfully." :#"Login Success!"];
WebViewController *second = [[WebViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:second animated:YES];
} else {
NSString *error_msg = (NSString *) [jsonData objectForKey:#"error_message"];
[self alertStatus:error_msg :#"Login Failed!"];
}
} else {
if (error) NSLog(#"Error: %#", error);
[self alertStatus:#"Connection Failed" :#"Login Failed!"];
}
}
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
[self alertStatus:#"Login Failed." :#"Login Failed!"];
}
}
Second ViewController.h
#interface LettoWebViewController : UIViewController {
IBOutlet UIWebView *lettoWebView;
NSString *AmemberUsername;
NSString *AmemberPassword;
}
#property (retain) NSString *AmemberUsername;
#property (retain) NSString *AmemberPassword;
Second ViewController.m
#import "WebViewController.h"
#import "SBJson.h"
#interface WebViewController ()
#end
#implementation WebViewController
#synthesize AmemberPassword, AmemberUsername;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSString *post =[[NSString alloc] initWithFormat:#"login=%#&pass=%#",[AmemberUsername text],[AmemberPassword text]];
NSLog(#"PostData: %#",post);
NSURL *myURL=[NSURL URLWithString:#"http://www.mydomain.com/apps/index.php"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:myURL];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
[lettoWebView loadRequest:request];
}
My questions is; how can I can I pass the two variables in the most simple way.
Any help would be great but please be kind I am very new to xcode and coding in general.
Regards
DJ
The solution:
When you created WebViewController, you just had to set the two parameters.
WebViewController *second = [[WebViewController alloc] initWithNibName:nil bundle:nil];
[second setAmemberUsername:[txtUsername text]];
[second setAmemberPassword:[txtPassword text]];
[self presentModalViewController:second animated:YES];
In your viewDidLoad of the WebViewController:
There was an issue, you wrote:
NSString *post =[[NSString alloc] initWithFormat:#"login=%#&pass=%#",[AmemberUsername text],[AmemberPassword text]];
But, AmemberPassword and AmemberUserName are NSString. So they don't know the text method. They aren's UITextField.
So the correction is:
NSString *post =[[NSString alloc] initWithFormat:#"login=%#&pass=%#",AmemberUsername,AmemberPassword];

How to get an array from NSMutableData

I have text file with 5 strings. I need to use NSURLConnection to get contnent of this file. But NSLog shows me, that 'dump' is empty. How can I transform the data from NSMutableData to NSArray. Arrays is because I need to show those 5 items in a TableView.
NSURLRequest *theRequest=[NSURLRequest
requestWithURL:[NSURL URLWithString:#"http://dl.dropbox.com/u/25105800/names.txt"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
receivedData = [NSMutableData data];
NSString *dump = [[NSString alloc] initWithData:receivedData
encoding:NSUTF8StringEncoding];
NSLog(#"data: %#", dump);
NSArray *outputArray=[dump componentsSeparatedByString:#"\n"];
self.namesArray = outputArray;
Thanks in advance. BTW URL works, you can see the file.
Here's how you implement this solution with a delegate:
In your .h file:
#interface MyClass : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
#property (nonatomic, retain) NSMutableData *receivedData;
#property (nonatomic, retain) NSArray *namesArray;
#end
In you .m file:
#implementation MyClass
#synthesize receivedData = _receivedData;
#synthesize namesArray = _namesArray;
- (id)init {
self = [super init];
if (self) {
self.receivedData = [NSMutableData data];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://dl.dropbox.com/u/25105800/names.txt"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
[connection start];
}
return self;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"Received response! %#", response);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *dump = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding];
NSLog(#"data: %#", dump);
self.namesArray = [dump componentsSeparatedByString:#"\n"];
}
#end
If you don't want to use a delegate, you can use a synchronous call with NSURLConnection, like this:
NSURLRequest *theRequest=[NSURLRequest
requestWithURL:[NSURL URLWithString:#"http://dl.dropbox.com/u/25105800/names.txt"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSError *error = nil;
NSHTTPURLResponse *response = nil;
NSData *receivedData = [NSURLConnection sendSynchronousRequest:theRequest response:&response error:&error];
if (error == nil) {
NSString *dump = [[NSString alloc] initWithData:receivedData
encoding:NSUTF8StringEncoding];
NSLog(#"data: %#", dump);
NSArray *outputArray=[dump componentsSeparatedByString:#"\n"];
self.namesArray = outputArray;
}
Just beware that this will not be running asynchronously. If you don't want it to run on the main thread and block your main thread/UI, consider using a separate thread to execute that code or use GCD.
You have to use the delegate, then save the received data into receivedData (which is of course empty right now.. you just initalized it.) and then you transform the data into a string, like you did it in your example. Have a look at NSURLConnectionDelegate
You need to implement the delegate methods for NSURLConnection to be notified of incoming data. You are using the asynchronous methods.
Also note that [NSMutableData data] just creates an empty data-object.. so you can't expect it to contain any data..
I suggest you read https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html#//apple_ref/doc/uid/20001836-BAJEAIEE
(completely!)

How can I load an HTML file?

How do I load an HTML file into my app (xcode)? I'm using the following code:
- (void)viewDidLoad
{
[super viewDidLoad];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"index" ofType:#"html"]isDirectory:NO]]];
}
When I start the app, I only see a white page. What's wrong?
.h file:
#import <UIKit/UIKit.h>
#interface poules : UIViewController {
IBOutlet UIWebView *webView;
}
#property (nonatomic,retain) UIWebView *webView;
#end
Here is a working example from one of my projects. My index.html file is in a folder called Documentation/html in the resources directory. Its important to note that these are "folder references", not groups (hence the blue icon):
then to load it in a webView:
NSString *resourceDir = [[NSBundle mainBundle] resourcePath];
NSArray *pathComponents = [NSArray arrayWithObjects:resourceDir, #"Documentation", #"html", #"index.html", nil];
NSURL *indexUrl = [NSURL fileURLWithPathComponents:pathComponents];
NSURLRequest *req = [NSURLRequest requestWithURL:indexUrl];
[webView loadRequest:req];
try loadHTMLString:baseURL: method
NSString *html=[NSString stringWithContentsOfFile:your_html_path encoding:NSUTF8StringEncoding error:nil];
[webview loadHTMLString:html baseURL:baseURL];
First thing you can check whether your webView is connected or not.
If it is then, you can break down your code to check what is wrong with request that you are trying to load.
1.. Create a NSString for the file path like this, and check if the path is returned or not.
NSString *urlString = [[NSBundle mainBundle] pathForResource:#"index" ofType:#"html"];
2.. Create a NSURL from the above string like this, and check if the url is correct or nil.
NSURL *url = [NSURL URLFromString:urlString];
3.. And then create the request.
NSURLRequest *request = [NSURLRequest requestFromURL:url];