github.com/keygen-sh/go-update@v1.0.0/doc.go (about) 1 /* 2 Package update provides functionality to implement secure, self-updating Go programs (or other single-file targets). 3 4 For complete updating solutions please see Equinox (https://equinox.io) and go-tuf (https://github.com/flynn/go-tuf). 5 6 Basic Example 7 8 This example shows how to update a program remotely from a URL. 9 10 import ( 11 "fmt" 12 "net/http" 13 14 "github.com/keygen-sh/go-update" 15 ) 16 17 func doUpdate(url string) error { 18 // request the new file 19 resp, err := http.Get(url) 20 if err != nil { 21 return err 22 } 23 defer resp.Body.Close() 24 err := update.Apply(resp.Body, update.Options{}) 25 if err != nil { 26 if rerr := update.RollbackError(err); rerr != nil { 27 fmt.Println("Failed to rollback from bad update: %v", rerr) 28 } 29 } 30 return err 31 } 32 33 34 Binary Patching 35 36 Go binaries can often be large. It can be advantageous to only ship a binary patch to a client 37 instead of the complete program text of a new version. 38 39 This example shows how to update a program with a bsdiff binary patch. Other patch formats 40 may be applied by implementing the Patcher interface. 41 42 import ( 43 "encoding/hex" 44 "io" 45 46 "github.com/keygen-sh/go-update" 47 ) 48 49 func updateWithPatch(patch io.Reader) error { 50 err := update.Apply(patch, update.Options{ 51 Patcher: update.NewBSDiffPatcher() 52 }) 53 if err != nil { 54 // error handling 55 } 56 return err 57 } 58 59 Checksum Verification 60 61 Updating executable code on a computer can be a dangerous operation unless you 62 take the appropriate steps to guarantee the authenticity of the new code. While 63 checksum verification is important, it should always be combined with signature 64 verification (next section) to guarantee that the code came from a trusted party. 65 66 go-update validates SHA256 checksums by default, but this is pluggable via the Hash 67 property on the Options struct. 68 69 This example shows how to guarantee that the newly-updated binary is verified to 70 have an appropriate checksum (that was otherwise retrived via a secure channel) 71 specified as a hex string. 72 73 import ( 74 "crypto" 75 _ "crypto/sha256" 76 "encoding/hex" 77 "io" 78 79 "github.com/keygen-sh/go-update" 80 ) 81 82 func updateWithChecksum(binary io.Reader, hexChecksum string) error { 83 checksum, err := hex.DecodeString(hexChecksum) 84 if err != nil { 85 return err 86 } 87 err = update.Apply(binary, update.Options{ 88 Hash: crypto.SHA256, // this is the default, you don't need to specify it 89 Checksum: checksum, 90 }) 91 if err != nil { 92 // error handling 93 } 94 return err 95 } 96 97 Cryptographic Signature Verification 98 99 Cryptographic verification of new code from an update is an extremely important way to guarantee the 100 security and integrity of your updates. 101 102 Verification is performed by validating the signature of a hash of the new file. This 103 means nothing changes if you apply your update with a patch. 104 105 This example shows how to add signature verification to your updates. To make all of this work 106 an application distributor must first create a public/private key pair and embed the public key 107 into their application. When they issue a new release, the issuer must sign the new executable file 108 with the private key and distribute the signature along with the update. 109 110 import ( 111 "crypto" 112 _ "crypto/sha256" 113 "encoding/hex" 114 "io" 115 116 "github.com/keygen-sh/go-update" 117 ) 118 119 var publicKey = []byte(` 120 -----BEGIN PUBLIC KEY----- 121 MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEtrVmBxQvheRArXjg2vG1xIprWGuCyESx 122 MMY8pjmjepSy2kuz+nl9aFLqmr+rDNdYvEBqQaZrYMc6k29gjvoQnQ== 123 -----END PUBLIC KEY----- 124 `) 125 126 func verifiedUpdate(binary io.Reader, hexChecksum, hexSignature string) { 127 checksum, err := hex.DecodeString(hexChecksum) 128 if err != nil { 129 return err 130 } 131 signature, err := hex.DecodeString(hexSignature) 132 if err != nil { 133 return err 134 } 135 opts := update.Options{ 136 Checksum: checksum, 137 Signature: signature, 138 Hash: crypto.SHA256, // this is the default, you don't need to specify it 139 Verifier: update.NewECDSAVerifier(), // this is the default, you don't need to specify it 140 } 141 err = opts.SetPublicKeyPEM(publicKey) 142 if err != nil { 143 return err 144 } 145 err = update.Apply(binary, opts) 146 if err != nil { 147 // error handling 148 } 149 return err 150 } 151 152 153 Building Single-File Go Binaries 154 155 In order to update a Go application with go-update, you must distributed it as a single executable. 156 This is often easy, but some applications require static assets (like HTML and CSS asset files or TLS certificates). 157 In order to update applications like these, you'll want to make sure to embed those asset files into 158 the distributed binary with a tool like go-bindata (my favorite): https://github.com/jteeuwen/go-bindata 159 160 Non-Goals 161 162 Mechanisms and protocols for determining whether an update should be applied and, if so, which one are 163 out of scope for this package. Please consult go-tuf (https://github.com/flynn/go-tuf) or Equinox (https://equinox.io) 164 for more complete solutions. 165 166 go-update only works for self-updating applications that are distributed as a single binary, i.e. 167 applications that do not have additional assets or dependency files. 168 Updating application that are distributed as mutliple on-disk files is out of scope, although this 169 may change in future versions of this library. 170 171 */ 172 package update