0

I'm making a file encryption app, but when I submit it to the App Store, if I don't enable Sandbox, it gets rejected when I upload it with Transporter.app.

So, I added Sandbox to Entitlements.plist as follows.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>com.apple.security.app-sandbox</key>
  <true/>
  <key>com.apple.security.files.user-selected.read-write</key>
  <true/>
</dict>
</plist>

Now I can upload files with Transporter.app without any problems, but now that I have enabled Sandbox, when I try to write files from NSSavePanel, the file access seems to be denied as shown below. By the way, I can read files from NSOpenPanel.

var panel = new NSSavePanel();
panel.CanCreateDirectories = true;
panel.ReleasedWhenClosed = true;

panel.BeginSheet(MainViewController.Window, ret =>
{
    panel.EndSheet(MainViewController.Window);
    if (ret > 0)
    {
        DirectoryInfo diParent = Directory.GetParent(panel.Url.Path);
        string DirPath = diParent.FullName;
        string FileName = Path.GetFileNameWithoutExtension(panel.Url.Path);

        var publicKeyFilePath = Path.Combine(DirPath, FileName + ".pub");
        var privateFilePath = Path.Combine(DirPath, FileName + ".pvt");

        var rsa = new RSACryptoServiceProvider(2048);
        var publicKey = rsa.ToXmlString(false);
        var privateKey = rsa.ToXmlString(true);

        var xml = XElement.Parse(publicKey);
        xml.Save(publicKeyFilePath);  // <- System.UnauthorizedAccessException

        //-----------------------------------
        xml = XElement.Parse(privateKey);
        xml.Save(privateFilePath);

        rsa.Clear();

        return guidString;
    }
});
xml.Save(publicKeyFilePath);  // <- System.UnauthorizedAccessException

Of course, if Sandbox is not enabled, the public key file will be saved without any problem.

What could be the problem?

mahal tertin
  • 3,239
  • 24
  • 41
hibara
  • 137
  • 11
  • Hard to see what is failing here. Show the code for getting the path through the save panel. Also realize that the permission you get is not persisted when your app closes. That would require extra steps – svn Jun 25 '21 at 08:42
  • I have added more detailed source code. Thank you. – hibara Jun 25 '21 at 20:51
  • So where is filePath comming from? Also try the unaltered url from the save panel – svn Jun 27 '21 at 13:48
  • I'm sorry. The code is essentially a function, and when I simplified and wrote it, the source of the `filePath` was not shown. The code has been re-corrected. `panel.Url.Path` is the relevant section. – hibara Jun 27 '21 at 21:20
  • 2
    I think the file path you write to has to be exactly the url you are getting from the savepanel. You are changing it with different extensions but the permission is only granted for the exact url the user choose. – svn Jun 28 '21 at 07:16

1 Answers1

0

This problem has been solved.

As mentioned in the comments, it seems that the file name specified by the user in NSSavePanel was not used as it is, and I generated two files with different extensions, which was caught by the Sandbox limitation.

In this case, I was able to save the desired file by displaying NSSavePanel twice in a row and saving the file with the user-specified file name.

var panel = new NSSavePanel();
panel.CanCreateDirectories = true;
panel.ReleasedWhenClosed = true;

panel.AllowedFileTypes = new[] { "pub" };
panel.BeginSheet(MainViewController.Window, ret =>
{
    XElement xml;
    var rsa = new RSACryptoServiceProvider(2048);
    panel.EndSheet(MainViewController.Window);
    if (ret > 0)
    {
        var publicKey = rsa.ToXmlString(false);
        xml = XElement.Parse(publicKey);
        xml.Save(panel.Url.Path);  // <- Use the file path selected by the user as is
    }

    panel = new NSSavePanel();
    panel.AllowedFileTypes = new[] { "pvt" };
    panel.BeginSheet(MainViewController.Window, rt =>
    {
        panel.EndSheet(MainViewController.Window);
        if (rt > 0)
        {
          var privateKey = rsa.ToXmlString(true);
          xml = XElement.Parse(privateKey);
          xml.Save(panel.Url.Path);  // <- Use the file path selected by the user as is
        }
    });

    rsa.Clear();

});
hibara
  • 137
  • 11