Search code examples
xamarin.macappstore-sandboxentitlementsnssavepanel

Xamarin.Mac cannot write files when Sandbox is enabled


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?


Solution

  • 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();
    
    });