mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
allow hmac authentication for read-file
This commit is contained in:
parent
4c68fc4ceb
commit
5f9f02d1cb
@ -37,6 +37,7 @@ import (
|
|||||||
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
|
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
|
||||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/cmdrunner"
|
"github.com/wavetermdev/waveterm/wavesrv/pkg/cmdrunner"
|
||||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/pcloud"
|
"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/releasechecker"
|
||||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/remote"
|
"github.com/wavetermdev/waveterm/wavesrv/pkg/remote"
|
||||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/rtnstate"
|
"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 {
|
func AuthKeyWrap(fn WebFnType) WebFnType {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
reqAuthKey := r.Header.Get("X-AuthKey")
|
reqAuthKey := r.Header.Get("X-AuthKey")
|
||||||
@ -921,7 +951,7 @@ func main() {
|
|||||||
gr.HandleFunc("/api/get-client-data", AuthKeyWrap(HandleGetClientData))
|
gr.HandleFunc("/api/get-client-data", AuthKeyWrap(HandleGetClientData))
|
||||||
gr.HandleFunc("/api/set-winsize", AuthKeyWrap(HandleSetWinSize))
|
gr.HandleFunc("/api/set-winsize", AuthKeyWrap(HandleSetWinSize))
|
||||||
gr.HandleFunc("/api/log-active-state", AuthKeyWrap(HandleLogActiveState))
|
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")
|
gr.HandleFunc("/api/write-file", AuthKeyWrap(HandleWriteFile)).Methods("POST")
|
||||||
configPath := path.Join(scbase.GetWaveHomeDir(), "config") + "/"
|
configPath := path.Join(scbase.GetWaveHomeDir(), "config") + "/"
|
||||||
log.Printf("[wave] config path: %q\n", configPath)
|
log.Printf("[wave] config path: %q\n", configPath)
|
||||||
|
52
wavesrv/pkg/promptenc/hmac.go
Normal file
52
wavesrv/pkg/promptenc/hmac.go
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user