How to get friends profile picture from gmail contacts? - ios

I'm trying to import GMail contacts (friends list). I have got friends' mail id, name, and phone number, but if I tried to get the images it says "401 error".
The code I have used is as follows:
GDataLink *photoLink = [contact photoLink];
NSLog(#"%#",photoLink);
NSURL *imageURL = [photoLink URL];
NSLog(#"image url = %#",imageURL);
How can I get friends' profile picture? Where did I go wrong?

Looking at some other (public) code that's roughly the same as what you're doing, I see that you should be using an auth token with these photo links. Without that auth token, Google assumes you might be malicious and will send back a 401 error.
E.G.
GDataLink *photoLink = [contact photoLink];
NSString *imageETag = [photoLink ETag];
if (imageETag == nil || ![mContactImageETag isEqual:imageETag]) {
if (imageETag != nil) {
// get an NSURLRequest object with an auth token
NSURL *imageURL = [photoLink URL];
GDataServiceGoogleContact *service = [self contactService];
// requestForURL:ETag:httpMethod: sets the user agent header of the
// request and, when using ClientLogin, adds the authorization header
NSMutableURLRequest *request = [service requestForURL:imageURL
ETag:nil
httpMethod:nil];
[request setValue:#"image/*" forHTTPHeaderField:#"Accept"];
GTMHTTPFetcher *fetcher = [GTMHTTPFetcher fetcherWithRequest:request];
[fetcher setAuthorizer:[service authorizer]];
[fetcher beginFetchWithDelegate:self
didFinishSelector:#selector(imageFetcher:finishedWithData:error:)];
}
}
}

Related

How to set pass api key within NSURLRequest in iOS?

as of now I have it like so:
NSURLRequest *Request = [NSURLRequest requestWithURL:[NSURL URLWithString: reqURLStr]];
NSURLResponse *resp = nil;
NSError *error = nil;
NSData *response = [NSURLConnection sendSynchronousRequest: Request returningResponse: &resp error: &error];
NSString *responseString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
return responseString;
and I call it like so:
NSString *stripeCustomerRequestURL = [NSString stringWithFormat:#"https://api.stripe.com/v1/customers/%#",stripeCustomerId];
// NSString for the return of the tax in decimal form
NSString *customerInformation = [self retrieveStripeCustomer:stripeCustomerRequestURL];
I am getting this error which I know I need to pass the api key but how can I?
{
"error": {
"type": "invalid_request_error",
"message": "You did not provide an API key. You need to provide your API key in the Authorization header, using Bearer auth (e.g. 'Authorization: Bearer YOUR_SECRET_KEY'). See https://stripe.com/docs/api#authentication for details, or we can help at https://support.stripe.com/."
}
}
It is not considered secure to be using your Stripe Secret API key from code that runs on a client device (iOS / Android apps, desktop apps, etc). As soon as you include your API key in a shipped binary, you can assume someone will inspect your binary and be able to extract the strings from it, including your API key thus compromising it.
Your API key should only be used on a server that you control. Your iOS app can call endpoints on your server and in turn your server will call out to Stripe.

Graph API with App Token for Page not working

I'm developing an app with Login with Facebook and also Login with username and password.
Now i want to find all the events of a public page on Facebook for both the types of users (Facebook and Normal).
The problem is that the User with Facebook can retrieve the data, but the "normal" user cannot because data is nil.
The steps are :
1 - Compile this url with the correct credential of my Facebook App :
https://graph.facebook.com/oauth/access_token?client_id=APP_ID&client_secret=APP_SECRET&grant_type=client_credentials
2 - Put the url in my browser and retrieve the App Token In the format :
53682XXXXXXXXXX|w6F3Ic6L48XXXXXXXXXXXXXXXXX
3 - Use this piece of code :
NSString *token = [[[FBSession activeSession] accessTokenData] accessToken];
NSString *urlString;
if (!userWithFb) {
NSString *token = #"53682XXXXXXXXXX|w6F3Ic6L48XXXXXXXXXXXXXXXXX";
urlString = [NSString stringWithFormat:#"https://graph.facebook.com/%#/events?access_token=%#", pageId,token];
}else{
urlString = [NSString stringWithFormat:#"https://graph.facebook.com/%#/events?access_token=%#", pageId,token];
}
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
if(data != nil)
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES];
BUT the data for the normal user is nil. When I put the "urlstring" in my browser I see all the data , I don't know where is the problem. Waiting for solution I say thanks.
I solved my question by adding this piece of code after the if statement :
NSString *encodedURLString = [urlString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
url = [NSURL URLWithString:encodedURLString];
NSData* data = [NSData dataWithContentsOfURL:url];
The Problem is the "|" in the token, it must be replaced with "&".
Hope this help you !

AFNetworking 2 Upload Plist Data to Apache Server

I am writing a sample app to test how AFNetworking can be used as a replacement for ASIHTTPLib.. The old library made it simple to upload a file to an Apache server (provided the user has write access to a URL/directory). No other server side support is used..
This code has some problem, but I have not pinpointed it: executing the method reports an upload success, but the plist file on the cloud side does not changeā€¦
-(void)uploadReminders:(NSArray*)reminders
{
NSLog(#"AppDelegate Synch Reminders to cloud");
//NSLog(#"Data: %#", reminders);
[self persistReminders:reminders atCustomPath:nil];
NSString *cacheDirectoryPath = [self cachesDirectoryPath];
NSString *urlString = [NSString stringWithFormat:#"%#/%#",kStandardCloudAreaAccessURL,kStandardLocalCachePlistFile];
//NSLog(#"URL: %#", urlString);
NSString *remindersPlistFile = [NSString stringWithFormat:#"%#/%#",cacheDirectoryPath,kStandardLocalCachePlistFile];
//NSLog(#"Filepath: %#",remindersPlistFile);
NSURLCredential *defaultCredential = [NSURLCredential credentialWithUser:kStandardCloudAreaAccessUsername password:kStandardCloudAreaAccessUserPW persistence:NSURLCredentialPersistenceNone];
/**/
NSURL *url = [NSURL URLWithString:urlString];
NSString *host = [url host];
NSInteger port = [[url port] integerValue];
NSString *protocol = [url scheme];
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:host port:port protocol:protocol realm:nil authenticationMethod:NSURLAuthenticationMethodHTTPBasic];
NSURLCredentialStorage *credentials = [NSURLCredentialStorage sharedCredentialStorage];
[credentials setDefaultCredential:defaultCredential forProtectionSpace:protectionSpace];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
[configuration setURLCredentialStorage:credentials];
[configuration setHTTPAdditionalHeaders: #{#"Accept": #"text/plain"}];
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
[manager.securityPolicy setAllowInvalidCertificates:YES];
manager.responseSerializer = [AFPropertyListResponseSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"text/plain"];
NSURL *URL = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURL *filePath = [NSURL fileURLWithPath:remindersPlistFile];
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromFile:filePath progress:nil completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(#"Upload Error: %#", error);
} else {
//NSLog(#"Upload Success");
NSLog(#"Upload Success: %# %#", response, responseObject);
}
}];
[uploadTask resume];
}
The console shows this:
Upload Success: <NSHTTPURLResponse: 0x8d4ec50> { URL: https://[.....]/CodeTests/Reminders/Reminders.plist } { status code: 200, headers {
"Accept-Ranges" = bytes;
Connection = "Keep-Alive";
"Content-Length" = 1324;
"Content-Type" = "text/plain";
Date = "Mon, 10 Mar 2014 14:48:13 GMT";
Etag = "\"3f06e5-52c-4f430180dae80\"";
"Keep-Alive" = "timeout=5, max=100";
"Last-Modified" = "Sun, 09 Mar 2014 17:48:26 GMT";
Server = "Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/0.9.7l DAV/2";
} } {
reminders = (
{
completed = 1;
created = "2014-03-09 17:47:41 +0000";
description = "";
title = Reminder;
updated = "2014-03-09 17:47:41 +0000";
},
{
completed = 1;
created = "2014-03-08 09:47:58 +0000";
description = "Orza!!! Ma orza in fretta... Ah: funziona? Ebbene, s\U00ec! O no?\n";
title = "Reminder Orza";
updated = "2014-03-08 11:39:43 +0000";
},
{
completed = 0;
created = "2014-03-07 11:09:59 +0000";
description = "Whatever you like; and of course you can even make it quite long.\n\nYeooww..\nReally long!\n\n\n\n";
title = "Reminder A";
updated = "2014-03-08 11:34:24 +0000";
}
);
version = "1.0";
}
The only catch is that when I reopen the app, it jumps back to the test reminders I did manually put on the server: the Reminders.plist gets never changed.
Thanks!
I'm assuming your NSLog of the responseObject is confirming that the plist was successfully received by the server. If so, then that may eliminate the above "upload" code as the source of the problem. You may want to inspect the data on your server (not through the app, but manually inspect it yourself) and see whether your new list of reminders is there or not. It seems that there a couple of possible logical possibilities:
If the updated data is not there, then look at your server's "save" logic, as it would appear to be failing.
If it is there, then you should look at your client's "retrieve" logic. I wonder, for example, if your app is caching the responses to its requests, and thus when you attempt to download again, perhaps you're getting the cached original response. I'd try turning off caching.
In these cases, a tool like Charles can be useful, where you can inspect the requests and responses that you're getting. That can be helpful in narrowing down precisely where the problem is occurring.
Taking a closer look at your request, I notice that you're not specifying the request type. I would have thought that your request would be a POST:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
[request setHTTPMethod:#"POST"];
[request setValue:#"text/plain" forHTTPHeaderField:#"Accept"]; // I'd also personally set the `Accept` here at the request, not at the `NSURLSessionConfiguration`
Having said that, given that your web service is successfully reporting your plist data back at you, I would have inferred that it successfully received it on the basis of the evidence you shared with us thus far. But maybe the failure to make the request a POST request means that the web service concluded it didn't need to save anything.
Generally, when interfacing with a web service, rather than tweaking the request, like I have above, I'd encourage you to post data using one of the standard AFHTTPSessionManager variations of the POST method (one is for multipart/form-data requests, the other is for other requests). But I can't figure out what your server is doing on the basis of what you've provided thus far (e.g. it makes no sense that the server is sending the body of your request back to you at all; it makes no sense that the server would appear to have received your request, but doesn't do anything with it and doesn't report some error; etc.). So maybe try making the request a POST request and see if that fixes it. If not, run Charles on your old ASIHTTP source code, and you'll see precisely what the old request looks like and you should be able to reproduce it with AFNetworking.

How do I set up and implement HTTP method for authorization?

I'm trying to get into a webAPI my classmate created with my iphone APP I've created. Right now, it connects, but my app just crashes because it tells me that I need authorization. So if for example, the username is abc and password abc123, How would I implement the HTTP method specifically to get passed authorization??
NSString *geturl = #"http://192.168.1.96:50364/api/transaction" ;
setValue:(NSString*)" " forHTTPHeaderField:(NSString*)username;
getjson *mds=[[getjson alloc] init];
SEL selector = #selector(addData:);
[mds setDirectionsQuery:geturl
withSelector:selector
withDelegate:self];
Edit: if the above problem is too confusing, what is the basic syntax/code for setting up the value and the key for username and password? I am sure
setValue:(NSString*)"abc " forHTTPHeaderField:(NSString*)username;
setValue:(NSString*)"abc123 " forHTTPHeaderField:(NSString*)password;
is not correct. compiler is not letting me run the program.
Your strings are missing #
Try setValue:(NSString*)#"abc " forHTTPHeaderField:(NSString*)username; although if the code you pasted is complete, it doesn't say what your setting values to.
I personally use NSMutableRequest and create the request and authorisation like this. Note that the auth gets Base64 encoded:
NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:_urlString]];
NSString *basicAuthCredentials = [NSString stringWithFormat:#"%#:%#", username, password;
NSString *authValue = [NSString stringWithFormat:#"Basic %#", AFBase64EncodedStringFromString(basicAuthCredentials)];
[urlRequest setValue:authValue forHTTPHeaderField:#"Authorization"];

Using NSURLCredentialPersistenceForSession while request and then clearing the credentials on logout still persist the cerdentials

I am using NSURLCredentialPersistenceForSession within didReceiveAuthenticationChallenge of NSURLConnection delegate method while login.
Now when I logout and use this code for clearing the storage..
NSURLCredentialStorage *credentialStorage = [NSURLCredentialStorage sharedCredentialStorage];
NSDictionary *credentialsDicationary = [credentialStorage allCredentials];
NSLog(#"credentialsDicationary..%#",[credentialsDicationary description]);
for (NSURLProtectionSpace *space in [credentialsDicationary allKeys]) {
NSDictionary *spaceDictionary = [credentialsDicationary objectForKey:space];
NSLog(#"spaceDictionary..%#",[spaceDictionary description]);
for (id userName in [spaceDictionary allKeys]) {
NSURLCredential *credential = [spaceDictionary objectForKey:userName];
[credentialStorage removeCredential:credential forProtectionSpace:space];
}
}
But when I suddenly login again exactly after logout the login happens with wrong credentials. Please let mw know how to clear the cache. It works if I relogin after some 5 secs of time.
Thanks in advance..
AJ
If you're using NSURLSession, invalidate the session and create a new one, e.g.:
[self.session invalidateAndCancel];
self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
This will clear session-scoped credentials.
If you use NSURLCredentialPersistenceForSession to create the credential then the app stores the credential for the entire session until the app is closed.
You can work around this by either:
changing the url (like appending '#' to the end of the url)
Use NSURLCredentialPersistenceNone and provide the credentials with each nsurlrequest
Append auth info to the url (http://username:password#mywebsite.com), instead of using creds
Append auth info to the request header, instead of using creds
//Pseudo code for appending to header:
NSString *authString = [NSString stringWithFormat:#"%#:%#", self.loginCreds.username, self.loginCreds.password];
NSData *stringData = [authString dataUsingEncoding:NSUTF8StringEncoding];
authString = [NSString stringWithFormat:#"Basic %#", [stringData base64EncodedString]];
[[self requestHeader] setValue:authString forHTTPHeaderField:#"Authorization"];
It's possible to remove the credential but it can take minutes before it is actually removed. However, I don't remember how its done.. It's either done the way you mentioned in the question or through the keychain.
I had the same issue and I tried clear the credential storage, cookies associated with url and even trying to reset the session but nothing seemed to work, finally I just resorted to adding a a random query string value to the end of the url and that did the trick for me
// Random number calculated.
NSInteger randomNumber = arc4random() % 16;
NSURL* apiURL = [NSURL URLWithString:#"https://localhost/api/"];
[[RKObjectManager sharedManager] getObjectsAtPath:[NSString stringWithFormat:#"%#getUser?randomNumber=%d",apiURL,randomNumber]
parameters:nil
success:successBlock
failure:failureBlock];
So instead of trying to remove current cached credentials (which seemed impossible) just use a "fresh" url so there aren't any cached objects associated with it.
I was facing the same problem, now it works.
Using NSURLConnection this issue can be fixed easily by adding a random number to the end of the URL:
So, search for your URLRequest and append the random number to URLRequest
NSInteger randomNumber = arc4random() % 999;
NSString *requestURL = [NSString stringWithFormat:#"%#?cache=%ld",yourURL,(long)randomNumber];
NSURL *URLRequest = [NSURL URLWithString:requestURL];
And make sure you have a random number at the end of all URLs you are calling.

Resources