X-Git-Url: https://ruderich.org/simon/gitweb/?p=nsscash%2Fnsscash.git;a=blobdiff_plain;f=file.go;h=e06a9bce335ccc4e4444e5f8ea9502d27df09eba;hp=b77cbb692de37f02df499c7af5254e34b2bf8de4;hb=0cc987b1bcb7b16da4f46d84d216df3f6ef457e1;hpb=d72650db8abe817b328754fb2e33137346058f15 diff --git a/file.go b/file.go index b77cbb6..e06a9bc 100644 --- a/file.go +++ b/file.go @@ -19,6 +19,8 @@ package main import ( "bytes" + "crypto/sha512" + "encoding/hex" "fmt" "io/ioutil" "log" @@ -26,6 +28,7 @@ import ( "os" "path/filepath" "syscall" + "time" "github.com/pkg/errors" ) @@ -58,9 +61,36 @@ func handleFiles(cfg *Config, state *State) error { return nil } +func checksumFile(file *File) (string, error) { + x, err := ioutil.ReadFile(file.Path) + if err != nil { + return "", err + } + return checksumBytes(x), nil +} + +func checksumBytes(x []byte) string { + h := sha512.New() + h.Write(x) + return hex.EncodeToString(h.Sum(nil)) +} + func fetchFile(file *File, state *State) error { t := state.LastModified[file.Url] - status, body, err := fetchIfModified(file.Url, &t) + + hash, err := checksumFile(file) + if err != nil { + // See below in deployFile() for the reason + return errors.Wrapf(err, "file.path %q must exist", file.Path) + } + if hash != state.Checksum[file.Url] { + log.Printf("%q -> %q: hash has changed", file.Url, file.Path) + var zero time.Time + t = zero // force download + } + + status, body, err := fetchIfModified(file.Url, + file.Username, file.Password, file.CA, &t) if err != nil { return err } @@ -116,6 +146,8 @@ func fetchFile(file *File, state *State) error { } else { return fmt.Errorf("unsupported file type %v", file.Type) } + + state.Checksum[file.Url] = checksumBytes(file.body) return nil } @@ -140,15 +172,16 @@ func deployFile(file *File) error { defer os.Remove(f.Name()) defer f.Close() - // Apply permissions/user/group from the target file, use Stat instead - // of Lstat as only the target's permissions are relevant + // Apply permissions/user/group from the target file but remove the + // write permissions to discourage manual modifications, use Stat + // instead of Lstat as only the target's permissions are relevant stat, err := os.Stat(file.Path) if err != nil { // We do not create the path if it doesn't exist, because we // do not know the proper permissions return errors.Wrapf(err, "file.path %q must exist", file.Path) } - err = f.Chmod(stat.Mode()) + err = f.Chmod(stat.Mode() & ^os.FileMode(0222)) // remove write perms if err != nil { return err }