From c1f3b038e4f07d524e48caa92f7e562a917108f2 Mon Sep 17 00:00:00 2001 From: Guangcong Luo Date: Wed, 5 Feb 2020 14:50:28 -0800 Subject: [PATCH] Update desktop client (#1459) Last time we built the desktop client, in 2015, NW.js was called node-webkit. Since then: - NW.js has added NaCl and some other things, ballooning the installer from 30 MB to 120 MB. (The NaCl stuff on Windows seems to be deletable, helping keep its installed size slightly smaller.) (If anyone wants to make a custom build without NaCl, that'd help me a lot) - NW.js also has a lot more files, and NSIS makes adding/removing files annoying enough that I wrote a script to automate it for me. - Apple has made Gatekeeper requirements a lot stricter, requiring setting up entitlements, Hardened Runtime, notarization, and stapling, (in addition to just signing in 2015). I documented the process because there are zero online guides for it right now. But on the other hand, this update hopefully fixes the crashes that the old desktop client has. It also fixes: - the Chrome bold emoji bug is gone - MP3 is no longer under patent, allowing us to have only MP3 files for everything - honestly I don't think we use any other Chrome feature added in the last four years --- desktop/DESKTOP.md | 125 ++++++++--- desktop/Info.plist | 108 ++++------ desktop/make-nsis-script.js | 195 ++++++++++++++++++ desktop/nwjs-entitlements.entitlements | 18 ++ desktop/pokemonshowdown.nsi | 275 +++++++++++++++++++++++-- desktop/sign-mac-app | 76 +++++++ 6 files changed, 682 insertions(+), 115 deletions(-) create mode 100644 desktop/make-nsis-script.js create mode 100644 desktop/nwjs-entitlements.entitlements create mode 100755 desktop/sign-mac-app diff --git a/desktop/DESKTOP.md b/desktop/DESKTOP.md index b85ceb14d..e04132b19 100644 --- a/desktop/DESKTOP.md +++ b/desktop/DESKTOP.md @@ -1,57 +1,128 @@ Desktop apps ============ -Pokémon Showdown for desktop is made with [node-webkit][1]. +Pokémon Showdown for desktop is made with [NW.js][1]. - [1]: https://github.com/rogerwang/node-webkit + [1]: https://nwjs.io/ -There's an `.ico` icon (for Windows) and an `.icns` icon (for Mac) in the -`graphics-src` directory of this repository. We use these pretty much -whenever we need icons. +There's an `.ico` icon (for Windows) and an `.icns` icon (for Mac) in the `graphics-src` directory of this repository. We use these pretty much whenever we need icons. -Note that node-webkit doesn't support normal window icons in Windows, -so we have to use a PNG icon to get scaling not to look horribly ugly. +Note that NW.js doesn't support normal window icons in Windows, so we have to use a PNG icon to get scaling not to look horribly ugly. Packaging --------- -node-webkit's wiki contains packaging instructions, but they're strewn -across their wiki and don't really go into best practices, so I have -better packaging instructions here. +NW.js's docs contains [packaging instructions][2], but they're strewn across their wiki and don't really go into best practices, so I have better packaging instructions here. -For performance, we don't zip up the package on either platform. In Windows, -the `index.html` and `package.json` files are dropped directly into the -node-webkit directory, and in OS X the files are dropped into -`Resources/app.nw`. + [2]: http://docs.nwjs.io/en/latest/For%20Users/Package%20and%20Distribute/ + +For performance, we don't zip up the package on either platform. In Windows, the `index.html` and `package.json` files are dropped directly into the install directory, and in OS X the files are dropped into `Resources/app.nw`. Packaging for Windows --------------------- -1. Put a copy of node-webkit (build or extract the prebuilt binary) into this - folder. +1. Put a copy of node-webkit (build or extract the prebuilt binary) into this folder. 2. Rename `nw.exe` to `pokemonshowdown.exe` -3. Edit `pokemonshowdown.exe` with [Resource Hacker][2], and replace the - node-webkit icon with`icons/pokemonshowdown.ico` +3. Edit `pokemonshowdown.exe` with [Resource Hacker][3], and replace the node-webkit icon with`icons/pokemonshowdown.ico` -4. Using [NSIS][2], build `pokemonshowdown.nsi` +4. You may need to update `pokemonshowdown.nsi` if the file layout has changed; refer to `make-nsis-script.js` - [2]: http://www.angusj.com/resourcehacker/ - [3]: http://nsis.sourceforge.net/ +5. Using [NSIS][4], build `pokemonshowdown.nsi` + + [3]: http://www.angusj.com/resourcehacker/ + [4]: http://nsis.sourceforge.net/ Packaging for OS X ------------------ +NOTE: By default, Mac apps will refuse to run, displaying a Gatekeeper warning. Removing the Gatekeeper warning requires an Apple Developer account (costs $99/year) and an annoying notarization process (step 8 to 18). + 1. Get a copy of node-webkit (build or extract the prebuilt binary) 2. Rename it to `Pokemon Showdown.app` -3. Replace `Pokemon Showdown.app/Contents/Info.plist` with the `Info.plist` - in this directory +3. Update `Pokemon Showdown.app/Contents/Info.plist`, changing: -4. Replace `Pokemon Showdown.app/Contents/Resources/nw.icns` with the - icns file in `graphics-src`. + - `CFBundleIdentifier` to `com.pokemonshowdown.pokemonshowdown` + - `CFBundleName` to `Pokemon Showdown` + - `CFBundleDisplayName` to `Pokemon Showdown` + - `CFBundleShortVersionString` to the current version, e.g. `0.11` + - `CFBundleVersion` to the some sort of version code, I just used the git commit hash + - empty the arrays of `CFBundleDocumentTypes`, `CFBundleURLTypes`, `NSUserActivityTypes`, and `UTExportedTypeDeclarations` so they look like `` + - (these register the app as able to open these files/URLs, which we _definitely_ do not want to do) -5. Create a folder `Pokemon Showdown.app/Contents/Resources/app.nw` and put - `index.html` and `package.json` in it. +4. Update `Pokemon Showdown.app/Contents/Resources/en.lproj/InfoPlist.strings`, + changing: + + - `CFBundleName` to `"Pokemon Showdown"` + - `CFBundleDisplayName` to `"Pokemon Showdown"` + - `CFBundleGetInfoString` to something like `"Pokemon Showdown 0.11, Copyright 2011-2020 Guangcong Luo and contributors."` + - `NSHumanReadableCopyright` to something like `"Copyright 2011-2020 Guangcong Luo and contributors."` + +5. Delete all the other `*.lproj` folders (other than `en.lproj`) in `Pokemon Showdown.app/Contents/Resources` + + - (our app is named "Pokemon Showdown" in all languages, we definitely don't want it to be called "nwjs" in other languages) + +6. Replace `Pokemon Showdown.app/Contents/Resources/app.icns` and `Pokemon Showdown.app/Contents/Resources/document.icns` with the icns file in `graphics-src`. + +7. Create a folder `Pokemon Showdown.app/Contents/Resources/app.nw` and put `index.html` and `package.json` in it. + +8. Grab a developer ID certificate (this requires an Apple Developer account costing $99) + + - https://developer.apple.com/account/mac/certificate/certificateList.action + - type should be "Developer ID Application" + +9. Install the cert in Keychain and remember its "identity" (the part in parentheses) + + - just drag and drop the cert file into Keychain Access + +10. Sign the app, set up entitlements, and set it to use Hardened Runtime + + - Edit `sign-mac-app`, setting `APP` to the location of your app, and `IDENTITY` to the identity from step 9 + - Run `sign-mac-app` + +11. Verify the signature + + - `codesign --verify -vvvv "Pokemon Showdown.app"` + +12. Zip up the app into `Pokemon Showdown.zip` + + - right-click, Compress, rename to remove the `.app` part + +13. Notarize the app, noting the `RequestUUID` + + - `[USERNAME]` is your Apple Developer account username (should be an email address) + - `[PASSWORD]` is an app-specific password for your Apple Developer account + - get an app-specific password here: https://support.apple.com/en-us/HT204397 + - `xcrun altool --notarize-app --primary-bundle-id "com.pokemonshowdown.pokemonshowdown" --username "[USERNAME]" --password "[PASSWORD]" --file "Pokemon Showdown.zip"` + - this will show a `RequestUUID`, which you'll need + +14. Wait for the app to notarize (this takes around 10 minutes in my experience) + +15. Check the notarization + + - `[RequestUUID]` is the UUID from above + - `xcrun altool --notarization-info [RequestUUID] -u "[USERNAME]"` + - it will ask for a password; use the same password as in step 12 + - the Status line will say either `in progress`, `Package Approved`, or `Package Invalid` + - `in progress` - try again in ten minutes + - `Package Invalid` - error messages will be in the `LogFileURL` link + - `Package Approved` - this is what we're hoping for + +16. Staple the notarization + + - `xcrun stapler staple "Pokemon Showdown.app"` + +17. Validate the notarization + + - `spctl -a -vvvv "Pokemon Showdown.app"` + +18. Delete the un-stapled zip, and create a new zip + +Apple's own documentation on the command-line notarization process might be useful: + +https://developer.apple.com/documentation/xcode/notarizing_macos_software_before_distribution/customizing_the_notarization_workflow + +But it doesn't cover how to set up an existing app for Hardened Runtime (I only figured it out from a random GitHub issue after an hour of Googling). diff --git a/desktop/Info.plist b/desktop/Info.plist index beb6a903c..a07e39617 100644 --- a/desktop/Info.plist +++ b/desktop/Info.plist @@ -3,46 +3,19 @@ BuildMachineOSBuild - 12F45 + 17G3025 CFBundleDevelopmentRegion en CFBundleDisplayName Pokemon Showdown CFBundleDocumentTypes - - - CFBundleTypeIconFile - nw.icns - CFBundleTypeName - nwjs App - CFBundleTypeRole - Viewer - LSHandlerRank - Owner - LSItemContentTypes - - io.nwjs.nw.app - - - - CFBundleTypeName - Folder - CFBundleTypeOSTypes - - fold - - CFBundleTypeRole - Viewer - LSHandlerRank - None - - + CFBundleExecutable nwjs CFBundleIconFile - nw.icns + app.icns CFBundleIdentifier - io.nwjs.nw + com.pokemonshowdown.pokemonshowdown CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -50,54 +23,53 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.3.0 + 0.11 + CFBundleSignature + NWJS + CFBundleURLTypes + CFBundleVersion - 2236.2 + bf46c879d0 + DTCompiler + com.apple.compilers.llvm.clang.1_0 DTSDKBuild - 12F37 + 10.14 DTSDKName - macosx10.8 + macosx10.14 DTXcode - 0511 + 1000 DTXcodeBuild - 5B1008 + 10A255 + LSEnvironment + + MallocNanoZone + 0 + LSFileQuarantineEnabled - + + LSHasLocalizedDisplayName + 1 LSMinimumSystemVersion - 10.6.0 + 10.10.0 + NSAppleScriptEnabled + NSPrincipalClass - NSApplication + BrowserCrApplication + NSRequiresAquaSystemAppearance + NSSupportsAutomaticGraphicsSwitching - SCMRevision - df30fb73b312044486237d93cf96f3606862f2a3 - UTExportedTypeDeclarations + NSUserActivityTypes - - UTTypeConformsTo - - com.pkware.zip-archive - - UTTypeDescription - nwjs App - UTTypeIconFile - nw.icns - UTTypeIdentifier - io.nwjs.nw.app - UTTypeReferenceURL - https://github.com/rogerwang/node-webkit/wiki/How-to-package-and-distribute-your-apps - UTTypeTagSpecification - - com.apple.ostype - nwjs - public.filename-extension - - nw - - public.mime-type - application/x-nwjs-app - - + NSUserActivityTypeBrowsingWeb + NSUserNotificationAlertStyle + banner + OSAScriptingDefinition + scripting.sdef + SCMRevision + ac9418ba9c3bd7f6baaffa0b055dfe147e0f8364-refs/branch-heads/3538@{#468} + UTExportedTypeDeclarations + diff --git a/desktop/make-nsis-script.js b/desktop/make-nsis-script.js new file mode 100644 index 000000000..c41d241e6 --- /dev/null +++ b/desktop/make-nsis-script.js @@ -0,0 +1,195 @@ +/** key order matters for buckets */ +function putInBuckets(files) { + let buckets = new Map(); + buckets.set('', []); + + for (let file of files) { + file = file.trim().replace(/\//g, `\\`); + if (!file) continue; + let splitFiles = file.split(`\\`); + for (let i = 1; i < splitFiles.length; i++) { + let parent = splitFiles.slice(0, i).join(`\\`); + if (buckets.has(parent)) continue; + buckets.set(parent, []); + } + let parent = splitFiles.slice(0, -1).join(`\\`); + if (!splitFiles[splitFiles.length - 1]) continue; + buckets.get(parent).push(file); + } + + return buckets; +} + +function createInstallScript(buckets) { + let out = ``; + for (const [parent, files] of buckets) { + if (parent) out += `CreateDirectory "$INSTDIR\\${parent}"\n`; + if (files.length) { + if (parent) out += `setOutPath "$INSTDIR\\${parent}"\n`; + for (const file of files) { + out += `file "${file}"\n`; + } + } + } + return out; +} + +function createUninstallScript(buckets) { + let out = ``; + let reverseEntries = [...buckets.entries()].reverse(); + for (const [parent, files] of reverseEntries) { + for (const file of files) { + out += `delete "$INSTDIR\\${file}"\n`; + } + if (parent) out += `rmDir "$INSTDIR\\${parent}"\n`; + } + return out; +} + +/*********************************************************************************/ + +const files = [ + 'credits.html', + 'd3dcompiler_47.dll', + 'ffmpeg.dll', + 'icons', + 'icons/icon_32x32.png', + 'icons/installerbg.bmp', + 'icons/pokemonshowdown.ico', + 'icudtl.dat', + 'index.html', + 'libEGL.dll', + 'libGLESv2.dll', + 'locales', + 'locales/am.pak', + 'locales/am.pak.info', + 'locales/ar.pak', + 'locales/ar.pak.info', + 'locales/bg.pak', + 'locales/bg.pak.info', + 'locales/bn.pak', + 'locales/bn.pak.info', + 'locales/ca.pak', + 'locales/ca.pak.info', + 'locales/cs.pak', + 'locales/cs.pak.info', + 'locales/da.pak', + 'locales/da.pak.info', + 'locales/de.pak', + 'locales/de.pak.info', + 'locales/el.pak', + 'locales/el.pak.info', + 'locales/en-GB.pak', + 'locales/en-GB.pak.info', + 'locales/en-US.pak', + 'locales/en-US.pak.info', + 'locales/es-419.pak', + 'locales/es-419.pak.info', + 'locales/es.pak', + 'locales/es.pak.info', + 'locales/et.pak', + 'locales/et.pak.info', + 'locales/fa.pak', + 'locales/fa.pak.info', + 'locales/fi.pak', + 'locales/fi.pak.info', + 'locales/fil.pak', + 'locales/fil.pak.info', + 'locales/fr.pak', + 'locales/fr.pak.info', + 'locales/gu.pak', + 'locales/gu.pak.info', + 'locales/he.pak', + 'locales/he.pak.info', + 'locales/hi.pak', + 'locales/hi.pak.info', + 'locales/hr.pak', + 'locales/hr.pak.info', + 'locales/hu.pak', + 'locales/hu.pak.info', + 'locales/id.pak', + 'locales/id.pak.info', + 'locales/it.pak', + 'locales/it.pak.info', + 'locales/ja.pak', + 'locales/ja.pak.info', + 'locales/kn.pak', + 'locales/kn.pak.info', + 'locales/ko.pak', + 'locales/ko.pak.info', + 'locales/lt.pak', + 'locales/lt.pak.info', + 'locales/lv.pak', + 'locales/lv.pak.info', + 'locales/ml.pak', + 'locales/ml.pak.info', + 'locales/mr.pak', + 'locales/mr.pak.info', + 'locales/ms.pak', + 'locales/ms.pak.info', + 'locales/nb.pak', + 'locales/nb.pak.info', + 'locales/nl.pak', + 'locales/nl.pak.info', + 'locales/pl.pak', + 'locales/pl.pak.info', + 'locales/pt-BR.pak', + 'locales/pt-BR.pak.info', + 'locales/pt-PT.pak', + 'locales/pt-PT.pak.info', + 'locales/ro.pak', + 'locales/ro.pak.info', + 'locales/ru.pak', + 'locales/ru.pak.info', + 'locales/sk.pak', + 'locales/sk.pak.info', + 'locales/sl.pak', + 'locales/sl.pak.info', + 'locales/sr.pak', + 'locales/sr.pak.info', + 'locales/sv.pak', + 'locales/sv.pak.info', + 'locales/sw.pak', + 'locales/sw.pak.info', + 'locales/ta.pak', + 'locales/ta.pak.info', + 'locales/te.pak', + 'locales/te.pak.info', + 'locales/th.pak', + 'locales/th.pak.info', + 'locales/tr.pak', + 'locales/tr.pak.info', + 'locales/uk.pak', + 'locales/uk.pak.info', + 'locales/vi.pak', + 'locales/vi.pak.info', + 'locales/zh-CN.pak', + 'locales/zh-CN.pak.info', + 'locales/zh-TW.pak', + 'locales/zh-TW.pak.info', + 'natives_blob.bin', + 'node.dll', + 'notification_helper.exe', + 'nw.dll', + 'nw.exe', + 'nw_100_percent.pak', + 'nw_200_percent.pak', + 'nw_elf.dll', + 'package.json', + 'resources.pak', + 'swiftshader', + 'swiftshader/libEGL.dll', + 'swiftshader/libGLESv2.dll', + 'v8_context_snapshot.bin', +]; + +/*********************************************************************************/ + +const buckets = putInBuckets(files); + +console.log(createInstallScript(buckets)); + +console.log(''); + +console.log(createUninstallScript(buckets)); + diff --git a/desktop/nwjs-entitlements.entitlements b/desktop/nwjs-entitlements.entitlements new file mode 100644 index 000000000..eb46552e7 --- /dev/null +++ b/desktop/nwjs-entitlements.entitlements @@ -0,0 +1,18 @@ + + + + + com.apple.security.automation.apple-events + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-executable-page-protection + + com.apple.security.cs.disable-library-validation + + + diff --git a/desktop/pokemonshowdown.nsi b/desktop/pokemonshowdown.nsi index a5f907c19..d648ff73e 100755 --- a/desktop/pokemonshowdown.nsi +++ b/desktop/pokemonshowdown.nsi @@ -70,20 +70,141 @@ Section "Main" SecMain setOutPath $INSTDIR # Files added here should be removed by the uninstaller (see section "uninstall") - file "pokemonshowdown.exe" - file "package.json" - file "index.html" - file "nw.pak" + file "credits.html" file "d3dcompiler_47.dll" + file "ffmpeg.dll" file "icudtl.dat" - file "ffmpegsumo.dll" + file "index.html" file "libEGL.dll" file "libGLESv2.dll" - file "pdf.dll" + file "natives_blob.bin" + file "node.dll" + file "notification_helper.exe" + file "nw.dll" + file "pokemonshowdown.exe" + file "nw_100_percent.pak" + file "nw_200_percent.pak" + file "nw_elf.dll" + file "package.json" + file "resources.pak" + file "v8_context_snapshot.bin" CreateDirectory "$INSTDIR\icons" setOutPath "$INSTDIR\icons" file "icons\icon_32x32.png" + file "icons\installerbg.bmp" file "icons\pokemonshowdown.ico" + CreateDirectory "$INSTDIR\locales" + setOutPath "$INSTDIR\locales" + file "locales\am.pak" + file "locales\am.pak.info" + file "locales\ar.pak" + file "locales\ar.pak.info" + file "locales\bg.pak" + file "locales\bg.pak.info" + file "locales\bn.pak" + file "locales\bn.pak.info" + file "locales\ca.pak" + file "locales\ca.pak.info" + file "locales\cs.pak" + file "locales\cs.pak.info" + file "locales\da.pak" + file "locales\da.pak.info" + file "locales\de.pak" + file "locales\de.pak.info" + file "locales\el.pak" + file "locales\el.pak.info" + file "locales\en-GB.pak" + file "locales\en-GB.pak.info" + file "locales\en-US.pak" + file "locales\en-US.pak.info" + file "locales\es-419.pak" + file "locales\es-419.pak.info" + file "locales\es.pak" + file "locales\es.pak.info" + file "locales\et.pak" + file "locales\et.pak.info" + file "locales\fa.pak" + file "locales\fa.pak.info" + file "locales\fi.pak" + file "locales\fi.pak.info" + file "locales\fil.pak" + file "locales\fil.pak.info" + file "locales\fr.pak" + file "locales\fr.pak.info" + file "locales\gu.pak" + file "locales\gu.pak.info" + file "locales\he.pak" + file "locales\he.pak.info" + file "locales\hi.pak" + file "locales\hi.pak.info" + file "locales\hr.pak" + file "locales\hr.pak.info" + file "locales\hu.pak" + file "locales\hu.pak.info" + file "locales\id.pak" + file "locales\id.pak.info" + file "locales\it.pak" + file "locales\it.pak.info" + file "locales\ja.pak" + file "locales\ja.pak.info" + file "locales\kn.pak" + file "locales\kn.pak.info" + file "locales\ko.pak" + file "locales\ko.pak.info" + file "locales\lt.pak" + file "locales\lt.pak.info" + file "locales\lv.pak" + file "locales\lv.pak.info" + file "locales\ml.pak" + file "locales\ml.pak.info" + file "locales\mr.pak" + file "locales\mr.pak.info" + file "locales\ms.pak" + file "locales\ms.pak.info" + file "locales\nb.pak" + file "locales\nb.pak.info" + file "locales\nl.pak" + file "locales\nl.pak.info" + file "locales\pl.pak" + file "locales\pl.pak.info" + file "locales\pt-BR.pak" + file "locales\pt-BR.pak.info" + file "locales\pt-PT.pak" + file "locales\pt-PT.pak.info" + file "locales\ro.pak" + file "locales\ro.pak.info" + file "locales\ru.pak" + file "locales\ru.pak.info" + file "locales\sk.pak" + file "locales\sk.pak.info" + file "locales\sl.pak" + file "locales\sl.pak.info" + file "locales\sr.pak" + file "locales\sr.pak.info" + file "locales\sv.pak" + file "locales\sv.pak.info" + file "locales\sw.pak" + file "locales\sw.pak.info" + file "locales\ta.pak" + file "locales\ta.pak.info" + file "locales\te.pak" + file "locales\te.pak.info" + file "locales\th.pak" + file "locales\th.pak.info" + file "locales\tr.pak" + file "locales\tr.pak.info" + file "locales\uk.pak" + file "locales\uk.pak.info" + file "locales\vi.pak" + file "locales\vi.pak.info" + file "locales\zh-CN.pak" + file "locales\zh-CN.pak.info" + file "locales\zh-TW.pak" + file "locales\zh-TW.pak.info" + CreateDirectory "$INSTDIR\swiftshader" + setOutPath "$INSTDIR\swiftshader" + file "swiftshader\libEGL.dll" + file "swiftshader\libGLESv2.dll" writeUninstaller "$INSTDIR\uninstall.exe" @@ -124,24 +245,138 @@ Section "Uninstall" delete "$SMPROGRAMS\${APPNAME}.lnk" # Remove files - delete "$INSTDIR\pokemonshowdown.exe" - delete "$INSTDIR\package.json" - delete "$INSTDIR\index.html" + delete "$INSTDIR\swiftshader\libEGL.dll" + delete "$INSTDIR\swiftshader\libGLESv2.dll" + rmDir "$INSTDIR\swiftshader" + delete "$INSTDIR\locales\am.pak" + delete "$INSTDIR\locales\am.pak.info" + delete "$INSTDIR\locales\ar.pak" + delete "$INSTDIR\locales\ar.pak.info" + delete "$INSTDIR\locales\bg.pak" + delete "$INSTDIR\locales\bg.pak.info" + delete "$INSTDIR\locales\bn.pak" + delete "$INSTDIR\locales\bn.pak.info" + delete "$INSTDIR\locales\ca.pak" + delete "$INSTDIR\locales\ca.pak.info" + delete "$INSTDIR\locales\cs.pak" + delete "$INSTDIR\locales\cs.pak.info" + delete "$INSTDIR\locales\da.pak" + delete "$INSTDIR\locales\da.pak.info" + delete "$INSTDIR\locales\de.pak" + delete "$INSTDIR\locales\de.pak.info" + delete "$INSTDIR\locales\el.pak" + delete "$INSTDIR\locales\el.pak.info" + delete "$INSTDIR\locales\en-GB.pak" + delete "$INSTDIR\locales\en-GB.pak.info" + delete "$INSTDIR\locales\en-US.pak" + delete "$INSTDIR\locales\en-US.pak.info" + delete "$INSTDIR\locales\es-419.pak" + delete "$INSTDIR\locales\es-419.pak.info" + delete "$INSTDIR\locales\es.pak" + delete "$INSTDIR\locales\es.pak.info" + delete "$INSTDIR\locales\et.pak" + delete "$INSTDIR\locales\et.pak.info" + delete "$INSTDIR\locales\fa.pak" + delete "$INSTDIR\locales\fa.pak.info" + delete "$INSTDIR\locales\fi.pak" + delete "$INSTDIR\locales\fi.pak.info" + delete "$INSTDIR\locales\fil.pak" + delete "$INSTDIR\locales\fil.pak.info" + delete "$INSTDIR\locales\fr.pak" + delete "$INSTDIR\locales\fr.pak.info" + delete "$INSTDIR\locales\gu.pak" + delete "$INSTDIR\locales\gu.pak.info" + delete "$INSTDIR\locales\he.pak" + delete "$INSTDIR\locales\he.pak.info" + delete "$INSTDIR\locales\hi.pak" + delete "$INSTDIR\locales\hi.pak.info" + delete "$INSTDIR\locales\hr.pak" + delete "$INSTDIR\locales\hr.pak.info" + delete "$INSTDIR\locales\hu.pak" + delete "$INSTDIR\locales\hu.pak.info" + delete "$INSTDIR\locales\id.pak" + delete "$INSTDIR\locales\id.pak.info" + delete "$INSTDIR\locales\it.pak" + delete "$INSTDIR\locales\it.pak.info" + delete "$INSTDIR\locales\ja.pak" + delete "$INSTDIR\locales\ja.pak.info" + delete "$INSTDIR\locales\kn.pak" + delete "$INSTDIR\locales\kn.pak.info" + delete "$INSTDIR\locales\ko.pak" + delete "$INSTDIR\locales\ko.pak.info" + delete "$INSTDIR\locales\lt.pak" + delete "$INSTDIR\locales\lt.pak.info" + delete "$INSTDIR\locales\lv.pak" + delete "$INSTDIR\locales\lv.pak.info" + delete "$INSTDIR\locales\ml.pak" + delete "$INSTDIR\locales\ml.pak.info" + delete "$INSTDIR\locales\mr.pak" + delete "$INSTDIR\locales\mr.pak.info" + delete "$INSTDIR\locales\ms.pak" + delete "$INSTDIR\locales\ms.pak.info" + delete "$INSTDIR\locales\nb.pak" + delete "$INSTDIR\locales\nb.pak.info" + delete "$INSTDIR\locales\nl.pak" + delete "$INSTDIR\locales\nl.pak.info" + delete "$INSTDIR\locales\pl.pak" + delete "$INSTDIR\locales\pl.pak.info" + delete "$INSTDIR\locales\pt-BR.pak" + delete "$INSTDIR\locales\pt-BR.pak.info" + delete "$INSTDIR\locales\pt-PT.pak" + delete "$INSTDIR\locales\pt-PT.pak.info" + delete "$INSTDIR\locales\ro.pak" + delete "$INSTDIR\locales\ro.pak.info" + delete "$INSTDIR\locales\ru.pak" + delete "$INSTDIR\locales\ru.pak.info" + delete "$INSTDIR\locales\sk.pak" + delete "$INSTDIR\locales\sk.pak.info" + delete "$INSTDIR\locales\sl.pak" + delete "$INSTDIR\locales\sl.pak.info" + delete "$INSTDIR\locales\sr.pak" + delete "$INSTDIR\locales\sr.pak.info" + delete "$INSTDIR\locales\sv.pak" + delete "$INSTDIR\locales\sv.pak.info" + delete "$INSTDIR\locales\sw.pak" + delete "$INSTDIR\locales\sw.pak.info" + delete "$INSTDIR\locales\ta.pak" + delete "$INSTDIR\locales\ta.pak.info" + delete "$INSTDIR\locales\te.pak" + delete "$INSTDIR\locales\te.pak.info" + delete "$INSTDIR\locales\th.pak" + delete "$INSTDIR\locales\th.pak.info" + delete "$INSTDIR\locales\tr.pak" + delete "$INSTDIR\locales\tr.pak.info" + delete "$INSTDIR\locales\uk.pak" + delete "$INSTDIR\locales\uk.pak.info" + delete "$INSTDIR\locales\vi.pak" + delete "$INSTDIR\locales\vi.pak.info" + delete "$INSTDIR\locales\zh-CN.pak" + delete "$INSTDIR\locales\zh-CN.pak.info" + delete "$INSTDIR\locales\zh-TW.pak" + delete "$INSTDIR\locales\zh-TW.pak.info" + rmDir "$INSTDIR\locales" + delete "$INSTDIR\icons\icon_32x32.png" + delete "$INSTDIR\icons\installerbg.bmp" + delete "$INSTDIR\icons\pokemonshowdown.ico" + rmDir "$INSTDIR\icons" + delete "$INSTDIR\credits.html" delete "$INSTDIR\d3dcompiler_47.dll" - delete "$INSTDIR\ffmpegsumo.dll" + delete "$INSTDIR\ffmpeg.dll" delete "$INSTDIR\icudtl.dat" - delete "$INSTDIR\icudt.dll" + delete "$INSTDIR\index.html" delete "$INSTDIR\libEGL.dll" delete "$INSTDIR\libGLESv2.dll" - delete "$INSTDIR\nw.pak" - delete "$INSTDIR\pdf.dll" - delete "$INSTDIR\icons\icon_32x32.png" - delete "$INSTDIR\icons\pokemonshowdown.ico" - delete "$INSTDIR\data\icon_32x32.png" - delete "$INSTDIR\data\pokemonshowdown.ico" - rmDir "$INSTDIR\icons" - rmDir "$INSTDIR\data" - rmDir "$INSTDIR\locales" + delete "$INSTDIR\natives_blob.bin" + delete "$INSTDIR\node.dll" + delete "$INSTDIR\notification_helper.exe" + delete "$INSTDIR\nw.dll" + delete "$INSTDIR\pokemonshowdown.exe" + delete "$INSTDIR\nw_100_percent.pak" + delete "$INSTDIR\nw_200_percent.pak" + delete "$INSTDIR\nw_elf.dll" + delete "$INSTDIR\package.json" + delete "$INSTDIR\resources.pak" + delete "$INSTDIR\v8_context_snapshot.bin" # Always delete uninstaller as the last action delete $INSTDIR\uninstall.exe diff --git a/desktop/sign-mac-app b/desktop/sign-mac-app new file mode 100755 index 000000000..672033ed7 --- /dev/null +++ b/desktop/sign-mac-app @@ -0,0 +1,76 @@ +#!/usr/bin/env node + +const APP = "path/to/Pokemon Showdown.app"; +const IDENTITY = "identity of Developer ID cert"; + +/****************************************************************************/ + +console.log("### finding things to sign"); + +const fs = require('fs'); +const child_process = require('child_process'); + +const items = []; + +const frameworksDir = `${APP}/Contents/Frameworks/nwjs Framework.framework`; + +let currentVersionDir; +for (const dir of fs.readdirSync(`${frameworksDir}/Versions`)) { + if (fs.statSync(`${frameworksDir}/Versions/${dir}`).isDirectory) { + currentVersionDir = `${frameworksDir}/Versions/${dir}`; + break; + } +} +if (!currentVersionDir) { + console.error(`couldn't find "${frameworksDir}/Versions/[version]"`); + process.exit(1); +} +for (const file of fs.readdirSync(`${currentVersionDir}`)) { + if (file.endsWith('.dylib')) { + items.push(`${currentVersionDir}/${file}`); + } +} +for (const file of fs.readdirSync(`${currentVersionDir}/Helpers`)) { + if (/^[a-z0-9_]*$/.test(file) || file.endsWith('.app')) { + items.push(`${currentVersionDir}/Helpers/${file}`); + } +} +for (const file of fs.readdirSync(`${currentVersionDir}/Libraries`)) { + if (file.endsWith('.dylib')) { + items.push(`${currentVersionDir}/Libraries/${file}`); + } +} +for (const file of fs.readdirSync(`${currentVersionDir}/XPCServices`)) { + if (file.endsWith('.xpc')) { + items.push(`${currentVersionDir}/XPCServices/${file}`); + } +} +items.push(frameworksDir); + +/****************************************************************************/ + +console.log(""); +console.log("### signing"); + +function exec(cmd) { + console.log(cmd); + const result = child_process.spawnSync(cmd, {shell: true, stdio: 'inherit'}); + if (result.status !== 0) { + console.log(`Command failed with status ${result.status}`); + if (result.error) console.log(result.error); + process.exit(1); + } +} + +for (const item of items) { + exec(`codesign --verbose --force --deep --strict --options runtime --timestamp --sign "${IDENTITY}" --entitlements nwjs-entitlements.entitlements "${item}"`); +} + +exec(`codesign --verbose --force --deep --strict --options runtime --timestamp --sign "${IDENTITY}" --entitlements nwjs-entitlements.entitlements "${APP}"`); + +/****************************************************************************/ + +console.log(""); +console.log("### verifying signature"); + +exec(`codesign --verify -vvvv "${APP}"`);