patch-mac-updater.mjs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. // Adapted from OpenMausBot 13c5005b (Apache-2.0). See licenses/OpenMausBot.
  2. // electron-updater 6.8.9 resolves the Mac download when its local HTTP response
  3. // finishes, before Squirrel validates/extracts the ZIP. Wait for native ready
  4. // instead, and never arm a future quit from a premature Restart request.
  5. // Exact, single-site replacements deliberately fail closed on upstream changes.
  6. export function patchMacUpdater(source) {
  7. function replace(before, after) {
  8. const count = source.split(before).length - 1;
  9. if (count !== 1) throw new Error(`Expected one Mac updater site to patch, found ${count}: ${before.slice(0, 80)}`);
  10. source = source.replace(before, after);
  11. }
  12. replace(
  13. ' return await new Promise((resolve, reject) => {\n const pass =',
  14. ` this.squirrelDownloadedUpdate = false;
  15. return await new Promise((resolve, reject) => {
  16. const cleanup = () => {
  17. this.nativeUpdater.removeListener("error", fail);
  18. this.nativeUpdater.removeListener("update-downloaded", ready);
  19. this.server?.removeListener("error", fail);
  20. };
  21. const fail = (error) => { cleanup(); reject(error); };
  22. const ready = () => { cleanup(); resolve([]); };
  23. this.server.once("error", fail);
  24. const pass =`,
  25. );
  26. replace(
  27. ` let errorOccurred = false;
  28. response.on("finish", () => {
  29. if (!errorOccurred) {
  30. this.nativeUpdater.removeListener("error", reject);
  31. resolve([]);
  32. }
  33. });
  34. `,
  35. "",
  36. );
  37. replace(
  38. ` errorOccurred = true;
  39. this.nativeUpdater.removeListener("error", reject);
  40. reject(new Error(\`Cannot pipe "\${downloadedFile}": \${error}\`));`,
  41. ' fail(new Error(`Cannot pipe "${downloadedFile}": ${error}`));',
  42. );
  43. replace(
  44. ` this.nativeUpdater.setFeedURL({
  45. url: getServerUrl(this.server),
  46. headers: {
  47. "Cache-Control": "no-cache",
  48. Authorization: \`Basic \${authInfo.toString("base64")}\`
  49. }
  50. });
  51. this.dispatchUpdateDownloaded(event);
  52. if (this.autoInstallOnAppQuit) {
  53. this.nativeUpdater.once("error", reject);
  54. this.nativeUpdater.checkForUpdates();
  55. } else {
  56. resolve([]);
  57. }`,
  58. ` try {
  59. this.nativeUpdater.setFeedURL({
  60. url: getServerUrl(this.server),
  61. headers: {
  62. "Cache-Control": "no-cache",
  63. Authorization: \`Basic \${authInfo.toString("base64")}\`
  64. }
  65. });
  66. this.dispatchUpdateDownloaded(event);
  67. if (this.autoInstallOnAppQuit) {
  68. this.nativeUpdater.once("error", fail);
  69. this.nativeUpdater.once("update-downloaded", ready);
  70. this.nativeUpdater.checkForUpdates();
  71. } else {
  72. ready();
  73. }
  74. } catch (error) {
  75. fail(error);
  76. }`,
  77. );
  78. replace(
  79. ` this.nativeUpdater.on("update-downloaded", () => this.handleUpdateDownloaded());
  80. if (!this.autoInstallOnAppQuit) {
  81. this.nativeUpdater.checkForUpdates();
  82. }`,
  83. ' throw new Error("The native Mac update is not ready to install.");',
  84. );
  85. return source;
  86. }