github.com/ruishantech/selfupdate@v1.0.3/apply_test.go (about) 1 package selfupdate 2 3 import ( 4 "bytes" 5 "crypto" 6 "crypto/rand" 7 "crypto/sha256" 8 "crypto/x509" 9 "encoding/pem" 10 "fmt" 11 "io/ioutil" 12 "os" 13 "testing" 14 15 "github.com/ruishantech/selfupdate/internal/binarydist" 16 ) 17 18 var ( 19 oldFile = []byte{0xDE, 0xAD, 0xBE, 0xEF} 20 newFile = []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06} 21 newFileChecksum = sha256.Sum256(newFile) 22 ) 23 24 func cleanup(path string) { 25 os.Remove(path) 26 os.Remove(fmt.Sprintf(".%s.new", path)) 27 } 28 29 // we write with a separate name for each test so that we can run them in parallel 30 func writeOldFile(path string, t *testing.T) { 31 if err := ioutil.WriteFile(path, oldFile, 0777); err != nil { 32 t.Fatalf("Failed to write file for testing preparation: %v", err) 33 } 34 } 35 36 func validateUpdate(path string, err error, t *testing.T) { 37 if err != nil { 38 t.Fatalf("Failed to update: %v", err) 39 } 40 41 buf, err := ioutil.ReadFile(path) 42 if err != nil { 43 t.Fatalf("Failed to read file post-update: %v", err) 44 } 45 46 if !bytes.Equal(buf, newFile) { 47 t.Fatalf("File was not updated! Bytes read: %v, Bytes expected: %v", buf, newFile) 48 } 49 } 50 51 func TestApplySimple(t *testing.T) { 52 fName := "TestApplySimple" 53 defer cleanup(fName) 54 writeOldFile(fName, t) 55 56 err := Apply(bytes.NewReader(newFile), Options{ 57 TargetPath: fName, 58 }) 59 validateUpdate(fName, err, t) 60 } 61 62 func TestApplyOldSavePath(t *testing.T) { 63 fName := "TestApplyOldSavePath" 64 defer cleanup(fName) 65 writeOldFile(fName, t) 66 67 oldfName := "OldSavePath" 68 69 err := Apply(bytes.NewReader(newFile), Options{ 70 TargetPath: fName, 71 OldSavePath: oldfName, 72 }) 73 validateUpdate(fName, err, t) 74 75 if _, err := os.Stat(oldfName); os.IsNotExist(err) { 76 t.Fatalf("Failed to find the old file: %v", err) 77 } 78 79 cleanup(oldfName) 80 } 81 82 func TestVerifyChecksum(t *testing.T) { 83 fName := "TestVerifyChecksum" 84 defer cleanup(fName) 85 writeOldFile(fName, t) 86 87 err := Apply(bytes.NewReader(newFile), Options{ 88 TargetPath: fName, 89 Checksum: newFileChecksum[:], 90 }) 91 validateUpdate(fName, err, t) 92 } 93 94 func TestVerifyChecksumNegative(t *testing.T) { 95 fName := "TestVerifyChecksumNegative" 96 defer cleanup(fName) 97 writeOldFile(fName, t) 98 99 badChecksum := []byte{0x0A, 0x0B, 0x0C, 0xFF} 100 err := Apply(bytes.NewReader(newFile), Options{ 101 TargetPath: fName, 102 Checksum: badChecksum, 103 }) 104 if err == nil { 105 t.Fatalf("Failed to detect bad checksum!") 106 } 107 } 108 109 func TestApplyPatch(t *testing.T) { 110 fName := "TestApplyPatch" 111 defer cleanup(fName) 112 writeOldFile(fName, t) 113 114 patch := new(bytes.Buffer) 115 err := binarydist.Diff(bytes.NewReader(oldFile), bytes.NewReader(newFile), patch) 116 if err != nil { 117 t.Fatalf("Failed to create patch: %v", err) 118 } 119 120 err = Apply(patch, Options{ 121 TargetPath: fName, 122 Patcher: NewBSDiffPatcher(), 123 }) 124 validateUpdate(fName, err, t) 125 } 126 127 func TestCorruptPatch(t *testing.T) { 128 fName := "TestCorruptPatch" 129 defer cleanup(fName) 130 writeOldFile(fName, t) 131 132 badPatch := []byte{0x44, 0x38, 0x86, 0x3c, 0x4f, 0x8d, 0x26, 0x54, 0xb, 0x11, 0xce, 0xfe, 0xc1, 0xc0, 0xf8, 0x31, 0x38, 0xa0, 0x12, 0x1a, 0xa2, 0x57, 0x2a, 0xe1, 0x3a, 0x48, 0x62, 0x40, 0x2b, 0x81, 0x12, 0xb1, 0x21, 0xa5, 0x16, 0xed, 0x73, 0xd6, 0x54, 0x84, 0x29, 0xa6, 0xd6, 0xb2, 0x1b, 0xfb, 0xe6, 0xbe, 0x7b, 0x70} 133 err := Apply(bytes.NewReader(badPatch), Options{ 134 TargetPath: fName, 135 Patcher: NewBSDiffPatcher(), 136 }) 137 if err == nil { 138 t.Fatalf("Failed to detect corrupt patch!") 139 } 140 } 141 142 func TestVerifyChecksumPatchNegative(t *testing.T) { 143 fName := "TestVerifyChecksumPatchNegative" 144 defer cleanup(fName) 145 writeOldFile(fName, t) 146 147 patch := new(bytes.Buffer) 148 anotherFile := []byte{0x77, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66} 149 err := binarydist.Diff(bytes.NewReader(oldFile), bytes.NewReader(anotherFile), patch) 150 if err != nil { 151 t.Fatalf("Failed to create patch: %v", err) 152 } 153 154 err = Apply(patch, Options{ 155 TargetPath: fName, 156 Checksum: newFileChecksum[:], 157 Patcher: NewBSDiffPatcher(), 158 }) 159 if err == nil { 160 t.Fatalf("Failed to detect patch to wrong file!") 161 } 162 } 163 164 const ecdsaPublicKey = ` 165 -----BEGIN PUBLIC KEY----- 166 MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEL8ThbSyEucsCxnd4dCZR2hIy5nea54ko 167 O+jUUfIjkvwhCWzASm0lpCVdVpXKZXIe+NZ+44RQRv3+OqJkCCGzUgJkPNI3lxdG 168 9zu8rbrnxISV06VQ8No7Ei9wiTpqmTBB 169 -----END PUBLIC KEY----- 170 ` 171 172 const ecdsaPrivateKey = ` 173 -----BEGIN EC PRIVATE KEY----- 174 MIGkAgEBBDBttCB/1NOY4T+WrG4FSV49Ayn3gK1DNzfGaJ01JUXeiNFCWQM2pqpU 175 om8ATPP/dkegBwYFK4EEACKhZANiAAQvxOFtLIS5ywLGd3h0JlHaEjLmd5rniSg7 176 6NRR8iOS/CEJbMBKbSWkJV1Wlcplch741n7jhFBG/f46omQIIbNSAmQ80jeXF0b3 177 O7ytuufEhJXTpVDw2jsSL3CJOmqZMEE= 178 -----END EC PRIVATE KEY----- 179 ` 180 181 const rsaPublicKey = ` 182 -----BEGIN PUBLIC KEY----- 183 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxSWmu7trWKAwDFjiCN2D 184 Tk2jj2sgcr/CMlI4cSSiIOHrXCFxP1I8i9PvQkd4hasXQrLbT5WXKrRGv1HKUKab 185 b9ead+kD0kxk7i2bFYvKX43oq66IW0mOLTQBO7I9UyT4L7svcMD+HUQ2BqHoaQe4 186 y20C59dPr9Dpcz8DZkdLsBV6YKF6Ieb3iGk8oRLMWNaUqPa8f1BGgxAkvPHcqDjT 187 x4xRnjgTRRRlZvRtALHMUkIChgxDOhoEzKpGiqnX7HtMJfrhV6h0PAXNA4h9Kjv5 188 5fhJ08Rz7mmZmtH5JxTK5XTquo59sihSajR4bSjZbbkQ1uLkeFlY3eli3xdQ7Nrf 189 fQIDAQAB 190 -----END PUBLIC KEY-----` 191 192 const rsaPrivateKey = ` 193 -----BEGIN RSA PRIVATE KEY----- 194 MIIEogIBAAKCAQEAxSWmu7trWKAwDFjiCN2DTk2jj2sgcr/CMlI4cSSiIOHrXCFx 195 P1I8i9PvQkd4hasXQrLbT5WXKrRGv1HKUKabb9ead+kD0kxk7i2bFYvKX43oq66I 196 W0mOLTQBO7I9UyT4L7svcMD+HUQ2BqHoaQe4y20C59dPr9Dpcz8DZkdLsBV6YKF6 197 Ieb3iGk8oRLMWNaUqPa8f1BGgxAkvPHcqDjTx4xRnjgTRRRlZvRtALHMUkIChgxD 198 OhoEzKpGiqnX7HtMJfrhV6h0PAXNA4h9Kjv55fhJ08Rz7mmZmtH5JxTK5XTquo59 199 sihSajR4bSjZbbkQ1uLkeFlY3eli3xdQ7NrffQIDAQABAoIBAAkN+6RvrTR61voa 200 Mvd5RQiZpEN4Bht/Fyo8gH8h0Zh1B9xJZOwlmMZLS5fdtHlfLEhR8qSrGDBL61vq 201 I8KkhEsUufF78EL+YzxVN+Q7cWYGHIOWFokqza7hzpSxUQO6lPOMQ1eIZaNueJTB 202 Zu07/47ISPPg/bXzgGVcpYlTCPTjUwKjtfyMqvX9AD7fIyYRm6zfE7EHj1J2sBFt 203 Yz1OGELg6HfJwXfpnPfBvftD0hWGzJ78Bp71fPJe6n5gnqmSqRvrcXNWFnH/yqkN 204 d6vPIxD6Z3LjvyZpkA7JillLva2L/zcIFhg4HZvQnWd8/PpDnUDonu36hcj4SC5j 205 W4aVPLkCgYEA4XzNKWxqYcajzFGZeSxlRHupSAl2MT7Cc5085MmE7dd31wK2T8O4 206 n7N4bkm/rjTbX85NsfWdKtWb6mpp8W3VlLP0rp4a/12OicVOkg4pv9LZDmY0sRlE 207 YuDJk1FeCZ50UrwTZI3rZ9IhZHhkgVA6uWAs7tYndONkxNHG0pjqs4sCgYEA39MZ 208 JwMqo3qsPntpgP940cCLflEsjS9hYNO3+Sv8Dq3P0HLVhBYajJnotf8VuU0fsQZG 209 grmtVn1yThFbMq7X1oY4F0XBA+paSiU18c4YyUnwax2u4sw9U/Q9tmQUZad5+ueT 210 qriMBwGv+ewO+nQxqvAsMUmemrVzrfwA5Oct+hcCgYAfiyXoNZJsOy2O15twqBVC 211 j0oPGcO+/9iT89sg5lACNbI+EdMPNYIOVTzzsL1v0VUfAe08h++Enn1BPcG0VHkc 212 ZFBGXTfJoXzfKQrkw7ZzbzuOGB4m6DH44xlP0oIlNlVvfX/5ASF9VJf3RiBJNsAA 213 TsP6ZVr/rw/ZuL7nlxy+IQKBgDhL/HOXlE3yOQiuOec8WsNHTs7C1BXe6PtVxVxi 214 988pYK/pclL6zEq5G5NLSceF4obAMVQIJ9UtUGbabrncyGUo9UrFPLsjYvprSZo8 215 YHegpVwL50UcYgCP2kXZ/ldjPIcjYDz8lhvdDMor2cidGTEJn9P11HLNWP9V91Ob 216 4jCZAoGAPNRSC5cC8iP/9j+s2/kdkfWJiNaolPYAUrmrkL6H39PYYZM5tnhaIYJV 217 Oh9AgABamU0eb3p3vXTISClVgV7ifq1HyZ7BSUhMfaY2Jk/s3sUHCWFxPZe9sgEG 218 KinIY/373KIkIV/5g4h2v1w330IWcfptxKcY/Er3DJr38f695GE= 219 -----END RSA PRIVATE KEY-----` 220 221 func signec(privatePEM string, source []byte, t *testing.T) []byte { 222 parseFn := func(p []byte) (crypto.Signer, error) { return x509.ParseECPrivateKey(p) } 223 return sign(parseFn, privatePEM, source, t) 224 } 225 226 func signrsa(privatePEM string, source []byte, t *testing.T) []byte { 227 parseFn := func(p []byte) (crypto.Signer, error) { return x509.ParsePKCS1PrivateKey(p) } 228 return sign(parseFn, privatePEM, source, t) 229 } 230 231 func sign(parsePrivKey func([]byte) (crypto.Signer, error), privatePEM string, source []byte, t *testing.T) []byte { 232 block, _ := pem.Decode([]byte(privatePEM)) 233 if block == nil { 234 t.Fatalf("Failed to parse private key PEM") 235 } 236 237 priv, err := parsePrivKey(block.Bytes) 238 if err != nil { 239 t.Fatalf("Failed to parse private key DER: %v", err) 240 } 241 242 checksum := sha256.Sum256(source) 243 sig, err := priv.Sign(rand.Reader, checksum[:], crypto.SHA256) 244 if err != nil { 245 t.Fatalf("Failed to sign: %v", sig) 246 } 247 248 return sig 249 }