Add mac signing
DELETE
WalletWasabi.Packager/Content/Osx/.VolumeIcon.icns
WalletWasabi.Packager/Content/Osx/.VolumeIcon.icns
Binary files a/WalletWasabi.Packager/Content/Osx/.VolumeIcon.icns and /dev/null differ

DELETE
WalletWasabi.Packager/Content/Osx/.fseventsd/0000000000351e4e
WalletWasabi.Packager/Content/Osx/.fseventsd/0000000000351e4e
Binary files a/WalletWasabi.Packager/Content/Osx/.fseventsd/0000000000351e4e and /dev/null differ

DELETE
WalletWasabi.Packager/Content/Osx/.fseventsd/0000000000351e4f
WalletWasabi.Packager/Content/Osx/.fseventsd/0000000000351e4f
Binary files a/WalletWasabi.Packager/Content/Osx/.fseventsd/0000000000351e4f and /dev/null differ

DELETE
WalletWasabi.Packager/Content/Osx/.fseventsd/fseventsd-uuid
-CCDE848F-0D7E-48A2-8065-4195F209D614
\ No newline at end of file

ADD
WalletWasabi.Packager/Content/Osx/App/Contents/Info.plist
+<?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>LSArchitecturePriority</key>
+ <array>
+ <string>x86_64</string>
+ </array>
+ <key>CFBundleIconFile</key>
+ <string>WasabiLogo.icns</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>?</string>
+ <key>CFBundleVersion</key>
+ <string>?</string>
+ <key>CFBundleExecutable</key>
+ <string>wassabee</string>
+ <key>CFBundleName</key>
+ <string>Wasabi Wallet</string>
+ <key>CFBundleIdentifier</key>
+ <string>zksnacks.wasabiwallet</string>
+ <key>NSHighResolutionCapable</key>
+ <true/>
+ <key>NSAppleScriptEnabled</key>
+ <true/>
+ <key>LSApplicationCategoryType</key>
+ <string>public.app-category.finance</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+</dict>
+</plist>

ADD
WalletWasabi.Packager/Content/Osx/App/Contents/Resources/WasabiLogo.icns
WalletWasabi.Packager/Content/Osx/App/Contents/Resources/WasabiLogo.icns
Binary files /dev/null and b/WalletWasabi.Packager/Content/Osx/App/Contents/Resources/WasabiLogo.icns differ

RENAME
WalletWasabi.Packager/Content/Osx/.DS_Store
WalletWasabi.Packager/Content/Osx/Dmg/.DS_Store.dat
Binary files a/WalletWasabi.Packager/Content/Osx/.DS_Store and b/WalletWasabi.Packager/Content/Osx/Dmg/.DS_Store.dat differ

RENAME
WalletWasabi.Packager/Content/Osx/.background/Logo_with_text_small.png
WalletWasabi.Packager/Content/Osx/Dmg/.background/Logo_with_text_small.png
ADD
WalletWasabi.Packager/Content/Osx/Dmg/.fseventsd/000000000081abf0
WalletWasabi.Packager/Content/Osx/Dmg/.fseventsd/000000000081abf0
Binary files /dev/null and b/WalletWasabi.Packager/Content/Osx/Dmg/.fseventsd/000000000081abf0 differ

ADD
WalletWasabi.Packager/Content/Osx/Dmg/.fseventsd/000000000081abf1
WalletWasabi.Packager/Content/Osx/Dmg/.fseventsd/000000000081abf1
Binary files /dev/null and b/WalletWasabi.Packager/Content/Osx/Dmg/.fseventsd/000000000081abf1 differ

ADD
WalletWasabi.Packager/Content/Osx/Dmg/.fseventsd/fseventsd-uuid
+5D4F6D41-8967-4D1E-9953-35A263D5EFDF
\ No newline at end of file

ADD
WalletWasabi.Packager/Content/Osx/WasabiLogo.icns
WalletWasabi.Packager/Content/Osx/WasabiLogo.icns
Binary files /dev/null and b/WalletWasabi.Packager/Content/Osx/WasabiLogo.icns differ

ADD
WalletWasabi.Packager/Content/Osx/addcert.sh
+#!/usr/bin/env bash
+
+key_chain="build.keychain"
+key_chain_pass="mysecretpassword"
+security create-keychain -p "$key_chain_pass" "$key_chain"
+security default-keychain -s "$key_chain"
+security unlock-keychain -p "$key_chain_pass" "$key_chain"
+security import macdevsign.p12 -k "$key_chain" -P "alma" -A
+security set-key-partition-list -S apple-tool:,apple: -s -k "$key_chain_pass" "$key_chain"
\ No newline at end of file

ADD
WalletWasabi.Packager/Content/Osx/entitlements.plist
+<?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.cs.allow-jit</key>
+ <true/>
+ <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
+ <true/>
+ <key>com.apple.security.cs.allow-dyld-environment-variables</key>
+ <true/>
+ <key>com.apple.security.cs.disable-library-validation</key>
+ <true/>
+ <key>com.apple.security.app-sendbox</key>
+ <true/>
+</dict>
+</plist>

ADD
WalletWasabi.Packager/MacSignTools.cs
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+
+namespace WalletWasabi.Packager
+{
+ public static class MacSignTools
+ {
+ public static void Sign()
+ {
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ throw new NotSupportedException("This signing method is only valid on macOS!");
+ }
+
+ Console.WriteLine("Phase: finding the zip file on desktop which contains the compiled binaries from Windows.");
+
+ string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
+
+ var srcZipFileNamePattern = "Wasabi-osx-*.zip";
+ var files = Directory.GetFiles(desktopPath, srcZipFileNamePattern); //Example: Wasabi-osx-1.1.10.2.zip
+ if (files.Length != 1)
+ {
+ throw new InvalidDataException($"{srcZipFileNamePattern} file missing or there are more on Desktop! There must be exactly one!");
+ }
+ var zipPath = files[0];
+ var versionPrefix = zipPath.Split('-').Last().TrimEnd(".zip", StringComparison.InvariantCultureIgnoreCase); // Example: "/Users/user/Desktop/Wasabi-unsigned-1.1.10.2.zip".
+ var workingDir = Path.Combine(desktopPath, "wasabiTemp");
+ var dmgPath = Path.Combine(workingDir, "dmg");
+ var unzippedPath = Path.Combine(workingDir, "unzipped");
+ var appName = "Wasabi Wallet.app";
+ var appPath = Path.Combine(dmgPath, appName);
+ var appContentsPath = Path.Combine(appPath, "Contents");
+ var appMacOsPath = Path.Combine(appContentsPath, "MacOS");
+ var appResPath = Path.Combine(appContentsPath, "Resources");
+ var appFrameworksPath = Path.Combine(appContentsPath, "Frameworks");
+ var infoFilePath = Path.Combine(appContentsPath, "Info.plist");
+ var dmgFileName = $"Wasabi-{versionPrefix}.dmg";
+ var dmgFilePath = Path.Combine(workingDir, dmgFileName);
+ var dmgUnzippedFilePath = Path.Combine(workingDir, $"Wasabi.tmp.dmg");
+ var appNotarizeFilePath = Path.Combine(workingDir, $"Wasabi-{versionPrefix}.zip");
+ var contentsPath = Path.GetFullPath(Path.Combine(Program.PackagerProjectDirectory.Replace("\\", "//"), "Content", "Osx"));
+ var entitlementsPath = Path.Combine(contentsPath, "entitlements.plist");
+ var dmgContentsDir = Path.Combine(contentsPath, "Dmg");
+ var torZipDirPath = Path.Combine(appMacOsPath, "TorDaemons", "tor-osx64");
+ var torZipPath = $"{torZipDirPath}.zip";
+ var desktopDmgFilePath = Path.Combine(desktopPath, dmgFileName);
+
+ var signArguments = $"--sign \"L233B2JQ68\" --verbose --force --options runtime --timestamp";
+
+ Console.WriteLine("Phase: creating the working directory.");
+
+ Console.WriteLine("Enter appleId (email):");
+ var appleId = Console.ReadLine();
+ Console.WriteLine("Enter password:");
+ var password = Console.ReadLine();
+
+ if (Directory.Exists(workingDir))
+ {
+ DeleteWithChmod(workingDir);
+ }
+
+ if (File.Exists(desktopDmgFilePath))
+ {
+ File.Delete(desktopDmgFilePath);
+ }
+
+ Console.WriteLine("Phase: creating the app.");
+
+ IoHelpers.EnsureDirectoryExists(appResPath);
+ IoHelpers.EnsureDirectoryExists(appMacOsPath);
+
+ ZipFile.ExtractToDirectory(zipPath, appMacOsPath); // Copy the binaries.
+
+
+ IoHelpers.CopyFilesRecursively(new DirectoryInfo(Path.Combine(contentsPath, "App")), new DirectoryInfo(appPath));
+
+ Console.WriteLine("Update the plist file with current information for example with version.");
+
+ var lines = File.ReadAllLines(infoFilePath);
+ string bundleIdentifier = null;
+
+ for (int i = 0; i < lines.Length; i++)
+ {
+ string line = lines[i];
+ if (!line.TrimStart().StartsWith("<key>", StringComparison.InvariantCultureIgnoreCase))
+ {
+ continue;
+ }
+
+ if (line.Contains("CFBundleShortVersionString", StringComparison.InvariantCulture) ||
+ line.Contains("CFBundleVersion", StringComparison.InvariantCulture))
+ {
+ lines[i + 1] = lines[i + 1].Replace("?", $"{Version.Parse(versionPrefix).ToString(3)}"); // Apple allow only 3 version tags in plist.
+ }
+ else if (line.Contains("CFBundleIdentifier", StringComparison.InvariantCulture))
+ {
+ bundleIdentifier = lines[i + 1].Trim().Replace("<string>", "").Replace("</string>", "");
+ }
+ }
+ IoHelpers.DeleteRecursivelyWithMagicDustAsync(infoFilePath).GetAwaiter().GetResult();
+ File.WriteAllLines(infoFilePath, lines);
+
+ using (var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "chmod",
+ Arguments = $"-R u+rwX,go+rX,go-w \"{appPath}\"",
+ WorkingDirectory = workingDir
+ }))
+ {
+ process.WaitForExit();
+ }
+
+ var filesToCheck = new[] { entitlementsPath, torZipPath };
+
+ foreach (var file in filesToCheck)
+ {
+ if (!File.Exists(file))
+ {
+ throw new FileNotFoundException($"File missing: {file}");
+ }
+ }
+
+ Console.WriteLine("Signing the files in app.");
+
+ UnlockKeychain();
+
+ IoHelpers.EnsureDirectoryExists(appResPath);
+ IoHelpers.EnsureDirectoryExists(appMacOsPath);
+
+ var executables = GetExecutables(appPath);
+ var filesToSignInOrder = Directory.GetFiles(appPath, "*.*", SearchOption.AllDirectories)
+ .OrderBy(file => executables.Contains(file))
+ .OrderBy(file => new FileInfo(file).Name == "wassabee")
+ .ToArray();
+
+
+ foreach (var file in executables)
+ {
+ using var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "chmod",
+ Arguments = $"u+x \"{file}\"",
+ WorkingDirectory = workingDir
+
+ });
+ process.WaitForExit();
+ }
+
+ SignDirectory(filesToSignInOrder, workingDir, signArguments, entitlementsPath);
+
+ Console.WriteLine("Phase: verifying the signature.");
+
+ Verify(appPath);
+
+ Console.WriteLine("Phase: notarize the app.");
+
+ // Source: https://blog.frostwire.com/2019/08/27/apple-notarization-the-signature-of-the-binary-is-invalid-one-other-reason-not-explained-in-apple-developer-documentation/
+ using (var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "ditto",
+ Arguments = $"-c -k --keepParent \"{appPath}\" \"{appNotarizeFilePath}\"",
+ WorkingDirectory = workingDir
+ }))
+ {
+ process.WaitForExit();
+ }
+
+ Notarize(appleId, password, appNotarizeFilePath, bundleIdentifier);
+ Staple(appPath);
+
+
+ using (var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "spctl",
+ Arguments = $"-a -t exec -vv \"{appPath}\"",
+ WorkingDirectory = workingDir,
+ RedirectStandardError = true
+ }))
+ {
+ process.WaitForExit();
+ string result = process.StandardError.ReadToEnd();
+ if (!result.Contains(": accepted"))
+ {
+ throw new InvalidOperationException(result);
+ }
+ }
+
+ Console.WriteLine("Phase: creating the dmg.");
+
+ if (File.Exists(dmgFilePath))
+ {
+ File.Delete(dmgFilePath);
+ }
+
+ Console.WriteLine("Phase: creating dmg.");
+
+ IoHelpers.CopyFilesRecursively(new DirectoryInfo(dmgContentsDir), new DirectoryInfo(dmgPath));
+
+ File.Copy(Path.Combine(contentsPath, "WasabiLogo.icns"), Path.Combine(dmgPath, ".VolumeIcon.icns"),true);
+
+ var temp = Path.Combine(dmgPath, ".DS_Store.dat");
+ File.Move(temp, Path.Combine(dmgPath, ".DS_Store"), true);
+
+ using (var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "ln",
+ Arguments = "-s /Applications",
+ WorkingDirectory = dmgPath
+ }))
+ {
+ process.WaitForExit();
+ }
+
+ var hdutilCreateArgs = string.Join(" ", new string[]
+ {
+ "create",
+ $"\"{dmgUnzippedFilePath}\"",
+ "-ov",
+ $"-volname \"Wasabi Wallet\"",
+ "-fs HFS+",
+ $"-srcfolder \"{dmgPath}\""
+ });
+
+ using (var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "hdiutil",
+ Arguments = hdutilCreateArgs,
+ WorkingDirectory = dmgPath
+ }))
+ {
+ process.WaitForExit();
+ }
+
+ var hdutilConvertArgs = string.Join(" ", new string[]
+ {
+ "convert",
+ $"\"{dmgUnzippedFilePath}\"",
+ "-format UDZO",
+ $"-o \"{dmgFilePath}\""
+ });
+
+ using (var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "hdiutil",
+ Arguments = hdutilConvertArgs,
+ WorkingDirectory = dmgPath
+ }))
+ {
+ process.WaitForExit();
+ }
+
+ Console.WriteLine("Phase: signing the dmg file.");
+
+ UnlockKeychain();
+
+ SignFile($"{signArguments} --entitlements \"{entitlementsPath}\" \"{dmgFilePath}\"", dmgPath);
+
+ Console.WriteLine("Phase: verifying the signature.");
+
+ Verify(dmgFilePath);
+
+ Console.WriteLine("Phase: notarize dmg");
+ Notarize(appleId, password, dmgFilePath, bundleIdentifier);
+
+ Console.WriteLine("Phase: staple dmp");
+ Staple(dmgFilePath);
+
+ using (var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "spctl",
+ Arguments = $"-a -t open --context context:primary-signature -v \"{dmgFilePath}\"",
+ WorkingDirectory = workingDir,
+ RedirectStandardError = true
+ }))
+ {
+ process.WaitForExit();
+ string result = process.StandardError.ReadToEnd();
+ if (!result.Contains(": accepted"))
+ {
+ throw new InvalidOperationException(result);
+ }
+ }
+
+ File.Move(dmgFilePath, desktopDmgFilePath);
+ DeleteWithChmod(workingDir);
+
+ Console.WriteLine("Phase: finish.");
+ }
+
+ public static bool IsMacSignMode()
+ {
+ return RuntimeInformation.IsOSPlatform(OSPlatform.OSX); // For now this is enough. If you run it on macOS you want to sign.
+ }
+
+ private static void Notarize(string appleId, string password, string filePath, string bundleIdentifier)
+ {
+ string uploadId = null;
+
+ Console.WriteLine("Start notarizing, uploading file.");
+
+ using (var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "xcrun",
+ Arguments = $"altool --notarize-app -t osx -f \"{filePath}\" --primary-bundle-id \"{bundleIdentifier}\" -u \"{appleId}\" -p \"{password}\" --output-format xml",
+ RedirectStandardOutput = true,
+ }))
+ {
+ process.WaitForExit();
+ string result = process.StandardOutput.ReadToEnd();
+
+ if (result.Contains("The software asset has already been uploaded. The upload ID is"))
+ {
+ // Example: The software asset has already been uploaded. The upload ID is 7689dc08-d6c8-4783-8d28-33e575f5c967
+ uploadId = result.Split('"').First(line => line.Contains("The software asset has already been uploaded.")).Split("The upload ID is").Last().Trim();
+ }
+ else if (result.Contains("No errors uploading"))
+ {
+ // Example: <key>RequestUUID</key>\n\t\t<string>2a2a164f-2ae7-4293-8357-5d5a5cdd580a</string>
+
+ var lines = result.Split('\n');
+
+ for (int i = 0; i < lines.Length; i++)
+ {
+ string line = lines[i].Trim();
+ if (!line.TrimStart().StartsWith("<key>", StringComparison.InvariantCultureIgnoreCase))
+ {
+ continue;
+ }
+
+ if (line.Contains("<key>RequestUUID</key>", StringComparison.InvariantCulture))
+ {
+ uploadId = lines[i + 1].Trim().Replace("<string>", "").Replace("</string>", "");
+ }
+ }
+ }
+ }
+
+ if (uploadId is null)
+ {
+ throw new InvalidOperationException("Cannot get uploadId. Notarization failed.");
+ }
+
+ Stopwatch sw = new Stopwatch();
+ sw.Start();
+ while (true) // Wait for the notarization.
+ {
+ Console.WriteLine($"Checking notarization status. Elapsed time: {sw.Elapsed.ToString()}");
+ using var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "xcrun",
+ Arguments = $"altool --notarization-info \"{uploadId}\" -u \"{appleId}\" -p \"{password}\"",
+ RedirectStandardError = true,
+ RedirectStandardOutput = true,
+ });
+ process.WaitForExit();
+ string result = $"{process.StandardError.ReadToEnd()} {process.StandardOutput.ReadToEnd()}";
+ if (result.Contains("Status Message: Package Approved"))
+ {
+ break;
+ }
+ if (result.Contains("Status: in progress"))
+ {
+ Thread.Sleep(4000);
+ continue;
+ }
+ if (result.Contains("Could not find the RequestUUID"))
+ {
+ Thread.Sleep(4000);
+ continue;
+ }
+
+ throw new InvalidOperationException(result);
+ }
+ }
+
+ private static void Staple(string filePath)
+ {
+ using var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "xcrun",
+ Arguments = $"stapler staple \"{filePath}\"",
+ });
+ process.WaitForExit();
+ }
+
+ private static void DeleteWithChmod(string path)
+ {
+ using (var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "chmod",
+ Arguments = $"-R ugo+rwx \"{path}\"",
+ }))
+ {
+ process.WaitForExit();
+ }
+
+ IoHelpers.DeleteRecursivelyWithMagicDustAsync(path).GetAwaiter().GetResult();
+ }
+
+ private static void UnlockKeychain()
+ {
+ using var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "security",
+ Arguments = $"unlock-keychain -p \"mysecretpassword\" build.keychain",
+ });
+ process.WaitForExit();
+ }
+
+ private static void SignFile(string arguments,string workingDir)
+ {
+ using var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "codesign",
+ Arguments = arguments,
+ WorkingDirectory = workingDir,
+ RedirectStandardError = true
+ });
+ process.WaitForExit();
+ var result = process.StandardError.ReadToEnd();
+ if (result.Contains("code object is not signed at all"))
+ {
+ throw new InvalidOperationException(result);
+ }
+ Console.WriteLine(result.Trim());
+ }
+
+ private static void Verify(string path)
+ {
+ using var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "codesign",
+ Arguments = $"-dv --verbose=4 \"{path}\"",
+ RedirectStandardError = true,
+ });
+ process.WaitForExit();
+ string result = process.StandardError.ReadToEnd();
+ if (!result.Contains("Authority=Developer ID Application: zkSNACKs Ltd."))
+ {
+ throw new InvalidOperationException(result);
+ }
+ }
+
+ private static void SignDirectory(string[] files, string workingDir, string signArguments, string entitlementsPath)
+ {
+ // Tor already signed by: The Tor Project, Inc (MADPSAYN6T)
+
+ // Wassabee has to be signed at the end. Otherwise codesing will throw a submodule not signed error.
+ foreach (var file in files)
+ {
+
+ var fileName = new FileInfo(file).Name;
+
+ if (fileName == ".DS_Store")
+ {
+ File.Delete(file);
+ continue;
+ }
+
+ SignFile($"{signArguments} --entitlements \"{entitlementsPath}\" \"{file}\"", workingDir);
+
+ }
+ }
+
+ private static string[] GetExecutables(string workingDir)
+ {
+ // Can be implemented as: find -H YourAppBundle -print0 | xargs -0 file | grep "Mach-O .*executable"
+
+ return Directory.GetFiles(workingDir, "*.", SearchOption.AllDirectories);
+ }
+
+ }
+}

