|
@@ -3,121 +3,97 @@
|
|
|
package client
|
|
|
|
|
|
import (
|
|
|
+ "fmt"
|
|
|
update "github.com/inconshreveable/go-update"
|
|
|
- "net/http"
|
|
|
- "net/url"
|
|
|
+ "github.com/inconshreveable/go-update/check"
|
|
|
"ngrok/client/mvc"
|
|
|
"ngrok/log"
|
|
|
"ngrok/version"
|
|
|
- "runtime"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
-const (
|
|
|
- updateEndpoint = "https://dl.ngrok.com/update"
|
|
|
- checkEndpoint = "https://dl.ngrok.com/update/check"
|
|
|
-)
|
|
|
-
|
|
|
-func progressWatcher(s mvc.State, progress chan int, complete chan int) {
|
|
|
- for {
|
|
|
- select {
|
|
|
- case pct, ok := <-progress:
|
|
|
- if !ok {
|
|
|
- close(complete)
|
|
|
- return
|
|
|
- } else if pct == 100 {
|
|
|
- s.SetUpdateStatus(mvc.UpdateInstalling)
|
|
|
- close(complete)
|
|
|
- return
|
|
|
- } else {
|
|
|
- if pct%25 == 0 {
|
|
|
- log.Info("Downloading update %d%% complete", pct)
|
|
|
- }
|
|
|
- s.SetUpdateStatus(mvc.UpdateStatus(pct))
|
|
|
- }
|
|
|
- }
|
|
|
+const appId = ""
|
|
|
+
|
|
|
+var publicKey []byte = []byte(
|
|
|
+ `-----BEGIN PUBLIC KEY-----
|
|
|
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Gx8r9no1QBtCruJW2tu
|
|
|
+082MJJ5ZA7k803GisR2c6WglPOD1b/+kUg+dx5Y0TKXz+uNlR3GrCxLh8WkoA95M
|
|
|
+T38CQldIjoVN/bWP6jzFxL+6BRoKy5L1TcaIf3xb9B8OhwEq60cvFy7BBrLKEHJN
|
|
|
+ua/D1S5axgNOAJ8tQ2w8gISICd84ng+U9tNMqIcEjUN89h3Z4zablfNIfVkbqbSR
|
|
|
+fnkR9boUaMr6S1w8OeInjWdiab9sUr87GmEo/3tVxrHVCzHB8pzzoZceCkjgI551
|
|
|
+d/hHfAl567YhlkQMNz8dawxBjQwCHHekgC8gAvTO7kmXkAm6YAbpa9kjwgnorPEP
|
|
|
+ywIDAQAB
|
|
|
+-----END PUBLIC KEY-----`)
|
|
|
+var u *update.Update
|
|
|
+var updateEndpoint = fmt.Sprintf("http://localhost:8889/1/Applications/%s/Update", appId)
|
|
|
+
|
|
|
+func init() {
|
|
|
+ var err error
|
|
|
+ u, err = update.New().VerifySignatureWithPEM(publicKey)
|
|
|
+ if err != nil {
|
|
|
+ panic(err)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func autoUpdate(s mvc.State, token string) {
|
|
|
- tryAgain := true
|
|
|
-
|
|
|
- params := make(url.Values)
|
|
|
- params.Add("version", version.MajorMinor())
|
|
|
- params.Add("os", runtime.GOOS)
|
|
|
- params.Add("arch", runtime.GOARCH)
|
|
|
- params.Add("user", token)
|
|
|
-
|
|
|
- updateUrl := updateEndpoint + "?" + params.Encode()
|
|
|
- checkUrl := checkEndpoint + "?" + params.Encode()
|
|
|
-
|
|
|
- update := func() {
|
|
|
+ update := func() (tryAgain bool) {
|
|
|
log.Info("Checking for update")
|
|
|
- available, err := update.NewDownload(checkUrl).Check()
|
|
|
- if err != nil {
|
|
|
- log.Error("Error while checking for update: %v", err)
|
|
|
- return
|
|
|
+ params := check.Params{
|
|
|
+ Version: 1,
|
|
|
+ AppId: appId,
|
|
|
+ AppVersion: version.MajorMinor(),
|
|
|
+ UserId: token,
|
|
|
}
|
|
|
|
|
|
- if !available {
|
|
|
+ result, err := params.CheckForUpdate(updateEndpoint)
|
|
|
+ if err == check.NoUpdateAvailable {
|
|
|
log.Info("No update available")
|
|
|
- return
|
|
|
+ return true
|
|
|
+ } else if err != nil {
|
|
|
+ log.Error("Error while checking for update: %v", err)
|
|
|
+ return true
|
|
|
}
|
|
|
|
|
|
- // stop trying after a single download attempt
|
|
|
- // XXX: improve this so the we can:
|
|
|
- // 1. safely update multiple times
|
|
|
- // 2. only retry after a network connection failure
|
|
|
- tryAgain = false
|
|
|
-
|
|
|
- download := update.NewDownload(updateUrl)
|
|
|
- downloadComplete := make(chan int)
|
|
|
-
|
|
|
- go progressWatcher(s, download.Progress, downloadComplete)
|
|
|
-
|
|
|
- log.Info("Trying to update . . .")
|
|
|
- err, errRecover := download.GetAndUpdate()
|
|
|
- <-downloadComplete
|
|
|
-
|
|
|
- if err != nil {
|
|
|
- // log error to console
|
|
|
- log.Error("Error while updating ngrok: %v", err)
|
|
|
- if errRecover != nil {
|
|
|
- log.Error("Error while recovering from failed ngrok update, your binary may be missing: %v", errRecover.Error())
|
|
|
- params.Add("errorRecover", errRecover.Error())
|
|
|
- }
|
|
|
-
|
|
|
- // log error to ngrok.com's servers for debugging purposes
|
|
|
- params.Add("error", err.Error())
|
|
|
- resp, reportErr := http.PostForm("https://dl.ngrok.com/update/error", params)
|
|
|
- if err != nil {
|
|
|
- log.Error("Error while reporting update error: %v, %v", err, reportErr)
|
|
|
- }
|
|
|
- resp.Body.Close()
|
|
|
-
|
|
|
- // tell the user to update manually
|
|
|
+ if result.Initiative == check.INITIATIVE_AUTO {
|
|
|
+ applyUpdate(s, result)
|
|
|
+ } else if result.Initiative == check.INITIATIVE_MANUAL {
|
|
|
+ // this is the way the server tells us to update manually
|
|
|
+ log.Info("Server wants us to update manually")
|
|
|
s.SetUpdateStatus(mvc.UpdateAvailable)
|
|
|
} else {
|
|
|
- if !download.Available {
|
|
|
- // this is the way the server tells us to update manually
|
|
|
- log.Info("Server wants us to update manually")
|
|
|
- s.SetUpdateStatus(mvc.UpdateAvailable)
|
|
|
- } else {
|
|
|
- // tell the user the update is ready
|
|
|
- log.Info("Update ready!")
|
|
|
- s.SetUpdateStatus(mvc.UpdateReady)
|
|
|
- }
|
|
|
+ log.Info("Update available, but ignoring")
|
|
|
}
|
|
|
|
|
|
- return
|
|
|
+ // stop trying after a single download attempt
|
|
|
+ // XXX: improve this so the we can:
|
|
|
+ // 1. safely update multiple times
|
|
|
+ // 2. only retry after temporary errors
|
|
|
+ return false
|
|
|
}
|
|
|
|
|
|
// try to update immediately and then at a set interval
|
|
|
- update()
|
|
|
- for _ = range time.Tick(updateCheckInterval) {
|
|
|
- if !tryAgain {
|
|
|
+ for {
|
|
|
+ if tryAgain := update(); !tryAgain {
|
|
|
break
|
|
|
}
|
|
|
- update()
|
|
|
+
|
|
|
+ time.Sleep(updateCheckInterval)
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+func applyUpdate(s mvc.State, result *check.Result) {
|
|
|
+ err, errRecover := result.Update(u)
|
|
|
+ if err == nil {
|
|
|
+ log.Info("Update ready!")
|
|
|
+ s.SetUpdateStatus(mvc.UpdateReady)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ log.Error("Error while updating ngrok: %v", err)
|
|
|
+ if errRecover != nil {
|
|
|
+ log.Error("Error while recovering from failed ngrok update, your binary may be missing: %v", errRecover.Error())
|
|
|
+ }
|
|
|
+
|
|
|
+ // tell the user to update manually
|
|
|
+ s.SetUpdateStatus(mvc.UpdateAvailable)
|
|
|
+}
|