Skip to content

Conversation

@slice
Copy link

@slice slice commented Dec 16, 2024

This patch aims to implement proper persistence on Darwin (macOS) by reapplying the injector when an update finishes. It also forcibly signs the bundle to ensure that it has a stable Designated Requirement, which is important for e.g. screen sharing and keybinds to work consistently.

Currently, it's hardcoded to use a code signing identity named Moonlight. This should be made configurable at some point.

This doesn't work at the moment because it introduces some kind of race against the app becoming ready:

[INFO] [core/extension/loader] Loaded 10 extensions
[DEBUG] [core/persist] Inferred bundle path: /Applications/Discord.app
[DEBUG] [core/darwin] Invoking codesign with args: [ '--verify', '-vvv', '/Applications/Discord.app' ]
[DEBUG] [core/darwin] Spawned codesign (pid: 58755)
[DEBUG] [core/darwin] codesign stderr: --prepared:/Applications/Discord.app/Contents/Frameworks/Discord Helper (GPU).app
--validated:/Applications/Discord.app/Contents/Frameworks/Discord Helper (GPU).app
--prepared:/Applications/Discord.app/Contents/Frameworks/Discord Helper.app
--validated:/Applications/Discord.app/Contents/Frameworks/Discord Helper.app
--prepared:/Applications/Discord.app/Contents/Frameworks/ReactiveObjC.framework/Versions/Current/.
--validated:/Applications/Discord.app/Contents/Frameworks/ReactiveObjC.framework/Versions/Current/.
--prepared:/Applications/Discord.app/Contents/Frameworks/Mantle.framework/Versions/Current/.
--validated:/Applications/Discord.app/Contents/Frameworks/Mantle.framework/Versions/Current/.
--prepared:/Applications/Discord.app/Contents/Frameworks/Squirrel.framework/Versions/Current/.
--validated:/Applications/Discord.app/Contents/Frameworks/Squirrel.framework/Versions/Current/.
--prepared:/Applications/Discord.app/Contents/Frameworks/Discord Helper (Renderer).app
--validated:/Applications/Discord.app/Contents/Frameworks/Discord Helper (Renderer).app
--prepared:/Applications/Discord.app/Contents/Frameworks/Discord Helper (Plugin).app
--validated:/Applications/Discord.app/Contents/Frameworks/Discord Helper (Plugin).app
--prepared:/Applications/Discord.app/Contents/Frameworks/Electron Framework.framework/Versions/Current/.
--validated:/Applications/Discord.app/Contents/Frameworks/Electron Framework.framework/Versions/Current/.
/Applications/Discord.app: valid on disk
/Applications/Discord.app: satisfies its Designated Requirement

[DEBUG] [core/darwin] codesign peacefully exited
[WARN] [core/persist] Bundle is currently passing code signing, no need to sign
Discord 0.0.323
(node:58754) UnhandledPromiseRejectionWarning: Error: protocol.registerSchemesAsPrivileged should be called before app is ready
    at Object.beforeReadyProtocolRegistration (/Applications/Discord.app/Contents/Resources/_app.asar/app_bootstrap/protocols.js:10:22)
    at Object.<anonymous> (/Applications/Discord.app/Contents/Resources/_app.asar/app_bootstrap/bootstrap.js:213:20)
    at Module._compile (node:internal/modules/cjs/loader:1373:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1432:10)
    at Module.load (node:internal/modules/cjs/loader:1215:32)
    at Module._load (node:internal/modules/cjs/loader:1031:12)
    at c._load (node:electron/js2c/node_init:2:17025)
    at Module.require (node:internal/modules/cjs/loader:1240:19)
    at require (node:internal/modules/helpers:179:18)
    at Object.<anonymous> (/Applications/Discord.app/Contents/Resources/_app.asar/app_bootstrap/index.js:17:3)
    at emitUnhandledRejectionWarning (node:internal/process/promises:298:15)
    at warnWithErrorCodeUnhandledRejectionsMode (node:internal/process/promises:406:5)
    at processPromiseRejections (node:internal/process/promises:470:17)
    at process.processTicksAndRejections (node:internal/process/task_queues:96:32)
(node:58754) Error: protocol.registerSchemesAsPrivileged should be called before app is ready
    at Object.beforeReadyProtocolRegistration (/Applications/Discord.app/Contents/Resources/_app.asar/app_bootstrap/protocols.js:10:22)
    at Object.<anonymous> (/Applications/Discord.app/Contents/Resources/_app.asar/app_bootstrap/bootstrap.js:213:20)
    at Module._compile (node:internal/modules/cjs/loader:1373:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1432:10)
    at Module.load (node:internal/modules/cjs/loader:1215:32)
    at Module._load (node:internal/modules/cjs/loader:1031:12)
    at c._load (node:electron/js2c/node_init:2:17025)
    at Module.require (node:internal/modules/cjs/loader:1240:19)
    at require (node:internal/modules/helpers:179:18)
    at Object.<anonymous> (/Applications/Discord.app/Contents/Resources/_app.asar/app_bootstrap/index.js:17:3)

The code signing process succeeds, but by the time registerSchemesAsPrivileged runs (a function in Discord's ASAR) the app is already ready for some reason.

As I was repeatedly re-running this I managed to get past the error and get this one:

2024-12-15 17:15:33.521 Discord[59145:2331708] Download completed to: file:///Users/skip/Library/Caches/com.hnc.Discord.ShipIt/update.DX5Y9Kz/Discord.zip
2024-12-16T01:15:34.140Z [Modules] Host update failed: Error: Code signature at URL file:///Users/skip/Library/Caches/com.hnc.Discord.ShipIt/update.DX5Y9Kz/Discord.app/ did not pass validation: code failed to satisfy specified code requirement(s)

According to Squirrel, the update bundle needs to match the DR of the target bundle, so we might need to actually sign Discord in moonlight's installer. Doing it from within core seems a bit precarious because macOS might not recognize the designated requirement changing on the fly like that.

@slice slice force-pushed the skip/darwin-persist branch from 40593c9 to 8025fae Compare December 16, 2024 01:42
I missed that hookUpdaterForPersistence (FKA persistAsar) merely hooks
into the updater, so we need to run it inside of the hooked emit method.
Those are synchronous, so our shelling out to codesign(1) needs to be
synchronous, too. This blocks the updater. Not sure if this can somehow
be async instead.
@adryd325 adryd325 self-assigned this Dec 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants