allow hmac authentication for read-file

This commit is contained in:
sawka 2024-03-13 23:58:28 -07:00
parent 4c68fc4ceb
commit 5f9f02d1cb
2 changed files with 83 additions and 1 deletions

View File

@ -37,6 +37,7 @@ import (
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
"github.com/wavetermdev/waveterm/wavesrv/pkg/cmdrunner"
"github.com/wavetermdev/waveterm/wavesrv/pkg/pcloud"
"github.com/wavetermdev/waveterm/wavesrv/pkg/promptenc"
"github.com/wavetermdev/waveterm/wavesrv/pkg/releasechecker"
"github.com/wavetermdev/waveterm/wavesrv/pkg/remote"
"github.com/wavetermdev/waveterm/wavesrv/pkg/rtnstate"
@ -695,6 +696,35 @@ func AuthKeyMiddleWare(next http.Handler) http.Handler {
})
}
func AuthKeyWrapAllowHmac(fn WebFnType) WebFnType {
return func(w http.ResponseWriter, r *http.Request) {
reqAuthKey := r.Header.Get("X-AuthKey")
if reqAuthKey == "" {
// try hmac
qvals := r.URL.Query()
if !qvals.Has("hmac") {
w.WriteHeader(500)
w.Write([]byte("no x-authkey header"))
return
}
hmacOk, err := promptenc.ValidateUrlHmac([]byte(GlobalAuthKey), r.URL.Path, qvals)
if err != nil || !hmacOk {
w.WriteHeader(500)
w.Write([]byte(fmt.Sprintf("error validating hmac")))
return
}
// fallthrough (hmac is valid)
} else if reqAuthKey != GlobalAuthKey {
w.WriteHeader(500)
w.Write([]byte("x-authkey header is invalid"))
return
}
w.Header().Set(CacheControlHeaderKey, CacheControlHeaderNoCache)
fn(w, r)
}
}
func AuthKeyWrap(fn WebFnType) WebFnType {
return func(w http.ResponseWriter, r *http.Request) {
reqAuthKey := r.Header.Get("X-AuthKey")
@ -921,7 +951,7 @@ func main() {
gr.HandleFunc("/api/get-client-data", AuthKeyWrap(HandleGetClientData))
gr.HandleFunc("/api/set-winsize", AuthKeyWrap(HandleSetWinSize))
gr.HandleFunc("/api/log-active-state", AuthKeyWrap(HandleLogActiveState))
gr.HandleFunc("/api/read-file", AuthKeyWrap(HandleReadFile))
gr.HandleFunc("/api/read-file", AuthKeyWrapAllowHmac(HandleReadFile))
gr.HandleFunc("/api/write-file", AuthKeyWrap(HandleWriteFile)).Methods("POST")
configPath := path.Join(scbase.GetWaveHomeDir(), "config") + "/"
log.Printf("[wave] config path: %q\n", configPath)

View File

@ -0,0 +1,52 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
package promptenc
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"net/url"
)
func ComputeUrlHmac(key []byte, baseUrl string, qvals url.Values) (string, error) {
if qvals.Has("nonce") {
return "", fmt.Errorf("nonce is required for hmac")
}
if qvals.Has("hmac") {
return "", fmt.Errorf("hmac is already present")
}
encStr := baseUrl + "?" + qvals.Encode()
mac := hmac.New(sha256.New, key)
mac.Write([]byte(encStr))
rtn := mac.Sum(nil)
return base64.URLEncoding.EncodeToString(rtn), nil
}
func copyUrlValues(src url.Values) url.Values {
rtn := make(url.Values)
for k, v := range src {
rtn[k] = v
}
return rtn
}
func ValidateUrlHmac(key []byte, baseUrl string, qvalsOrig url.Values) (bool, error) {
qvals := copyUrlValues(qvalsOrig)
hmacStr := qvals.Get("hmac")
if hmacStr == "" {
return false, fmt.Errorf("no hmac key found"))
}
qvals.Del("hmac")
encStr := baseUrl + "?" + qvals.Encode()
mac := hmac.New(sha256.New, key)
mac.Write([]byte(encStr))
expected := mac.Sum(nil)
actual, err := base64.URLEncoding.DecodeString(hmacStr)
if err != nil {
return false, fmt.Errorf("error decoding hmac: %w", err)
}
return hmac.Equal(expected, actual), nil
}