http.Error(w, err.Error(), http.StatusBadRequest)
return
}
+ var digestExpected []byte
+ if digestExpectedHex, exists := r.MultipartForm.Value["sha256_digest"]; exists {
+ digestExpected, err = hex.DecodeString(digestExpectedHex[0])
+ if err != nil {
+ http.Error(w, "bad sha256_digest: "+err.Error(), http.StatusBadRequest)
+ return
+ }
+ }
for _, file := range r.MultipartForm.File["content"] {
filename := file.Filename
log.Println(r.RemoteAddr, "put", filename, "by", username)
return
}
dst.Close()
+ digest := hasher.Sum(nil)
+ if digestExpected != nil {
+ if bytes.Compare(digestExpected, digest) == 0 {
+ log.Println(r.RemoteAddr, filename, "good checksum received")
+ } else {
+ log.Println(r.RemoteAddr, filename, "bad checksum received")
+ http.Error(w, "bad checksum", http.StatusBadRequest)
+ os.Remove(dst.Name())
+ return
+ }
+ }
if err = os.Rename(dst.Name(), path); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- if err = ioutil.WriteFile(path+SHA256Ext, hasher.Sum(nil), os.FileMode(0666)); err != nil {
+ if err = ioutil.WriteFile(path+SHA256Ext, digest, os.FileMode(0666)); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@itemize
@item proxying and caching of missing packages
@item atomic packages store on filesystem
-@item SHA256-checksummed packages (both uploaded and proxied one)
+@item SHA256-checksummed packages: storing checksums, giving them back,
+ verifying stored files integrity, verifying checksum of uploaded
+ packaged
@item graceful HTTP-server shutdown
@item no YAML configuration, just command-line arguments
@item no package overwriting ability (as PyPI does)
--password foo dist/tarball.tar.gz
@end verbatim
+If @command{twine} sends SHA256 checksum in the request, then uploaded
+file is checked against it.
+
@node Passwords
@unnumbered Password authentication