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

electron-updater and GitHub Releases from a private repo (2nd attempt) #2314

Closed
naheller opened this issue Nov 20, 2017 · 10 comments
Closed

Comments

@naheller
Copy link

naheller commented Nov 20, 2017

Hello, and thanks @develar for your continued support! My previous issue #2292 was closed prematurely and may have since been buried.

Here's the quick summary: I'm building an app for use by employees at my company. I would like to use GitHub Releases to serve updates from a private repository. Can I do this by setting a token in the app's package.json as follows?

"build": {
    "appId": "com.github.<owner>.repo",
    "productName": "Training Tracker",
    "files": [
      "dist",
      "node_modules",
      "main.js",
      "package.json"
    ],
    "directories": {
      "output": "output"
    },
    "mac": {
      "publish": {
        "provider": "github",
        "private": true,
        "token": "<token>"
      },
      "target": [
        "zip",
        "dmg"
      ]
    }
  }

My main.js simply imports electron-updater and calls autoUpdater.checkForUpdatesAndNotify() when the app is ready. On startup, however, I get the following error in my logs:

[error] Error: Error: Unable to find latest version on GitHub (https://api.github.com/repos/<owner>/training-tracker/releases/latest), please ensure a production release exists followed by ERR_CONNECTION_REFUSED.

Following the link above, I see this in my browser:

{
  "message": "Not Found",
  "documentation_url": "https://developer.github.com/v3/repos/releases/#get-the-latest-release"
}

What am I missing? Your advice is appreciated!

@MarkusBansky
Copy link

You need to set process.env.GH_TOKEN in your main.js instead of package.json
And also set environment variable on your system

@naheller
Copy link
Author

@MarkusBansky Thanks for your reply! What about users who do not have a GH_TOKEN set on their systems? Is main.js able to reach into their ~/.bash_profile and set the token when I set process.env.GH_TOKEN?

@MarkusBansky
Copy link

MarkusBansky commented Nov 21, 2017

You need to set process.env.GH_TOKEN in main.js only, the environment variable is for your system only, to release the build to github, users should not see the token
Look at the documentation

@ghost
Copy link

ghost commented Jan 22, 2018

For what it's worth, I had to go about it a different way. I didn't want to hard-code my GitHub Repo Token inside the application (it's not a read-only token), so as soon as the user of my application logs in, the app retrieves the GH token from my server and uses it to construct the setFeedURL for the updater just before it checks for updates:

ipcMain.on('autoUpdate.status', (evt, token) => {
  const data = {
    'provider': 'github',
    'owner':    '<owner-name>',
    'repo':     '<repo-name>',
    'token':    token
  };
  updater.setFeedURL(data);
  updater.autoDownload = false;
  updater.checkForUpdates();
});

@CydeSwype
Copy link
Contributor

CydeSwype commented Jan 30, 2018

Really glad you guys got to the bottom of how to use setFeedURL! I wasn't able to figure this out from the docs.

A couple notes on GH tokens and private repos:
I had a similar need but was not comfortable with the app storing a GH key. The fundamental problem with GH private repos being used in this way is that GH doesn't have granular ACL. They have a single token that has VERY broad permissions and it's dangerous for anyone outside your org to have access to that. The solution I use: I make a request from the app to my web server (using the "provider: generic" type) which then makes a GH API request for the latest.yml file asset and returns it. Having a web server I control in the middle of the flow between the app and GH allows me to throttle access to just the yml files and binary files (and not allow someone to delete releases, modify info, etc. which can all be done with the private token).

I still need to use setFeedURL in order to test a new build (including updating to it) before distributing it to my install base. setFeedURL allows me to reference a "prerelease" or a "beta" channel so I can QA the upgrade to the new app. Now I just need to build a settings flag I can flip in the frontend of the app!

I think the docs should be updated since saying "don't use setFeedURL" is misleading (especially when in the same doc it describes the method and its parameters). Any takers? If not, I'll try to update and send a PR (but @nbcnc should get credit for this one).

@marceloavf
Copy link
Contributor

@CydeSwype It costs to the server having to stream the file using transfer bandwidth or you give it through another way?

@ghost
Copy link

ghost commented Apr 11, 2018

Update from my earlier comment on Jan 22nd: auto updater has stopped working for GitHub private repos (and public repos from what I understand, though I haven't tested this independently). I have since switched my releases to use AWS S3 bucket and it is working.

See this thread:
#2508

@CydeSwype
Copy link
Contributor

@marceloavf yes there is a cost to stream the yml file, but it's a short text file, so cost is nominal (acceptable for our for-profit company's use case). You're right in assuming that the solution I mentioned of sitting in the middle of the request to provide more granular access control requires that the file transfer ALSO needs to go through that same service. If ever the end-user/client is making a direct request to GH with that token, they could discover that and use the token for any other purpose (i.e. deleting releases).

@nbcnc I couldn't get reliable streaming of the binary files from GH with private repo (frequent timeouts on download) so we ended up writing a script to copy new build binaries to Google Cloud Storage. We still reference the yml files in our private GitHub repo that the desktop app checks to see if there's a new binary to download, but when the yml file references a newer version, the desktop app hits our webserver and then redirects that request to GCS for the actual binary. This set up has been very reliable for us.

@harrypotter033
Copy link

For what it's worth, I had to go about it a different way. I didn't want to hard-code my GitHub Repo Token inside the application (it's not a read-only token), so as soon as the user of my application logs in, the app retrieves the GH token from my server and uses it to construct the setFeedURL for the updater just before it checks for updates:

ipcMain.on('autoUpdate.status', (evt, token) => {
  const data = {
    'provider': 'github',
    'owner':    '<owner-name>',
    'repo':     '<repo-name>',
    'token':    token
  };
  updater.setFeedURL(data);
  updater.autoDownload = false;
  updater.checkForUpdates();
});

I try this way, but it still says in log authentication failed . TOken is invalid.

@irafaelfurtado
Copy link

irafaelfurtado commented Jul 16, 2020

For what it's worth, I had to go about it a different way. I didn't want to hard-code my GitHub Repo Token inside the application (it's not a read-only token), so as soon as the user of my application logs in, the app retrieves the GH token from my server and uses it to construct the setFeedURL for the updater just before it checks for updates:

ipcMain.on('autoUpdate.status', (evt, token) => {
  const data = {
    'provider': 'github',
    'owner':    '<owner-name>',
    'repo':     '<repo-name>',
    'token':    token
  };
  updater.setFeedURL(data);
  updater.autoDownload = false;
  updater.checkForUpdates();
});

I try this way, but it still says in log authentication failed . TOken is invalid.

Hello @hmpargi, I know this seems to be old, but I'm sure you should help your next colleagues with this difficulty.
You must specify that you are accessing a private repository as follows: private: true
See below for a working example so far.

const data = {
    provider: 'github',
    owner:    '<owner-name>',
    repo:     '<repo-name>',
    token:    token,
    private: true,
  };

NOTE: Be careful when using this method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants