Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't start app from ZIP artifact #4299

Closed
pashvin opened this issue Oct 8, 2019 · 86 comments · Fixed by #6023
Closed

Can't start app from ZIP artifact #4299

pashvin opened this issue Oct 8, 2019 · 86 comments · Fixed by #6023

Comments

@pashvin
Copy link

pashvin commented Oct 8, 2019

  • Version: 21.2.0
6.x
  • Target: Mac/zip

Extract app from ZIP and try to start it, fails with "The application xyz can't be opened".

@pashvin pashvin changed the title Can start app from ZIP artifact Can't start app from ZIP artifact Oct 8, 2019
@jsgv
Copy link

jsgv commented Oct 8, 2019

I am experiencing the same thing.

I can open an unsigned build, but not a zipped up signed build.

macOS: Catalina 10.15
npm: 6.11.3
electron-builder: 21.2.0

@jsgv
Copy link

jsgv commented Oct 8, 2019

Partially solved with electron-notarize.

Due to Apple requirements on Catalina OS. https://developer.apple.com/news/?id=04102019a

@jookyboi
Copy link

jookyboi commented Oct 9, 2019

@jsgv I'm using electron_notarize and it still fails for the same reason. Can you say more about how you got it to work?

@jookyboi
Copy link

jookyboi commented Oct 9, 2019

Update: I've tried just compressing the .app/ folder with Finder->Compress and the unzipped app works fine on Catalina. It has something to do with the 7z compressor used from 7zip-bin. In the meantime, I'm trying to just use the native zip command to compress the folder.

@jsgv
Copy link

jsgv commented Oct 9, 2019

@jookyboi I mostly followed this article:
https://medium.com/@TwitterArchiveEraser/notarize-electron-apps-7a5f988406db

Important details is creating the 'App-specific password'. Your regular apple credentials will not work.
https://support.apple.com/HT204397

Note: The ZIPPED app still fails to open, but the DMG works.
I have not tested the auto-update functionality, but I have read that it is also failing for now.

@jookyboi
Copy link

jookyboi commented Oct 9, 2019

@jsgv I don't have an issue notarizing the app (and neither does the issuer filer). It has to do with using the zip build target for macOS. Something about the way 7z is compressing the app folder causes Catalina to reject opening the unzipped app.

@jsgv
Copy link

jsgv commented Oct 9, 2019

@jsgv I don't have an issue notarizing the app (and neither does the issuer filer). It has to do with using the zip build target for macOS. Something about the way 7z is compressing the app folder causes Catalina to reject opening the unzipped app.

@jookyboi You are correct. My mistake.

@jookyboi
Copy link

jookyboi commented Oct 9, 2019

Update: Running from my Electron app's root folder:
../../node_modules/7zip-bin-mac/7za a -mm=Deflate -r [path_to_zip] [MyApp.app/]gives me a decently compressed zip file which still works fine on Catalina.

Can @develar look into removing some of the optional arguments for 7z to get things working again?

export function compute7zCompressArgs(format: string, options: ArchiveOptions = {}) {

@jookyboi
Copy link

jookyboi commented Oct 9, 2019

Update: 7zip has nothing to do with it. I tried with the max compression option from the command line and that still worked okay on Catalina. Something happening between zipping and final output is causing the issue.

@pashvin
Copy link
Author

pashvin commented Oct 9, 2019

My application is notarized so there is no issue with it, having said that I don't know zip artifact waits for notarization to be finish. I can try to compare content from zip app vs dmg app and see that has any difference

@pashvin
Copy link
Author

pashvin commented Oct 9, 2019

Ok I used following command to check app notarized or not from dmg and zip and it is confirmed that zip picked up app before notarization is done.

Command to check status of app:
codesign --test-requirement="=notarized" --verify --verbose <appname.app>

@jookyboi
Copy link

jookyboi commented Oct 9, 2019

@pashvin Good find. So the issue is that the folder get zipped up before notarization is complete? It just feels strange as my build process resulted in a properly notarized zipped app in Mojave.

How does this relate to the fact that the executable in the unzipped .app/ folder doesn't get execute permissions?

@jookyboi
Copy link

Here is the workaround I'm using until the problem gets fixed: https://snippets.cacher.io/snippet/354a3eb7b0dcbe711383

@bigshahan
Copy link

We've been experiencing the same issue and using a workaround similar to @jookyboi's.

@stevenroussey-privicy
Copy link

The last couple of days Apple has had issues with notarization, which if you do it by hand you would have noticed how long it took. Curious if the timing bug disappears when apple is running more smoothly today.

@pashvin
Copy link
Author

pashvin commented Oct 11, 2019

No this is not a timing issue. This is always reproducible. I know notarization takes some time long and some time it is fast but I am tracking this issue from almost month and we have every day build. Every build has the same issue.

@jookyboi
Copy link

jookyboi commented Oct 11, 2019

Update: Found the culprit: https://github.com/electron-userland/electron-builder/blob/master/packages/app-builder-lib/src/targets/ArchiveTarget.ts#L65

After creating the zip, the default behavior for ArchiveTarget is to append the .blockmap to the file, then calculate the blockmapsize from that. This is in the name of doing differential updates.. though I've never seen electron-updater update this way for macOS.

I dug into node_modules/app-builder-lib/out/targets/ArchiveTarget.js and commented out this functionality:

if (this.isWriteUpdateInfo && format === "zip") {
  // updateInfo = await (0, _differentialUpdateInfoBuilder().appendBlockmap)(artifactPath);
}

The resulting latest-mac.yml will be missing the blockmapsize attribute but it doesn't seem to matter for me.

The resulting zip works fine on Catalina as does the auto-update functionality.


My theory is that by altering the zip file in this way (after compressing the notarized .app/ folder), we're confusing Catalina's Gatekeeper functionality.

@pashvin
Copy link
Author

pashvin commented Oct 14, 2019

Yes once app is signed by apple, any modification will make signature invalid. I think those item must be added (if really required) before starting app notarization. Looks like we have some solution and need to generate an official build with fix.

@jookyboi
Copy link

I think the correct course of action would be to append the blockmapsize attribute, create the zip, then notarize the zip file itself. According to the docs, this should be possible: https://developer.apple.com/documentation/security/notarizing_your_app_before_distribution

@pashvin
Copy link
Author

pashvin commented Oct 15, 2019

There is no need to notarize zip, if anything is added to .app, then it need to be added before it sent for notarization so correct fix is add everything to .app before notarization start and then make zip once notarization is done. remember ZIP is not complaining anything , it extracts fine but .app is not able to start.

@pashvin
Copy link
Author

pashvin commented Oct 21, 2019

what is the next step to get the fix. I think we already proved that this is a real issue so to get the fix what is the next step? Need to assign to some developer? Waiting for fix for this issue almost 3 month.
I can't go back to older version because in that case i do not get any way to notarize app.

@semireg
Copy link

semireg commented Oct 21, 2019

This is a very strange issue and I'll mention my findings because I haven't seen it mentioned here.

I had multiple Catalina users report "The application Label LIVE can't be opened." I downloaded and the app worked fine on Catalina. URL for reference and public reproduction: http://label.live/download.

I finally screen-shared (via Zoom) with a user and sure enough, the download app didn't work. They were using Chrome and the zip file was being decompressed by Archive Utility. I had the user download the same zip using Safari and presto, the decompressed app launched no problem. I have given this advice to other users with varying success. I believe that Safari users must have "Open safe files after downloading" checked. If not, then the Archive Utility is launched to unzip - causing the issue.

2019-10-21 at 3 02 PM

In all of my own tests I was decompressing with Safari's built-in unzipper (whatever that is)... can anyone confirm this issue with their builds? I'm skeptical that I'm the only one to notice this behavior...

@ansgarschulte
Copy link

@semireg I can confirm, that Safari downloaded app works for me and Chrome downloaded and Finder unzipped does not.

@semireg
Copy link

semireg commented Oct 22, 2019

Apple developer support confirmed and helped me understand the issue. 🙌

The problem is that Archive Utility (only on Catalina) fails to create the proper symlinks when unpacking, whereas Safari "open safe" does create the symlinks as expected. An example of this is Contents/Frameworks/Electron Framework.framework/Versions/Current -> A

But, before we can blame Archive Utility, consider that unzip (on both Mojave and Catalina) fails to list the contents of the zip:

unzip -l Label-LIVE-1.4.6-10406006.zip
Archive:  Label-LIVE-1.4.6-10406006.zip
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of Label-LIVE-1.4.6-10406006.zip or
        Label-LIVE-1.4.6-10406006.zip.zip, and cannot find Label-LIVE-1.4.6-10406006.zip.ZIP, period.

Apple developer support recommended ditto to create the zip, but I'm not sure if this is our end goal... I have not looked into how to fix/work-around electron-builder. Looking for help with that! 😅

/usr/bin/ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH"
Reference: https://developer.apple.com/documentation/security/notarizing_your_app_before_distribution/customizing_the_notarization_workflow

Apple developer support also recommended filing a bug on this. I filed bug FB7400365 that describes this regression in Catalina's Archive Utility.

@stale
Copy link

stale bot commented Jun 7, 2021

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

@stale stale bot added the backlog label Jun 7, 2021
@vitor251093
Copy link

It is still relevant.

@vitor251093
Copy link

Also, according to AWstats from cPanel, it seems that the automatic update system is downloading both the zip and the dmg for most of my users. I assume it's downloading the zip, noticing it was broken, and then downloading the dmg to solve the problem. I've recently made the dmg the default download (which is what I assume the path and sha512 of the YML root is), so I expect to put that theory to the test soon.

@stale stale bot removed the backlog label Jun 7, 2021
@fmiceli24
Copy link

Still relevant!!!! I have to edit node_modules/app-builder-lib/out/targets/ArchiveTarget.js as explained below just to have a zip file that makes the updater work.

Update: Found the culprit: https://github.com/electron-userland/electron-builder/blob/master/packages/app-builder-lib/src/targets/ArchiveTarget.ts#L65

After creating the zip, the default behavior for ArchiveTarget is to append the .blockmap to the file, then calculate the blockmapsize from that. This is in the name of doing differential updates.. though I've never seen electron-updater update this way for macOS.

I dug into node_modules/app-builder-lib/out/targets/ArchiveTarget.js and commented out this functionality:

if (this.isWriteUpdateInfo && format === "zip") {
  // updateInfo = await (0, _differentialUpdateInfoBuilder().appendBlockmap)(artifactPath);
}

The resulting latest-mac.yml will be missing the blockmapsize attribute but it doesn't seem to matter for me.

The resulting zip works fine on Catalina as does the auto-update functionality.

My theory is that by altering the zip file in this way (after compressing the notarized .app/ folder), we're confusing Catalina's Gatekeeper functionality.

@mmaietta
Copy link
Collaborator

mmaietta commented Jun 8, 2021

@fmiceli24 you can use this with patch-package to have it persist for MacOS builds specifically. I'm not sure what the implications of the blockmap not being present will be for electron-updater.
If it is indeed safe to disable blockmaps for mac zip target, then it's easy to turn this into a PR

app-builder-lib+22.11.5.patch

diff --git a/node_modules/app-builder-lib/out/targets/ArchiveTarget.js b/node_modules/app-builder-lib/out/targets/ArchiveTarget.js
index 77bdfb0..b788d5a 100644
--- a/node_modules/app-builder-lib/out/targets/ArchiveTarget.js
+++ b/node_modules/app-builder-lib/out/targets/ArchiveTarget.js
@@ -59,7 +59,8 @@ class ArchiveTarget extends core_1.Target {
                 withoutDir,
             };
             await archive_1.archive(format, artifactPath, dirToArchive, archiveOptions);
-            if (this.isWriteUpdateInfo && format === "zip") {
+            // Disabled for mac zips: https://github.com/electron-userland/electron-builder/issues/4299
+            if (this.isWriteUpdateInfo && format === "zip" && !isMac) {
                 updateInfo = await differentialUpdateInfoBuilder_1.appendBlockmap(artifactPath);
             }
         }

@vitor251093
Copy link

Thanks to @jookyboi 's 7za command, I've managed to replace the ZIP file with a functional one, but latest-mac-yml still had the info from the original ZIP file, so I had to create the JS file below, which receives the app version as an argument to work:

const fs = require('fs')
const yaml = require('yaml')
const child_process = require('child_process')

var args = process.argv.slice(2);
var version = args[0]

var filePath = './dist/latest-mac.yml'
var dataYaml = fs.readFileSync(filePath, {encoding: 'utf-8'})
var data = yaml.parse(dataYaml)

var zipFilePath = "./dist/My App-{version}-mac.zip".replace("{version}",version)
var regCommand = "shasum -a512 " + zipFilePath.replace(" ", "\\ ")
var output = child_process.execSync(regCommand, {encoding: 'utf-8'})
output = output.split(" ").shift().split("\t").shift()
output = new Buffer(output, 'hex').toString('base64') 
var stats = fs.statSync(zipFilePath)

var zipFile = data.files.filter(e => e.url.endsWith(".zip")).pop()
zipFile.sha512 = output
zipFile.size = stats.size

var dmgFile = data.files.filter(e => e.url.endsWith(".dmg")).pop()
data.path = dmgFile.url
data.sha512 = dmgFile.sha512

fs.writeFile(filePath, yaml.stringify(data), 'utf-8', function(){});

This is definitively just a workaround, and it requires yaml, but at least it is a workaround that worked for me, and that may work for someone else, so I decided to post it here.

@fmiceli24
Copy link

diff --git a/node_modules/app-builder-lib/out/targets/ArchiveTarget.js b/node_modules/app-builder-lib/out/targets/ArchiveTarget.js
index 77bdfb0..b788d5a 100644
--- a/node_modules/app-builder-lib/out/targets/ArchiveTarget.js
+++ b/node_modules/app-builder-lib/out/targets/ArchiveTarget.js
@@ -59,7 +59,8 @@ class ArchiveTarget extends core_1.Target {
withoutDir,
};
await archive_1.archive(format, artifactPath, dirToArchive, archiveOptions);

  •        if (this.isWriteUpdateInfo && format === "zip") {
    
  •        // Disabled for mac zips: https://github.com/electron-userland/electron-builder/issues/4299
    
  •        if (this.isWriteUpdateInfo && format === "zip" && !isMac) {
               updateInfo = await differentialUpdateInfoBuilder_1.appendBlockmap(artifactPath);
           }
       }
    

Thanks. Did that in order to have it streamlined. I am not using the blockmap. I understand this is for delta updates, right?

If delta updates are not working on OSX, and enabling the blockmap breaks updates altogether, would it be possible to have this workaround implemented upstream in order to avoid patching?

@sourabhverificient
Copy link

My application is notarized so there is no issue with it, having said that I don't know zip artifact waits for notarization to be finish. I can try to compare content from zip app vs dmg app and see that has any difference

i am getting same issue even after notrization

@sourabhverificient
Copy link

sourabhverificient commented Jun 22, 2021

i ### solved this problem by using different target packaging in electron-builder "tar.xz"

"mac": {
"target": ["tar.xz", "7z"]
},

@gniezen
Copy link
Contributor

gniezen commented Jun 23, 2021

i ### solved this problem by using different target packaging in electron-builder "tar.xz"

Correct me if I'm wrong, but doesn't Squirrel.Mac require .zip artefacts? See (2) in Note here: https://www.electron.build/auto-update#quick-setup-guide

@sourabhverificient
Copy link

i ### solved this problem by using different target packaging in electron-builder "tar.xz"

Correct me if I'm wrong, but doesn't Squirrel.Mac require .zip artefacts? See (2) in Note here: https://www.electron.build/auto-update#quick-setup-guide

your right , in my use case i just wanted to compressed app which can launch after unzip i am not planning to autoupdate it at this moment.

@RobertLowe
Copy link

After a lot of pain I finally got this working, I spent more time figuring out codesign-ing and this issue than I did developing my app.

You can see my implementation here: https://github.com/RobertLowe/force-audio which is based on https://gist.github.com/harshitsilly/a1bd5a405f93966aad20358ae6c4cec5

I use a two step process:

  1. build the release as electron-builder wants,
  2. run the patcher AND reupload (and overwrite) to github releases.

mmaietta added a commit to mmaietta/electron-builder that referenced this issue Jul 4, 2021
@mmaietta
Copy link
Collaborator

mmaietta commented Jul 4, 2021

I discovered that I can just swap it to generate an external .blockmap file so the zip isn't modified. Opened PR #6023

mmaietta added a commit that referenced this issue Jul 4, 2021
* building separate blockmap instead of embedding on mac since embedded blockmap breaks codesigning. fixes: #4299
@0xdeafcafe
Copy link

@mmaietta Just used your changes in my local node_modules folder and this does work perfectly 🎉, thank you so much! Do you know when the change will make it over to npm?

@mmaietta
Copy link
Collaborator

@0xdeafcafe I've just published next v22.11.9 to npm 🙂
https://github.com/electron-userland/electron-builder/releases/tag/v22.11.9

Please note though...this issue was just reported but I've not been able to repro it in my 2 projects. So that's why I've published it as next
#6045
If anyone could confirm if they experience the issue, please comment on that ticket and any additional debug data would be immensely helpful.

@Vishal1419
Copy link

Writing this comment to help someone else facing the same issue in future.

I am using MacOS Mojave for development purposes
I was using electron-builder v22.9.x and creating a zip file
Then I was transferring generated .zip to my new laptop with MacOS Monterey via slack
Then I was using Archive Utility to unzip the app. (If I use The Unarchiever it worked fine)
I always got the error: Application cannot be opened

But when I saw above message from @mmaietta, I updated electron builder to v22.13.1 and then repeated the same process
Now, I can see that blockmap file is generated correctly and my app on MacOS Monterey opens up correctly.

Thank you @mmaietta for resolving the issue.

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 a pull request may close this issue.