AFNetworking 2.0 JSON Vulnerability Protection - ios

i'm using AFNetworking 2.+ in my iOS app,
my server uses JSON Vulnerability Protection.
that makes my requests to the server "Half working".
meaning, i do get code 200 for my requests, but the request fails.
i can't parse the json.
I'm using AFHTTPRequestOperationManager and i set his Serializers like that:
[self setResponseSerializer:[AFJSONResponseSerializer serializer]];
[self setRequestSerializer:[AFJSONRequestSerializer serializerWithWritingOptions:NSJSONWritingPrettyPrinted]];
i also tried that:
[self setResponseSerializer:[AFJSONResponseSerializer serializer]];
[self setRequestSerializer:[AFJSONRequestSerializer serializer]];
didnt worked as well.
as far as i can tell, JSON Vulnerability Protection adds ")]}'," before the real json, as shown here in angular docs
JSON Vulnerability Protection A JSON vulnerability allows third party
website to turn your JSON resource URL into JSONP request under some
conditions. To counter this your server can prefix all JSON requests
with following string ")]}',\n". Angular will automatically strip the
prefix before processing it as JSON.
For example if your server needs to return:
['one','two']
which is vulnerable to attack, your server can return:
)]}', ['one','two']
is there any way to handle that with the provided tools AFNetworking gives me?
Should i use a custom AFJSONRequestSerializer?
Thanks,
Shahar.

