Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement security scoped url with bookmark for readDir on iOS #52

Conversation

zenoxs
Copy link

@zenoxs zenoxs commented Jun 15, 2024

Implement security scoped url with bookmark for readDir on iOS (more info: https://developer.apple.com/documentation/uikit/view_controllers/providing_access_to_directories)

The function now accept a bookmark:// scheme following by the iOS bookmark in base64.

Example of usage with the @react-native-documents/picker librairie to pick up the bookmark of a folder on iOS:

import * as RNFS from '@dr.pogodin/react-native-fs'
import { pickDirectory } from '@react-native-documents/picker'


const res = await pickDirectory({
  requestLongTermAccess: true // Request the bookmark 
})

if (res.bookmarkStatus === 'success') {
  const files = await RNFS.readDir(`bookmark://${res.bookmark}`)
  console.log(files)
}

NB: I was not sure on how to handle the exception for readDir function, feel free to edit my PR or add comments :)

Related to: #51

@birdofpreyru birdofpreyru changed the base branch from master to dev-v2.27 June 15, 2024 12:19
@birdofpreyru birdofpreyru merged commit bda4fc6 into birdofpreyru:dev-v2.27 Jun 15, 2024
@birdofpreyru
Copy link
Owner

Looks fine. Will double-check it does not break tests in the Example App and release shortly. Are you using a 3rd part library to get the bookmark because pickFile() from this lib only allows to pick files? Isn't it possible to ask it to select folders, by some special mimeType option value? If so, I'd create a ticket that we should support selecting folders by the system file-picker in this lib.

@birdofpreyru
Copy link
Owner

Well... it turned out your PR even did not compile; and when looking into it closely I figured out that readDir() function had to be further refactored to use NSURL objects all around, rather than relying on old logic using path strings (I doubt the old way would work for security scoped stuff).

@zenoxs
Copy link
Author

zenoxs commented Jun 16, 2024

Looks fine. Will double-check it does not break tests in the Example App and release shortly. Are you using a 3rd part library to get the bookmark because pickFile() from this lib only allows to pick files? Isn't it possible to ask it to select folders, by some special mimeType option value? If so, I'd create a ticket that we should support selecting folders by the system file-picker in this lib.

Sadly, I am using the premium version of this lib. There is actually no free react native lib that allows selecting a folder. I think it's not that hard to implement, but it would probably easier to do in swift rather than objectif c.

EDIT: Nvm, it looks like you can simply edit the the pickFile method on ReactNativeFs.mm to forward this argument ´initWithDocumentTypes:@[(NSString *)kUTTypeFolder]´ in order to request a directory picker, this would give the following code :

        picker = [[UIDocumentPickerViewController alloc]
                  // Add the following line
                  initWithDocumentTypes:@[(NSString *)kUTTypeFolder]
                  inMode:UIDocumentPickerModeOpen];

then on the App.tsx of the example:

            const res = await pickFile();
            if (res.length > 0 && res[0]) {
              const items = await readDir(res[0]);
              console.log(items);
            }

I tried on my own and it returns a correct bookmark for the picked directory, and I can then list its content with the readDir method.

@zenoxs
Copy link
Author

zenoxs commented Jun 16, 2024

Well... it turned out your PR even did not compile; and when looking into it closely I figured out that readDir() function had to be further refactored to use NSURL objects all around, rather than relying on old logic using path strings (I doubt the old way would work for security scoped stuff).

Sorry for that, that's really weird. I tested my branch on simulator and real device. I also patched the lib with the same code on my application and everything works as expected. Could you describe what error you got on compilation ? And which version of xcode you are using ?

@birdofpreyru
Copy link
Owner

Could you describe what error you got on compilation?

You did the following, and NSURL does not have stringByAppendingPathComponent method.

NSString *path = [dirUrl stringByAppendingPathComponent:obj];

Then, even it has other means to turn an NSURL into a NSString URL representation, I guess doing so you loose any security permissions granted to the original NSURL instance. Have a look how I ended up doing it — only using NSURL methods to get child URLs and retrieve their attributes.

EDIT: Nvm, it looks like you can simply edit the the pickFile method on ReactNativeFs.mm to forward this argument

Yeah, that is about what I thought. Actually, there might be no need to edit anything, see how pickFile() transforms mimeTypes option it gets into the corresponding UTType (in particular, the line 1218):

for (int i = 0; i < numMimeTypes; ++i) {
NSString *mime = mimeTypes[i];
UTType *type;
if ([mime isEqual:@"*/*"]) type = UTTypeItem;
else type = [UTType typeWithMIMEType:mime];
[types addObject:type];
}

I guess, there might be a MIME string (to be checked in iOS documentation) denoting a directory, which you can pass in on TS side, to automatically get kUTTypeFolder type on the iOS side. And if there is no such string, we should introduce one, and handle it similar to how */* MIME value is handled there. Also... one way or another, it should be ensured to work the same for Android, and Windows; and library README should mention it (and perhaps even expose an auxiliary pickFolder() method).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants