Add debug handler for fetching a remote actor
All checks were successful
/ docker (push) Successful in 3m59s

Will be used later to add to internal db
This commit is contained in:
Melody Becker 2025-04-12 11:47:01 +02:00
parent d4f2f66807
commit f8b3a6ff06
Signed by: mstar
SSH key fingerprint: SHA256:vkXfS9FG2pVNVfvDrzd1VW9n8VJzqqdKQGljxxX8uK8
12 changed files with 313 additions and 156 deletions

79
web/shared/client.go Normal file
View file

@ -0,0 +1,79 @@
package webshared
import (
"crypto/sha256"
"net/http"
"time"
"git.mstar.dev/mstar/goutils/maputils"
"git.mstar.dev/mstar/linstrom/config"
)
// No init needed, zero value is good
var RequestClient http.Client
const xRandomHeader = "X-Auth-Random"
// Sign a given outbound request for authorized fetch.
// At the end, the Signature header will have the signature needed,
// nothing else is modified.
// If the request is POST, the postBody must contain the raw body of
// the request and the Digest header will also be added
func SignRequest(r *http.Request, keyId string, privateKeyBytes, postBody []byte) error {
method := r.Method
headers := r.Header
var nowString string
if dateString := headers.Get("Date"); dateString != "" {
nowString = dateString
} else {
nowString = time.Now().Format("Mon, 02 Jan 2006 15:04:05 MST")
headers.Set("Date", nowString)
}
var host string
if hostString := headers.Get("Host"); hostString != "" {
host = hostString
} else {
host = config.GlobalConfig.General.GetFullDomain()
headers.Set("Date", host)
}
applyBodyHash(headers, postBody)
mappedHeaders := maputils.MapSameKeys(headers, func(k string, v []string) string {
if len(v) > 0 {
return v[0]
} else {
return ""
}
})
var signedString string
if config.GlobalConfig.Experimental.UseEd25519Keys {
tmp, err := CreateSignatureED(method, r.URL.RawPath, mappedHeaders, privateKeyBytes)
if err != nil {
return err
}
signedString = tmp
} else {
tmp, err := CreateSignatureRSA(method, r.URL.RawPath, mappedHeaders, privateKeyBytes)
if err != nil {
return err
}
signedString = tmp
}
signature := CreateSignatureHeaderContent(
keyId,
signedString,
maputils.KeysFromMap(mappedHeaders)...,
)
headers.Set("Signature", signature)
return nil
}
func applyBodyHash(headers http.Header, body []byte) error {
if body == nil {
return nil
}
hash := sha256.Sum256(body)
headers.Set("Digest", string(hash[:]))
return nil
}

View file

@ -1,11 +1,15 @@
package webshared
import (
"encoding/base64"
"strings"
"git.mstar.dev/mstar/linstrom/shared"
)
// Generate the signed string of the headers, method and target
// and sign it using the given RSA key. Returns the base64 encoded
// result
func CreateSignatureRSA(
method string,
target string,
@ -14,9 +18,12 @@ func CreateSignatureRSA(
) (string, error) {
message := genPreSignatureString(method, target, headers)
signed, err := shared.Sign(message, privateKeyBytes, true)
return string(signed), err
return base64.StdEncoding.EncodeToString(signed), err
}
// Generate the signed string of the headers, method and target
// and sign it using the given ED25519 key. Returns the base64
// encoded result
func CreateSignatureED(
method string,
target string,
@ -25,7 +32,10 @@ func CreateSignatureED(
) (string, error) {
message := genPreSignatureString(method, target, headers)
signed, err := shared.Sign(message, privateKeyBytes, false)
return string(signed), err
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(signed), nil
}
func genPreSignatureString(method, target string, headers map[string]string) string {
@ -38,3 +48,24 @@ func genPreSignatureString(method, target string, headers map[string]string) str
}
return dataBuilder.String()
}
// Generate the content of the "Signature" header based on
// The user who's key was used, the hashed and base64 encoded
// signed string, as returned by CreateSignatureED/RSA
func CreateSignatureHeaderContent(userId string, hash string, headerNames ...string) string {
builder := strings.Builder{}
builder.WriteString("keyId=\"")
builder.WriteString(userId)
builder.WriteString("\",headers=\"")
for i, header := range headerNames {
builder.WriteString(header)
if i+1 < len(headerNames) {
builder.WriteRune(' ')
}
}
builder.WriteString("\",signature=\"")
builder.WriteString(hash)
builder.WriteRune('"')
return builder.String()
}