MODIFY
WalletWasabi.Packager/Program.cs
WalletWasabi.Packager/Program.cs
@@ -60,6 +60,12 @@ namespace WalletWasabi.Packager
private static void Main(string[] args)
{
+ if (MacSignTools.IsMacSignMode())
+ {
+ MacSignTools.Sign();
+ return;
+ }
+
// If I want a list of up to date onions run it with '--getonions'.
if (IsGetOnionsMode(args))
{
@@ -90,11 +96,9 @@ namespace WalletWasabi.Packager
if (DoPublish || OnlyBinaries)
{
Publish();
- if (OnlyBinaries)
- {
+
IoHelpers.OpenFolderInFileExplorer(BinDistDirectory);
}
- }
if (!OnlyBinaries)
{
@@ -381,6 +385,19 @@ namespace WalletWasabi.Packager
IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
Console.WriteLine($"Deleted {publishedFolder}");
}
+ else if (target.StartsWith("osx", StringComparison.OrdinalIgnoreCase))
+ {
+ string dmgFilePath = Path.Combine(BinDistDirectory, $"Wasabi-{VersionPrefix}.dmg");
+ if (!File.Exists(dmgFilePath))
+ {
+ throw new Exception(".dmg does not exist.");
+ }
+ string zipFilePath = Path.Combine(BinDistDirectory, $"Wasabi-osx-{VersionPrefix}.zip");
+ if (File.Exists(zipFilePath))
+ {
+ File.Delete(zipFilePath);
+ }
+ }
}
Console.WriteLine("Signing final files...");
@@ -598,133 +615,10 @@ namespace WalletWasabi.Packager
continue;
}
- var tempName = Path.Combine(BinDistDirectory, $"temp-{target}");
- Directory.Move(currentBinDistDirectory, tempName);
- currentBinDistDirectory = tempName;
-
- string macWasabiAppDir = Path.Combine(publishedFolder, "Wasabi Wallet.App"); // This should be lowercase .app, but MAC will prevent people from upgrading if we change it.
- string macContentsDir = Path.Combine(macWasabiAppDir, "Contents");
- string newName = Path.GetFullPath(Path.Combine(macContentsDir, "MacOS"));
- Directory.CreateDirectory(macContentsDir);
- Directory.Move(currentBinDistDirectory, newName);
- currentBinDistDirectory = newName;
-
- string resourcesDir = Path.Combine(macContentsDir, "Resources");
- string infoFilePath = Path.Combine(macContentsDir, "Info.plist");
+ ZipFile.CreateFromDirectory(currentBinDistDirectory, Path.Combine(BinDistDirectory, $"Wasabi-osx-{VersionPrefix}.zip"));
- Directory.CreateDirectory(resourcesDir);
- var iconPath = Path.Combine(GuiProjectDirectory, "Assets", "WasabiLogo.icns");
- File.Copy(iconPath, Path.Combine(resourcesDir, "WasabiLogo.icns"));
-
- string infoContent = $@"<?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>LSMinimumSystemVersion</key>
- <string>10.12</string>
-
- <key>LSArchitecturePriority</key>
- <array>
- <string>x86_64</string>
- </array>
-
- <key>CFBundleIconFile</key>
- <string>WasabiLogo.icns</string>
-
- <key>CFBundlePackageType</key>
- <string>APPL</string>
-
- <key>CFBundleShortVersionString</key>
- <string>{VersionPrefix}</string>
-
- <key>CFBundleVersion</key>
- <string>{VersionPrefix}</string>
-
- <key>CFBundleExecutable</key>
- <string>{ExecutableName}</string>
-
- <key>CFBundleName</key>
- <string>Wasabi Wallet</string>
-
- <key>CFBundleIdentifier</key>
- <string>zksnacks.wasabiwallet</string>
-
- <key>NSHighResolutionCapable</key>
- <true/>
-
- <key>NSAppleScriptEnabled</key>
- <true/>
-
- <key>LSApplicationCategoryType</key>
- <string>public.app-category.finance</string>
-
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
-</dict>
-</plist>
-";
- File.WriteAllText(infoFilePath, infoContent);
-
- using (var process = Process.Start(new ProcessStartInfo
- {
- FileName = "cmd",
- RedirectStandardInput = true,
- WorkingDirectory = publishedFolder
- }))
- {
- process.StandardInput.WriteLine($"wsl ln -s /Applications && exit");
- process.WaitForExit();
- }
-
- //how to generate .DS_Store file - https://github.com/zkSNACKs/WalletWasabi/pull/928/commits/e38ed672dee25f6e45a3eb16584887cc6d48c4e6
- var dmgContentDir = Path.Combine(PackagerProjectDirectory, "Content", "Osx");
- IoHelpers.CopyFilesRecursively(new DirectoryInfo(dmgContentDir), new DirectoryInfo(publishedFolder));
-
- string uncompressedDmgFileName = $"Wasabi-uncompressed.dmg";
- string uncompressedDmgFilePath = Path.Combine(BinDistDirectory, uncompressedDmgFileName);
- string dmgFileName = $"Wasabi-{VersionPrefix}.dmg";
- using (var process = Process.Start(new ProcessStartInfo
- {
- FileName = "cmd",
- RedirectStandardInput = true,
- WorkingDirectory = BinDistDirectory
- }))
- {
- // http://www.nathancoulson.com/proj_cross_tools.php
- // -D: Do not use deep directory relocation, and instead just pack them in the way we see them
- // -V: Volume Label
- // -no-pad: Do not pad the end by 150 sectors (300kb). As it is not a cd image, not required
- // -apple -r: Creates a .dmg image
- process.StandardInput.WriteLine($"wsl genisoimage -D -V \"Wasabi Wallet\" -no-pad -apple -r -dir-mode 755 -o \"{uncompressedDmgFileName}\" \"{new DirectoryInfo(publishedFolder).Name}\" && exit");
- process.WaitForExit();
- }
- // cd ~
- // git clone https://github.com/planetbeing/libdmg-hfsplus.git && cd libdmg-hfsplus
- // https://github.com/planetbeing/libdmg-hfsplus/issues/14
- // mkdir build && cd build
- // sudo apt-get install zlib1g-dev
- // cmake ..
- // cd build
- // sudo apt-get install libssl1.0-dev
- // cmake ..
- // cd ~/libdmg-hfsplus/build/
- // make
- using (var process = Process.Start(new ProcessStartInfo
- {
- FileName = "cmd",
- RedirectStandardInput = true,
- WorkingDirectory = BinDistDirectory
- }))
- {
- process.StandardInput.WriteLine($"wsl ~/libdmg-hfsplus/build/dmg/./dmg dmg \"{uncompressedDmgFileName}\" \"{dmgFileName}\" && exit");
- process.WaitForExit();
- }
-
- IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
- File.Delete(uncompressedDmgFilePath);
-
- IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
- Console.WriteLine($"Deleted {publishedFolder}");
+ IoHelpers.DeleteRecursivelyWithMagicDustAsync(currentBinDistDirectory).GetAwaiter().GetResult();
+ Console.WriteLine($"Deleted {currentBinDistDirectory}");
}
else if (target.StartsWith("linux"))
{

Add mac signing