Sandbox Bug

Discussion in 'Mac Programming' started by DavidBlack, Oct 24, 2013.

  1. DavidBlack, Oct 24, 2013
    Last edited: Oct 24, 2013

    DavidBlack macrumors 6502a

    DavidBlack

    Joined:
    Jan 27, 2013
    Location:
    Somewhere In Apple's HQ ;)
    #1
    Hi, I have this app which downloads YouTube videos it's currently not sandboxed, and I will like to be. So I tried to do that today it does not work properly my app has a feature called "simple downloading" it basically downloads the video to a defined folder and to choose your folder an NSSavePanel opens. So I did that with the app and downloading works fine but when you relaunch the app when you try to download the video it fails. I think this because PowerBox and failed to grant the app access to the file system. The app also has a feature that when the download button is click it opens an NSSavePanel this only works if the user has already clicked simple downloading and select a predefined and then uncheck it. (Another bug caused my app sandbox)
    Can someone help me with this issue?

    Thanks in advance
     

    Attached Files:

  2. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #2
    Without your code, probably not. Please share your relevant code. I haven't used this kind of feature before, but as I recall when I was reading the APIs when it was new, there was some sort of bookmark or something you're supposed to store that can be reused between launches to grant access to folders to which the user has previously given you access.
     
  3. DavidBlack, Oct 25, 2013
    Last edited: Oct 25, 2013

    DavidBlack thread starter macrumors 6502a

    DavidBlack

    Joined:
    Jan 27, 2013
    Location:
    Somewhere In Apple's HQ ;)
    #3
    This is the NSSavPanel Method and the first part of the download method.

    Code:
     self.extractedURL = [NSURL URLWithString: url];
                            NSString *downloadtitle = [youtubewebview stringByEvaluatingJavaScriptFromString:@"document.title"];
                            NSSavePanel *savePanel = [NSSavePanel savePanel];
                            [savePanel setTitle:NSLocalizedString(@"Choose Where You Want To Save Your Video...", @"Choose Where You Want To Save Your Video... comment")];
                            [savePanel setCanCreateDirectories:YES];
                            [savePanel setPrompt:NSLocalizedString(@"Download", @"Download Propmt comment")];
                            [savePanel setNameFieldStringValue:downloadtitle];
                            
                            NSInteger result = [savePanel runModal];
                            if(result != NSFileHandlingPanelOKButton)
                                return;
                            NSURL *directoryURL = [savePanel directoryURL];
                            
                            NSString *outputName = [savePanel nameFieldStringValue];
                            NSString *brain = [directoryURL path];
                            NSString *outputDic = brain;
                            
                            
                            // start fetching videos
                            [self.progressIndicator setIndeterminate: NO];
                            
                            [self.downloadButton setTitle:NSLocalizedString(@"Stop", @"Stop download")];
                            
                            
                         
                            
                            
                            r = [ASIHTTPRequest requestWithURL:self.extractedURL];
                            ASIHTTPRequest * __unsafe_unretained unretainedOperation = r;
                            
                            NSString *local_full_path = [NSString stringWithFormat: @"%@/%@.mp4", outputDic,outputName];
                            NSLog(@"Saving: %@", local_full_path);
                            //NSLog(@"Saving to the folder: %@", [local_full_path stringByDeletingLastPathComponent]);
                            [r setTimeOutSeconds: 10];
                            
                            [unretainedOperation setAllowResumeForFileDownloads: YES];
                            [unretainedOperation setNumberOfTimesToRetryOnTimeout:5];
                            [unretainedOperation setDownloadDestinationPath: local_full_path];
                            [unretainedOperation setTemporaryFileDownloadPath: [NSString stringWithFormat:@"%@/%@.temp", outputDic,outputName]];
                            
                            [unretainedOperation setDownloadProgressDelegate: self.progressIndicator];
                            
                            [unretainedOperation setShowAccurateProgress:YES];
                            [unretainedOperation setDelegate: self];
    
     
  4. JoshDC macrumors regular

    Joined:
    Apr 8, 2009
    #4
    You need to save any URLs you want access to after relaunches using security scoped bookmarks, as explained here under "Security-Scoped Bookmarks and Persistent Resource Access".

    Another option in your case would be to include access to the downloads folder in your sandbox entitlements, and allow users to select that as their location for simple downloading.
     
  5. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #5
    The whole idea of a sandbox is that your app cannot do whatever it likes, but is restricted to doing only things that are save. What you have is not a "Sandbox Bug", it's the sandbox doing exactly what it is supposed to do. One thing your app isn't supposed to be able to do is writing files anywhere it likes.

    When you use the NSSavePanels from a sandbox, and the user picks a file or directory, the OS opens up access to that file. But only as long as the application is running. As JoshDC said, once your app has access to that file, even momentarily, you can make calls that give you access rights later.
     
  6. DavidBlack thread starter macrumors 6502a

    DavidBlack

    Joined:
    Jan 27, 2013
    Location:
    Somewhere In Apple's HQ ;)
    #6
    Thanks I found these examples online. But they appear to need the NSSavePanel to run in a completion handler, which is not an option for me.

    Code:
    NSError *error = nil;
    NSData *bookmarkData = nil;
     
    bookmarkData = [openPanelFileURL 
    bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
    includingResourceValuesForKeys:nil
    relativeToURL:nil
    error:&error];
    Code:
    NSError *error = nil;
    BOOL bookmarkDataIsStale;
    NSURL *bookmarkFileURL = nil;
     
    bookmarkFileURL = [NSURL 
    URLByResolvingBookmarkData:bookmarkData
    options:NSURLBookmarkResolutionWithSecurityScope
    relativeToURL:nil
    bookmarkDataIsStale:&bookmarkDataIsStale
    error:&error];
    Can you help me?
     
  7. JoshDC macrumors regular

    Joined:
    Apr 8, 2009
    #7
    You don't have to run it with a completion block. Provided the URL you are creating a security scoped bookmark from is accessible at the point you create it, it will work fine. You can replace openPanelFileURL with [savePanel URL] at the point your save panel ends.
     
  8. DavidBlack thread starter macrumors 6502a

    DavidBlack

    Joined:
    Jan 27, 2013
    Location:
    Somewhere In Apple's HQ ;)
    #8
    This what I have but I getting a null value. Thanks for your help so far btw.

    Code:
      NSString *downloadtitle = [youtubewebview stringByEvaluatingJavaScriptFromString:@"document.title"];
                            NSSavePanel *savePanel = [NSSavePanel savePanel];
                            [savePanel setTitle:NSLocalizedString(@"Choose Where You Want To Save Your Video...", @"Choose Where You Want To Save Your Video... comment")];
                            [savePanel setCanCreateDirectories:YES];
                            [savePanel setPrompt:NSLocalizedString(@"Download", @"Download Propmt comment")];
                            [savePanel setNameFieldStringValue:downloadtitle];
                            
                            NSInteger result = [savePanel runModal];
                            if(result != NSFileHandlingPanelOKButton)
                                return;
                            NSURL *directoryURL = [savePanel URL];
                            
                            NSString *outputURL = [savePanel nameFieldStringValue];
                            
                            NSError *error = nil;
                            NSData *bookmarkData = nil;
                            
                            bookmarkData = [directoryURL
                                            bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
                                            includingResourceValuesForKeys:nil
                                            relativeToURL:nil
                                            error:&error];
                            
                            BOOL bookmarkDataIsStale;
                            NSURL *bookmarkFileURL = nil;
                            
                            bookmarkFileURL = [NSURL
                                               URLByResolvingBookmarkData:bookmarkData
                                               options:NSURLBookmarkResolutionWithSecurityScope
                                               relativeToURL:nil
                                               bookmarkDataIsStale:&bookmarkDataIsStale
                                               error:&error];
                            
                            if (error) {
                                NSLog(@"Error");
                            }
                          
                            NSString *bookmarkFilePath = [bookmarkFileURL absoluteString];
                            
                            [bookmarkFileURL startAccessingSecurityScopedResource];
    
    
                            
                            // start fetching videos
                            [self.progressIndicator setIndeterminate: NO];
                            
                            [self.downloadButton setTitle:NSLocalizedString(@"Stop", @"Stop download")];
                            
                            
                            NSString *randomFilename = [NSString stringWithFormat: @"%@", outputURL];
                            
                           
                            r = [ASIHTTPRequest requestWithURL:self.extractedURL];
                            ASIHTTPRequest * __unsafe_unretained unretainedOperation = r;
                            
                            NSString *local_full_path = [NSString stringWithFormat: @"%@/%@.mp4", bookmarkFilePath,outputURL];
                            NSLog(@"Saving: %@", local_full_path);
                           
                            [r setTimeOutSeconds: 10];
                            
                            [unretainedOperation setAllowResumeForFileDownloads: YES];
                            [unretainedOperation setNumberOfTimesToRetryOnTimeout:5];
                            [unretainedOperation setDownloadDestinationPath: local_full_path];
                            [unretainedOperation setTemporaryFileDownloadPath: [NSString stringWithFormat:@"%@/%@.temp", bookmarkFilePath,outputURL]];
    I get this in the debug area:

    Code:
    Error
    Saving: (null)/Coming Soon - YouTube.mp4
     
  9. JoshDC macrumors regular

    Joined:
    Apr 8, 2009
    #9
    You don't need to do that when the user selects an exact file path. From my understanding your app works in one of two ways:

    • Simple downlding: the user clicks "download", the file is saved to a folder chosen previously
    • Non-simple downloading: the user is asked each time they want to download a file

    Sandboxing only affects you in the first case, in which you need to save the folder as a security scoped bookmark. Something like:

    • The user enables simple downloading and chooses a folder
    • You save that folder as a security scoped bookmark (for examaple in their preferences)
    • When the user wants to download a file, you resolve the URL from the data in their preferences and use the APIs available to work with it

    Make sure to read and understand the sandbox guide, specifically how open and save panels work with powerbox.

    For what it's worth I'd just add the downloads folder to your entitlements and tell users they can only save there if they want simple downloading.
     
  10. DavidBlack thread starter macrumors 6502a

    DavidBlack

    Joined:
    Jan 27, 2013
    Location:
    Somewhere In Apple's HQ ;)
    #10
    Thanks, but I want to have the option for the use an NSSavePanel. Which currently does not work.
     

Share This Page