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}"`);