Answering my own...
i implemented
and added that method:
-(id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error{
NSString * jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (jsonString && [jsonString hasPrefix:#")]}',"]) {
jsonString = [jsonString substringFromIndex:#")]}',".length];
}
NSData *newData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
return [NSJSONSerialization JSONObjectWithData:newData options:0 error:nil];
}
That fixed that.

Related

how to turn AFNetworking GET request to soap web service request?

The project I'm working on have using AFHTTPRequestOperation to retrieve data from the web service using the down below method but now the company want to change this method and make it a soap request can i modify the current code the project have more than 100 class and so advanced and I'm still beginner can any one help me 2 modify the code to use the soap request and accept the soap message and requests with a simple edit or something plz ,this is the code that exist :
NSString *path = [NSString stringWithFormat:#"*********?mobile=%#&email=%#",mobile,email];
[self.operationManager GET:path parameters:nil success:^void(AFHTTPRequestOperation * operation, id responseObject) {
} failure:^void(AFHTTPRequestOperation * operation, NSError * error) {
}];
I have tried to follow the answer on (How can you use AFNetworking or STHTTPRequest to make a request of a SOAP web service?) but in the part where i call it in the other class that i need to use it in this error showed (No known class method for selector 'dictionaryForNSXMLParser:'). i found the problem i didn't call
NSDictionary *dict = [XMLReader dictionaryForNSXMLParser:parser error:nil];
but he did the same ,he used
NSDictionary *dict = [XMLReader dictionaryForNSXMLParser:parser];but while running the app it crashed in XMLReader.m class on this line
self.errorPointer = *error;
XMLReader *reader = [[XMLReader alloc] initWithError:error];
ther error is EC_Bad_Access.

iOS: How would a put request work in this scenario?

I am using AFNetworking and trying to figure out how to use PUT requests properly. This is what the API document has given me (just an easy example).
curl -X PUT -d '{"problem":[{"problem":"text"}]}'
"https://api.website.com/form?apiKey={apiKey}"
Params is
'{"problem":[{"problem":"text"}]}' while urlStr is https://api.website.com/form?apiKey={apiKey} If you need any more information please let me know.
Here is my put request being executed.
- (void) executePutRequest : (NSString *) url params : (NSString *) params
{
NSString *urlStr = [NSString stringWithFormat:#"%#?apikey=%#", url,apiKey];
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:
NSASCIIStringEncoding];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager PUT:urlStr parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
[operation setUserInfo:userinfo];
SBJsonParser *jsonparser = [SBJsonParser new];
id result = [jsonparser objectWithString:[operation responseString]];
if ( self.delegate != nil && [self.delegate respondsToSelector:finishSelector] ) {
[self.delegate performSelector:finishSelector withObject:result];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[operation setUserInfo:userinfo];
if ( self.delegate != nil && [self.delegate respondsToSelector:failSelector] ) {
[self.delegate performSelector:failSelector withObject:[operation error]];
}
}];
}
What am I doing wrong? I am getting a 400 error (bad request). This is what my log looks like.
Error Domain=com.alamofire.error.serialization.response Code=-1011 "Request failed: bad request (400)" UserInfo=0x7aee9a40 {com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x7aeea400>
AFNetworking is meant to do some of the redundant work for you, including serializing and deserializing output to server and input from server respectively. Your code implies that you are trying to do it manually, too, which is incorrect.
You have params set to be an NSString *. Just pass it the NSDictionary * it expects. e.g. NSDictionary *params = #{ #"problem": #[ #{ #"problem": #"text" }]};, from your example.
If you enter the success block, then responseObject should be deserialized into the format you have configured. IIRC, the default response format is JSON -- but look it up. You don't need to further process the response -- it's been done for you. For example, if the JSON body is something like { "cat": { "says": "meow" } }, then simply cast the object to an NSDictionary; e.g. NSDictionary *catDict = (NSDictionary *)responseObject;
Did you or your team write the web service? Do you know what the expected request and response format is?
If you have to further configure the request and response serializers, you can do so in your manager's constructor (so subclass the manager, and make your own). For e.g,
[self setRequestSerializer:[AFJSONRequestSerializer serializer]];
[self setResponseSerializer:[AFJSONResponseSerializer serializer]];
... would configure the client to send JSON to the server, and expect JSON back from the server.

Force app to wait for method completion (data download)

I'm working with an app that requests data from an OAuth2.0 protected server. When I use the GTM OAuth Library to retrieve data, the program continues to run while the data is being downloaded in the background. I need some sort of mechanism to either force my application to wait until the didFinishWithData selector is called,or I need a way to notify my ViewController of the download's completion, so I can then utilize the data immediately.
I've tried conditional blocks, but those aren't doing it for me. I've also tried polling the object whose data I'm interested in, but if I do that, the data never seems to download. I've heard I can somehow utilize the Notification Center to accomplish this task, so I'll look more into that while I'm waiting for replies here.
Here is basically what is going on:
-(void) getAlert{
// Define the URL of the API module we'd like to utilize.
NSURL *url = [[NSURL alloc] initWithString:#"https://access.active911.com/interface/open_api/api/alerts"];
// Constructs a an HTTP request object to send to the server in order to obtain data.
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setValue:#"1" forHTTPHeaderField:#"alert_days"];
// This fetcher sends the request along with the authentication header in a recognizable manner.
GTMHTTPFetcher *fetcher = [[GTMHTTPFetcher alloc] initWithRequest:request];
// Attach the OAuth credentials for the fetcher's use.
[fetcher setAuthorizer:auth];
// Execute the operation.
[fetcher waitForCompletionWithTimeout:10];
NSLog(#"About to get alert");
[fetcher beginFetchWithDelegate:self didFinishSelector:#selector(responseHandler:finishedWithData:finishedWithError:)];
NSLog(#"got alert");
}
-(void)responseHandler:(id)valueNotUsed finishedWithData:(NSData *)data finishedWithError:(NSError *)error{
// Retrieve the server data in a usable object
// All that's being done here is conversion to an NSDictionary
// followed by the creation of subdictionaries from that dictionary
// until our final value can be picked directly out of the resulting dict
NSData *jsonData = [[NSData alloc] initWithData:data];
NSError *dictError;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:jsonData //1
options:kNilOptions
error:&dictError];
NSDictionary *token = [json objectForKeyedSubscript:#"message"];
NSArray *alerts = [token objectForKeyedSubscript:#"alerts"];
NSDictionary *alertData = alerts[0];
mapCode = [alertData objectForKeyedSubscript:#"map_code"];
NSString *city = [alertData objectForKeyedSubscript:#"city"];
NSLog(#"Map code: '%#' with city '%#' and access token %#", mapCode, city, accessToken);
}
And I need to pass the mapCode to my view controller.
Thanks for the help!
First off, please rethink about having the UI halt while you fetch results from the server. This can create an extremely bad UX for the app and only should be done if absolutely necessary.
Second, does your responseHandler method work? And do you only need mapCode in the VC that responseHandler is in?
If so, you don't even need to use Notifications. Simply do:
-(void)responseHandler:(id)valueNotUsed finishedWithData:(NSData *)data finishedWithError:(NSError *)error{
...
...
mapCode = [alertData objectForKeyedSubscript:#"map_code"];
[self updateVCWithMapCode:mapCode];
}
That will call the method after the response has been received. Passing it explicitly too so you don't need to have mapCode be a property as well.

RestKit post request parameter MIMEType

I'm working on an iOS app that was implement in RestKit .10 and am updating it to .20. One of the post requests the app makes has a block of data as a parameter. Previously, the app encoded this use RKParam setData:MIMEType:forParam; I'm looking for the .20 version of this for adding a parameter to a NSMutableDictionary parameter.
Old code:
NSString *logString; // loaded up elsewhere
NSData *textFileContentsData = [logString dataUsingEncoding:NSUTF8StringEncoding];
RKParams *params = [RKParams params];
[params setData: textFileContentsData MIMEType:#"text/plain" forParam:#"log_file"];
New code:
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
[parameters setObject:???? forKey:#"log_file"]; // not sure how to get string here.
I have tried putting the textFileContentsData NSData object in for ???? but the data arrives in binary, which is not what is required. I need to figure out how to retain the text/plain MIMEType.
TIA
Janene
From your description I wouldn't use RestKit for this as there is no mapping going on, I'd use AFNetworking instead (vehicular is included in RestKit so you already have full access).
Using RestKit, you would use the object manager to create a request to send, something like:
NSMutableURLRequest *request =
[objectManager multipartFormRequestWithObject:nil
method:RKRequestMethodPOST
path:#"..."
parameters:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFormData:...
name:#"..."];
}];
Then you could use RKObjectRequestOperation to process the request. But I'm not convinced this is exactly what you need if you just want to set the mime type (just a header) and the post data, both of which can be done directly on NSMutableURLRequest.

Google Places API Autocomplete on iOS

Over the last few days I've been struggling to get Google Places autocomplete to work on my app, and no matter what I do, I always get the REQUEST_DENIED error.
I followed Google's "tutorial" for the implementation, Places API is enabled, API key has the correct bundle ID, I also tested with a Browser ID, with no success.
I am pretty sure it has something to do with the key, though. Curiously, on the Android version of the app, the service will work with the Browser Key. And on the browser, obviously, it works with that key too.
These are the two keys I experimented with:
And this is my implementation code, using AFNetworking:
NSURL *url = [NSURL URLWithString:#"https://maps.googleapis.com/maps/api/place/autocomplete/"];
NSDictionary *params = #{#"input" : [input stringByReplacingOccurrencesOfString:#" " withString:#"+"],
#"location" : [NSString stringWithFormat:#"%f,%f", searchCoordinate.latitude, searchCoordinate.longitude],
#"sensor" : #(true),
// #"language" : #"pt_BR",
// #"types" : #"(regions)",
// #"components" : #"components=country:br",
#"key" : GOOGLE_API_KEY};
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
[httpClient setParameterEncoding:AFFormURLParameterEncoding];
[httpClient getPath:#"json"
parameters:params
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary *JSON = [[NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:nil] dictionaryWithoutNulls];
if (completion) {
completion(JSON[#"predictions"]);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *errorResponse) {
NSLog(#"[HTTPClient Error]: %# for URL %#", [errorResponse localizedDescription], [[[operation request] URL] path]);
}];
I know there are some questions like this one here, but some are old, and say that Places API does not work on Android or iOS, which clearly is not the case anymore, since Google itself publishes examples on both platforms, as seen on Places API page: https://developers.google.com/places/documentation/autocomplete
A workaround I'm currently using is Apple's GeoCoding system, which works good when you type the full address, but is terrible with half-typed phrases. This is not good at all, I'd really like to use Google's API.
I got it!
The paramenter sensor should receive either #"true"or #"false", and not #(true)or #(false).
For the record, the API key used is indeed the Browser Key, and not an iOS key.
You should init httpClient with base URL #"https://maps.googleapis.com/" and get path /maps/api/place/autocomplete/json. Base URL - host only, it does not take other parts of path, so in your case you get request to URL "https://maps.googleapis.com/json".
https://maps.googleapis.com/maps/api/geocode/json?address="%#","%#"&sensor=false,yourAddress,your c

Resources