I Face a big problem,I made a VPN for IOS Devices,it is on the appstore,it is working nicely,However i face problem with macos application,I use same codes.Same codes work for IOS Devices however they dont work for MacOS application.
The Problem says ;
No VPN shared secret was provided. Verify your settings and try reconnecting.
When i try to connect to vpn.
Code that i use for connect vpn
[[NEVPNManager sharedManager] loadFromPreferencesWithCompletionHandler: ^(NSError *error) {
NEVPNProtocolIPSec *p = [[NEVPNProtocolIPSec alloc] init];
p.serverAddress =ipAddress;
p.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret;
NSLog(#"vpn connecting to ip %#",ipAddress);
p.username=#"vpnuser";
p.sharedSecretReference = [KeyChainHelper load:sharedSecret];
p.passwordReference = [KeyChainHelper load:password];
// NSData * data = [self searchKeychainCopyMatching:sharedSecret];
p.disconnectOnSleep = NO;
[NEVPNManager sharedManager].protocolConfiguration=p;
NSMutableArray *rules = [[NSMutableArray alloc] init];
NEOnDemandRuleConnect *connectRule = [NEOnDemandRuleConnect new];
[rules addObject:connectRule];
[[NEVPNManager sharedManager] setOnDemandRules:rules];
[[NEVPNManager sharedManager] setLocalizedDescription:#"VPN Fire"];
[[NEVPNManager sharedManager] setEnabled:YES];
[[NEVPNManager sharedManager] saveToPreferencesWithCompletionHandler: ^(NSError *error) {
NSLog(#"Save VPN to preference complete");
if (error) {
NSLog(#"Save error: %#", error);
}
NSError *startError;
[[NEVPNManager sharedManager].connection startVPNTunnelAndReturnError:&startError];
delayStart(5)
NSLog(#"%#",[NEVPNManager sharedManager]);
NSLog(#"%#",[NEVPNManager sharedManager]);
delayEnd
if(startError) {
NSLog(#"Start error: %#", startError.localizedDescription);
}
}];
}];
Here i put some screenshoots;
Looks like KeyChainHelper is a wrapper for accessing the keychain. It isn't clear exactly what the KeyChainHelper::load() method returns, but my guess is either a standard reference or data.
NEVPNProtocolIPSec::sharedSecretReference is defined as:
A persistent keychain reference to a keychain item containing the IKE shared secret.
You need to create a keychain item of type kSecClassGenericPassword to use as the shared secret, and provide a persistent reference to the keychain item. A persistent reference is critical here, as it can be stored to disk or passed between processes, which is required for NEVPNManager to access the shared secret and connect your VPN. Likewise for passwordReference.
You will need to use SecItemCopyMatching with return type kSecReturnPersistentRef to achieve this. Your KeyChainHelper class may provide a method to return the persistent reference.
Related
I am trying to add Google Drive support to one of my apps using a private app data folder. I have sign-in working with the GIDSignIn class and the scope set to kGTLRAuthScopeDriveAppdata. Once I am signed in, I can create folders and get a file listing that shows the folders are there, then I can delete the folders and the file listing shows that they are gone. But for some reason when I try to upload a file I get a 403 error ("The user does not have sufficient permissions for this file."). This happens whether I try to put the file in the root of the app data folder or into a folder I have created.
I have set up a project in the Google Developer Console. I have an API key configured to work with my app's bundle ID and given it unrestricted API access. The Google Drive API is enabled.
My code is adapted from Google's own samples so a lot of this may look quite familiar. I've trimmed down the sign-in handling since that appears to be working fine.
- (instancetype) init
{
self = [super init];
if (!self) return nil;
[GIDSignIn sharedInstance].clientID = (NSString *)kGoogleClientId;
//kGoogleClientId is the ID from the developer console.
[GIDSignIn sharedInstance].delegate = self;
[GIDSignIn sharedInstance].scopes = #[kGTLRAuthScopeDriveAppdata];
return self;
}
//GIDSignInDelegate method
- (void) signIn:(GIDSignIn *)signIn didSignInForUser:(GIDGoogleUser *)user withError:(NSError *)error
{
authenticatedUser = user; //authenticatedUser is an instance variable
NSLog(#"Signed in to Google Drive with user %#", user.profile.name);
[delegate GoogleDriveDidSignIn:self];
}
- (GTLRDriveService *) driveService
{
static GTLRDriveService *service;
static dispatch_once_t onceToken;
dispatch_once(&onceToken,
^{
service = [[GTLRDriveService alloc] init];
service.APIKey = (NSString *)kGoogleApiKey;
//kGoogleApiKey matches the developer console too. It has unrestricted API access and is tied to my bundle ID
service.APIKeyRestrictionBundleID = [[NSBundle mainBundle] bundleIdentifier];
service.shouldFetchNextPages = YES;
service.retryEnabled = YES;
});
service.authorizer = authenticatedUser.authentication.fetcherAuthorizer;
//authenticatedUser is an instance variable which stores the user information returned by
//GIDSignIn when the user signs in
return service;
}
- (void) createFolderNamed:(NSString *)folderName completionHandler:(void(^)(NSString *foldername, NSString *newFolderId))completionHandler
{
GoogleDriveHandler * __weak weakself = self;
GTLRDriveService *service = [self driveService];
GTLRDrive_File *folder = [GTLRDrive_File object];
folder.name = folderName;
folder.mimeType = (NSString *)kMimeType_GoogleDriveFolder;
folder.parents = #[#"appDataFolder"];
GTLRDriveQuery_FilesCreate *query = [GTLRDriveQuery_FilesCreate queryWithObject:folder uploadParameters:nil];
[service executeQuery:query completionHandler:^(GTLRServiceTicket * _Nonnull callbackTicket, id _Nullable object, NSError * _Nullable callbackError)
{
if (callbackError)
{
NSLog(#"-createFolderNamed: callbackError: %#", callbackError.localizedDescription);
}
else
{
GTLRDrive_File *createdFolder = (GTLRDrive_File *)object;
if ( [createdFolder.mimeType isEqualToString:(NSString *)kMimeType_GoogleDriveFolder] )
{
NSLog(#"Google Drive created folder named \"%#\" with identifier \"%#\" and mime-type \"%#\"", createdFolder.name, createdFolder.identifier, createdFolder.mimeType);
}
else
{
NSLog(#"Error : Attempted to create folder, but Google Drive created item named \"%#\" with identifier \"%#\" and mime-type \"%#\"", createdFolder.name, createdFolder.identifier, createdFolder.mimeType);
}
}
}];
}
- (void) writeFileAtUrl:(NSURL *)source toFolderWithId:(NSString *)folderId completionHandler:(void(^)(NSString *filename, NSString *newFileId))completionHandler
{
GoogleDriveHandler * __weak weakself = self;
GTLRDriveService *service = [self driveService];
GTLRDrive_File *file = [GTLRDrive_File object];
file.name = source.lastPathComponent;
file.mimeType = #"binary/octet-stream";
file.parents = #[folderId];
file.spaces = #[#"appDataFolder"];
GTLRUploadParameters *parameters = [GTLRUploadParameters uploadParametersWithFileURL:source MIMEType:#"binary/octet-stream"];
parameters.shouldUploadWithSingleRequest = YES;
GTLRDriveQuery_FilesCreate *query = [GTLRDriveQuery_FilesCreate queryWithObject:file uploadParameters:parameters];
query.fields = #"id";
[service executeQuery:query completionHandler:^(GTLRServiceTicket * _Nonnull callbackTicket, id _Nullable object, NSError * _Nullable callbackError)
{
if (callbackTicket.statusCode == 200)
{
GTLRDrive_File *createdFile = (GTLRDrive_File *)object;
NSLog(#"Wrote file %# in Google Drive folder %#", createdFile.name, folderId);
if (completionHandler) completionHandler(createdFile.name, createdFile.identifier);
}
else
{
NSLog(#"-writeFileAtUrl:toFolderWithId:completionHandler: status code = %li : callbackError: %#", callbackTicket.statusCode, callbackError.localizedDescription);
}
}];
}
As an example, I've tried doing this after GIDSignIn logs in:
NSURL *sampleFile = [[NSBundle mainBundle] URLForResource:#"AValidTestFile" withExtension:#"png"];
if (sampleFile)
{
[self writeFileAtUrl:sampleFile toFolderWithId:#"appDataFolder" completionHandler:^(NSString *filename, NSString *newFileId)
{
NSLog(#"Uploaded file %# with ID %#", filename, newFileId);
}];
}
I still just get a 403 error.
At this point, I've read a huge number of tutorials, blog posts and forum threads in several different programming languages. I've gone over my own code several times and added an insane number of logging statements to double check everything, but I can't work out how I can have permission to create folders, but not to put files in them.
Some time later...
If you go through the credential wizard in the Google Console (rather than just selecting an iOS credential because you're creating an iOS app), you get a message which says "Application data cannot be accessed securely from iOS. Please consider selecting another platform" and it refuses to create a credential for you. Is it possible that this just doesn't work, despite the SDK having the necessary constants?
For those who follow after me, I think I've concluded that using the appDataFolder in iOS just doesn't work.
Having switched to using a folder in the Drive space, I've also found that the -uploadParametersWithFileURL:MIMEType: method of GTLRUploadParameters doesn't work. When I use that I get a file called 'Untitled' (containing the file metadata I set in my GTLRDrive_File object) in the root of the drive. As soon as I switched to -uploadParametersWithData:MIMEType: I got the correct file in the correct place.
I suppose the lesson so far is that if something isn't working, assume it’s the SDK.
When I'm trying to perform request for inserting of a broadcast I receive error:
Error Domain=com.google.GTLRErrorObjectDomain Code=403 "The user is blocked from live streaming."
UserInfo={GTLRStructuredError=GTLRErrorObject 0x28027ad30: {code:403
errors:[1] message:"The user is blocked from live streaming."},
NSLocalizedDescription=The user is blocked from live streaming.}
I have started receiving this error today. Before, everything has been working fine. I have tested on several accounts and had not any luck.
Code:
GTLRYouTube_LiveBroadcastSnippet *broadcastSnippet= [[GTLRYouTube_LiveBroadcastSnippet alloc] init];
[broadcastSnippet setTitle:title];
[broadcastSnippet setScheduledStartTime:[GTLRDateTime dateTimeWithDate:self.beginOfStream]]; // current date + 1 minute.
[broadcastSnippet setScheduledEndTime:[GTLRDateTime dateTimeWithDate:[NSDate dateWithTimeIntervalSinceNow:80000]]];
GTLRYouTube_LiveBroadcastStatus *status = [[GTLRYouTube_LiveBroadcastStatus alloc] init];
[status setPrivacyStatus:[StreamSettings youtubeStringForPrivacyStatus:[privacyStatus intValue]]];
GTLRYouTube_LiveBroadcastContentDetails *details = [self streamDetailsWith:latency];
GTLRYouTube_LiveBroadcast *broadcast = [[GTLRYouTube_LiveBroadcast alloc] init];
[broadcast setKind:#"youtube#liveBroadcast"];
[broadcast setSnippet:broadcastSnippet];
[broadcast setStatus:status];
GTLRYouTubeQuery_LiveBroadcastsInsert *query = [GTLRYouTubeQuery_LiveBroadcastsInsert queryWithObject:broadcast
part:#"id, snippet, contentDetails,status"];
GTLRYouTubeService *service = self.youTubeService;
__strong id <YouTubeHelperDelegate> strongDelegate = self.delegate;
[service executeQuery:query completionHandler:^(GTLRServiceTicket *ticket,
GTLRYouTube_LiveBroadcast *returnedBrocast,
NSError *error) {
if (error) {
NSLog(#"%#", error); //Here is place I got an error
}
}];
If the logged in user does not have more than 1000 subscribers he can't go live using a mobile app, as mentioned in link:
https://support.google.com/youtube/answer/2853834?hl=en
I want to establish a VPN connection with my VPN server.
I installed VPN server from digital oceans.
I want to make VPN application for IOS by using objective-C by using my VPN connection settings.
Here I faced problem:
no VPN shared secret was provided.
Here I Used Codes
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[[NEVPNManager sharedManager] setEnabled:YES];
[[NEVPNManager sharedManager] loadFromPreferencesWithCompletionHandler: ^(NSError *error) {
NEVPNProtocolIPSec *p = [[NEVPNProtocolIPSec alloc] init];
p.serverAddress =#"178.62.78.101";
p.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret;
p.useExtendedAuthentication = YES;
NSString *secret = #"gfJL$$";
NSData *secretData = [secret dataUsingEncoding:NSUTF8StringEncoding];
p.sharedSecretReference=secretData;
p.localIdentifier=#"londra1";
p.username=#"root";
p.passwordReference=[[SSKeychain passwordForService:#"2eee9fa59" account:#"2eee9fa5"] dataUsingEncoding:NSUTF8StringEncoding];
p.disconnectOnSleep = NO;
[NEVPNManager sharedManager].protocolConfiguration=p;
NSMutableArray *rules = [[NSMutableArray alloc] init];
NEOnDemandRuleConnect *connectRule = [NEOnDemandRuleConnect new];
[rules addObject:connectRule];
[[NEVPNManager sharedManager] setOnDemandRules:rules];
[[NEVPNManager sharedManager] setLocalizedDescription:#"vpn"];
[[NEVPNManager sharedManager] setEnabled:YES];
[[NEVPNManager sharedManager] saveToPreferencesWithCompletionHandler: ^(NSError *error) {
NSLog(#"Save VPN to preference complete");
if (error) {
NSLog(#"Save error: %#", error);
}
}];
NSError *startError;
[[NEVPNManager sharedManager].connection startVPNTunnelAndReturnError:&startError];
if(startError) {
NSLog(#"Start error: %#", startError.localizedDescription);
}
}];
return YES;
}
You are setting sharedSecretReference as an NSData, but this conflicts with its definition.
NEVPNProtocolIPSec::sharedSecretReference is defined as:
A persistent keychain reference to a keychain item containing the IKE shared secret.
You need to create a keychain item of type kSecClassGenericPassword to use as the shared secret, and provide a persistent reference to the keychain item. A persistent reference is critical here, as it can be stored to disk or passed between processes, which is required for NEVPNManager to access the shared secret and connect your VPN. I suspect that although passwordReference seems to be set by a keychain item, it may not be returning a persistent reference either.
You will need to use SecItemCopyMatching with return type kSecReturnPersistentRef to achieve this.
I had created network manager by using the below code. but as soon the first line of call is run the manager is being nil so any other methods are getting not effected. Can Anyone let me know that what wrong thing I had done ?
NEVPNManager *manager = [NEVPNManager sharedManager];
NEVPNProtocolIPSec *p = [[NEVPNProtocolIPSec alloc] init];
p.username = #"MYUSERNAME";
p.passwordReference = [#"MYPW" dataUsingEncoding:NSUTF8StringEncoding];
p.serverAddress = #"[NetworkIP]";
p.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret;
p.sharedSecretReference = [#"SharedSecretHashCode" dataUsingEncoding:NSUTF8StringEncoding];
[manager setProtocol:p];
[manager setOnDemandEnabled:NO];
[manager setLocalizedDescription:#"VIT VPN"];
NSArray *array = [NSArray new];
[manager setOnDemandRules: array];
NSLog(#"Connection desciption: %#", manager.localizedDescription);
NSLog(#"VPN status: %li", (long)manager.connection.status);
[manager saveToPreferencesWithCompletionHandler:^(NSError *error) {
if(error) {
NSLog(#"Save error: %#", error);
}
}];
"manager" is being nil . please help. thanks in advance.
I found Solution for my question for the NEVPNManager instances.
When using this to the app developer must need its related certificates in which The APPID has has enabled the VPN Configuration & controls. and this app must need to run in the device.
So the NEVPNManager will not be nil and it can be adapt from the shared instance of the device. (also this is from NetworkExtension.framework which is available for iOS8 & higher devices)
May be this can help anyone who is having the same issue.
When logging a user into my application I need to pull a user object down from the server using only the username. This returns the userId (among other things) that I need in order to make other API calls. From that point I'll make a couple other HTTP calls using the userId. How can I make a synchronous call to completely pull down the user object before sending the other calls?
I've setup my object mapping in my app delegate class, which works perfectly, and am using this code to pull the user object down from the server:
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:[#"/api/users/" stringByAppendingString:[_userNameField text]] delegate:self];
This is what I've tried... as suggested here: Making synchronous calls with RestKit
RKObjectLoader* loader = [[RKObjectManager sharedManager] objectLoaderForObject:currentUser method:RKRequestMethodPUT delegate:nil];
RKResponse* response = [loader sendSynchronously];
However this code (1) uses the deprecated method objectLoaderForObject and (2) crashes saying 'Unable to find a routable path for object of type '(null)' for HTTP Method 'POST''.
Putting aside the question of whether this is the ideal design for an iPhone application, I was able to accomplish what I was hoping using blocks.
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:[#"/api/users/" stringByAppendingString:[_userNameField text]] usingBlock:^(RKObjectLoader* loader) {
loader.onDidLoadResponse = ^(RKResponse *response) {
NSLog(#"Response: \n%#", [response bodyAsString]);
};
loader.onDidLoadObjects = ^(NSArray *objects) {
APIUser *apiUser = [objects objectAtIndex:0];
NSLog(#"user_id is %i", apiUser.user_id);
};
loader.onDidFailWithError = ^(NSError *error) {
UIAlertView *badLoginAlert = [[UIAlertView alloc]initWithTitle:NSLocalizedString(#"LOGIN_FAILED", nil)
message:NSLocalizedString(#"BAD PASSWORD OR USERNAME", nil)
delegate:self
cancelButtonTitle:NSLocalizedString(#"OK", nil)
otherButtonTitles:nil];
[badLoginAlert show];
};
}];
Hope this helps someone.