improve (build): make build reproducible and easy to inspect/verify

This commit is contained in:
Mickael Kerjean 2019-08-20 00:34:24 +10:00
parent aff3dc704a
commit 4a0b952ba8
7 changed files with 52 additions and 31 deletions

View file

@ -8,4 +8,4 @@ build_frontend:
NODE_ENV=production npm run build NODE_ENV=production npm run build
build_backend: build_backend:
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/ CGO_CFLAGS_ALLOW='-fopenmp' go build --tags "fts5" -ldflags "-X github.com/mickael-kerjean/filestash/server/common.BUILD_NUMBER=`date -u +%Y%m%d`" -o dist/filestash server/main.go PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/ CGO_CFLAGS_ALLOW='-fopenmp' go build --tags "fts5" -ldflags "-X github.com/mickael-kerjean/filestash/server/common.BUILD_DATE=`date -u +%Y%m%d` -X github.com/mickael-kerjean/filestash/server/common.BUILD_REF=`git rev-parse HEAD`" -o dist/filestash server/main.go

View file

@ -34,7 +34,8 @@ func init(){
var ( var (
BUILD_NUMBER string BUILD_REF string
BUILD_DATE string
SECRET_KEY string SECRET_KEY string
SECRET_KEY_DERIVATE_FOR_PROOF string SECRET_KEY_DERIVATE_FOR_PROOF string
SECRET_KEY_DERIVATE_FOR_ADMIN string SECRET_KEY_DERIVATE_FOR_ADMIN string

View file

@ -8,6 +8,7 @@ import (
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"encoding/base64" "encoding/base64"
"encoding/hex"
"hash/fnv" "hash/fnv"
"io" "io"
"io/ioutil" "io/ioutil"
@ -50,31 +51,34 @@ func DecryptString(secret string, data string) (string, error){
func Hash(str string, n int) string { func Hash(str string, n int) string {
hasher := sha256.New() hasher := sha256.New()
hasher.Write([]byte(str)) hasher.Write([]byte(str))
d := hasher.Sum(nil) return hashSize(hasher.Sum(nil), n)
h := ""
for i:=0; i<len(d); i++ {
if n > 0 && len(h) >= n {
break
}
h += ReversedBaseChange(Letters, int(d[i]))
}
if len(h) > n {
return h[0:len(h) - 1]
}
return h
} }
func QuickHash(str string, n int) string { func QuickHash(str string, n int) string {
hash := fnv.New64() hasher := fnv.New64()
hash.Write([]byte(str)) hasher.Write([]byte(str))
d := string(hash.Sum(nil)) return hashSize(hasher.Sum(nil), n)
}
func HashStream(r io.Reader, n int) string {
hasher := sha256.New()
io.Copy(hasher, r)
h := hex.EncodeToString(hasher.Sum(nil))
if n == 0 {
return h
} else if n >= len(h) {
return h
}
return h[0:n]
}
func hashSize(b []byte, n int) string {
h := "" h := ""
for i:=0; i<len(d); i++ { for i:=0; i<len(b); i++ {
if n > 0 && len(h) >= n { if n > 0 && len(h) >= n {
break break
} }
h += ReversedBaseChange(Letters, int(d[i])) h += ReversedBaseChange(Letters, int(b[i]))
} }
if len(h) > n { if len(h) > n {

View file

@ -8,7 +8,7 @@ import (
"time" "time"
) )
var USER_AGENT = fmt.Sprintf("Filestash/%s.%s (http://filestash.app)", APP_VERSION, BUILD_NUMBER) var USER_AGENT = fmt.Sprintf("Filestash/%s.%s (http://filestash.app)", APP_VERSION, BUILD_DATE)
var HTTPClient = http.Client{ var HTTPClient = http.Client{
Timeout: 5 * time.Hour, Timeout: 5 * time.Hour,

View file

@ -102,8 +102,7 @@ func Page(stuff string) string {
html { background: #f4f4f4; color: #455164; font-size: 16px; font-family: -apple-system,system-ui,BlinkMacSystemFont,Roboto,"Helvetica Neue",Arial,sans-serif; } html { background: #f4f4f4; color: #455164; font-size: 16px; font-family: -apple-system,system-ui,BlinkMacSystemFont,Roboto,"Helvetica Neue",Arial,sans-serif; }
body { text-align: center; padding-top: 50px; text-align: center; } body { text-align: center; padding-top: 50px; text-align: center; }
h1 { font-weight: 200; line-height: 1em; font-size: 40px; } h1 { font-weight: 200; line-height: 1em; font-size: 40px; }
p { opacity: 0.7; } p { opacity: 0.8; font-size: 1.05em; }
span { font-size: 0.7em; opacity: 0.7; }
</style> </style>
</head> </head>
<body> <body>

View file

@ -67,16 +67,24 @@ func IndexHandler(_path string) func(App, http.ResponseWriter, *http.Request) {
func AboutHandler(ctx App, res http.ResponseWriter, req *http.Request) { func AboutHandler(ctx App, res http.ResponseWriter, req *http.Request) {
t, _ := template.New("about").Parse(Page(` t, _ := template.New("about").Parse(Page(`
<h1> {{index .App 0}} <br> <h1> {{index .App 0}} </h1>
<span>({{index .App 1}} - {{index .App 2}})</span> <table>
</h1> <tr> <td> Commit hash </td> <td> {{ index .App 1}} </td> </tr>
<tr> <td> Binary hash </td> <td> {{ index .App 2}} </td> </tr>
<tr> <td> Config hash </td> <td> {{ index .App 3}} </td> </tr>
</table>
<style>
table { margin: 0 auto; font-family: monospace; opacity: 0.8; }
td { text-align: right; padding-left: 10px; }
</style>
`)) `))
t.Execute(res, struct { t.Execute(res, struct {
App []string App []string
}{ []string{ }{ []string{
"Filestash " + APP_VERSION + "." + BUILD_NUMBER, "Filestash " + APP_VERSION + "." + BUILD_DATE,
hashFile(filepath.Join(GetCurrentDir(), "/filestash"), 6), BUILD_REF,
hashFile(filepath.Join(GetCurrentDir(), CONFIG_PATH, "config.json"), 6), hashFileContent(filepath.Join(GetCurrentDir(), "/filestash"), 0),
hashFileContent(filepath.Join(GetCurrentDir(), CONFIG_PATH, "config.json"), 0),
}}) }})
} }
@ -131,7 +139,7 @@ func ServeFile(res http.ResponseWriter, req *http.Request, filePath string) {
file.Close() file.Close()
} }
func hashFile (path string, n int) string { func hashFile(path string, n int) string {
f, err := os.OpenFile(path, os.O_RDONLY, os.ModePerm) f, err := os.OpenFile(path, os.O_RDONLY, os.ModePerm)
if err != nil { if err != nil {
return "" return ""
@ -144,3 +152,12 @@ func hashFile (path string, n int) string {
} }
return QuickHash(fmt.Sprintf("%s %d %d %s", path, stat.Size(), stat.Mode(), stat.ModTime()), n) return QuickHash(fmt.Sprintf("%s %d %d %s", path, stat.Size(), stat.Mode(), stat.ModTime()), n)
} }
func hashFileContent(path string, n int) string {
f, err := os.OpenFile(path, os.O_RDONLY, os.ModePerm)
if err != nil {
return ""
}
defer f.Close()
return HashStream(f, n)
}

View file

@ -45,7 +45,7 @@ func IndexHeaders(fn func(App, http.ResponseWriter, *http.Request)) func(ctx App
header.Set("X-Content-Type-Options", "nosniff") header.Set("X-Content-Type-Options", "nosniff")
header.Set("X-XSS-Protection", "1; mode=block") header.Set("X-XSS-Protection", "1; mode=block")
header.Set("X-Frame-Options", "DENY") header.Set("X-Frame-Options", "DENY")
header.Set("X-Powered-By", fmt.Sprintf("Filestash/%s <https://filestash.app>", APP_VERSION + "." + BUILD_NUMBER)) header.Set("X-Powered-By", fmt.Sprintf("Filestash/%s.%s <https://filestash.app>", APP_VERSION, BUILD_DATE))
header.Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; font-src 'self' data:; manifest-src 'self'; script-src 'self' 'sha256-JNAde5CZQqXtYRLUk8CGgyJXo6C7Zs1lXPPClLM1YM4=' 'sha256-9/gQeQaAmVkFStl6tfCbHXn8mr6PgtxlH+hEp685lzY='; img-src 'self' data:; connect-src 'self'; object-src 'self'; media-src 'self'; worker-src 'self'; form-action 'self'; frame-ancestors 'none'; base-uri 'self'") header.Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; font-src 'self' data:; manifest-src 'self'; script-src 'self' 'sha256-JNAde5CZQqXtYRLUk8CGgyJXo6C7Zs1lXPPClLM1YM4=' 'sha256-9/gQeQaAmVkFStl6tfCbHXn8mr6PgtxlH+hEp685lzY='; img-src 'self' data:; connect-src 'self'; object-src 'self'; media-src 'self'; worker-src 'self'; form-action 'self'; frame-ancestors 'none'; base-uri 'self'")
fn(ctx, res, req) fn(ctx, res, req)
} }