Debug proxy, duck as fs
All checks were successful
/ docker (push) Successful in 4m23s

- Add proxy endpoint for proxying a message to a target's inbox
- Change duck embed to fs based to fix mk not understanding it
This commit is contained in:
Melody Becker 2025-04-23 15:11:46 +02:00
parent d70786439e
commit 415cd89792
Signed by: mstar
SSH key fingerprint: SHA256:9VAo09aaVNTWKzPW7Hq2LW+ox9OdwmTSHRoD4mlz1yI
8 changed files with 104 additions and 17 deletions

View file

@ -39,6 +39,9 @@ var nojsFS embed.FS
//go:embed duck.webp
var defaultDuck string
//go:embed duck.webp
var duckFS embed.FS
func main() {
other.SetupFlags()
flag.Parse()
@ -167,6 +170,7 @@ func newServer() {
public := webpublic.New(
fmt.Sprintf(":%v", config.GlobalConfig.General.PrivatePort),
&defaultDuck,
duckFS,
)
if err = public.Start(); err != nil {
log.Fatal().Err(err).Msg("Failed to start public server")

View file

@ -1,8 +1,7 @@
# .
[general]
protocol = "https"
domain = "serveo.net"
subdomain = "5dc9c90be02fecb3b132ad4d4877555a"
subdomain = "e8f7573481d6b2311fb076f4190ac852"
private_port = 8080
public_port = 443

View file

@ -30,6 +30,8 @@ func New(addr string) *Server {
handler.HandleFunc("GET /import-user", issueUserImport)
handler.HandleFunc("GET /keys-for", returnKeypair)
handler.HandleFunc("GET /import-server", importServerInfo)
handler.HandleFunc("GET /request-follow", kickoffFollow)
handler.HandleFunc("POST /send-as", proxyMessageToTarget)
web := http.Server{
Addr: addr,
Handler: webutils.ChainMiddlewares(

View file

@ -6,6 +6,7 @@ import (
"encoding/json"
"encoding/pem"
"fmt"
"io"
"net/http"
"strconv"
"time"
@ -206,13 +207,78 @@ func returnKeypair(w http.ResponseWriter, r *http.Request) {
func issueUserImport(w http.ResponseWriter, r *http.Request) {
target := r.FormValue("target")
_, err := activitypub.ImportRemoteAccountByHandle(target)
hlog.FromRequest(r).Info().Err(err).Msg("Err from import request")
if err != nil {
hlog.FromRequest(r).Info().Err(err).Msg("Err from import request")
}
}
func proxyMessageToTarget(w http.ResponseWriter, r *http.Request) {
type Inbound struct {
From string `json:"from"`
Target string `json:"target"`
Message any `json:"message"`
}
log := hlog.FromRequest(r)
data := Inbound{}
dec := json.NewDecoder(r.Body)
err := dec.Decode(&data)
if err != nil {
log.Warn().Err(err).Msg("Failed to decode json body")
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
return
}
log.Debug().Any("data", data).Msg("Received message")
user, err := dbgen.User.GetByUsername(data.From)
if err != nil {
log.Error().Err(err).Msg("Failed to get user from storage")
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
return
}
targetId, err := activitypub.ImportRemoteAccountByHandle(data.Target)
if err != nil {
log.Error().Err(err).Msg("Failed to import target user")
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
return
}
target, err := dbgen.User.Where(dbgen.User.ID.Eq(targetId)).
Preload(dbgen.User.RemoteInfo).
First()
if err != nil {
log.Error().Err(err).Msg("Failed to get target user from db")
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
return
}
outBody, err := json.Marshal(data.Message)
if err != nil {
log.Error().Err(err).Msg("Failed to marshal out data")
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
return
}
log.Debug().Bytes("request-body", outBody).Msg("Body of proxied request")
response, err := webshared.RequestSignedCavage(
"POST",
target.RemoteInfo.InboxLink,
outBody,
user,
)
if err != nil {
log.Error().Err(err).Msg("Request failed")
webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
return
}
defer response.Body.Close()
respBody, _ := io.ReadAll(response.Body)
log.Debug().
Int("status-code", response.StatusCode).
Bytes("body", respBody).
Msg("Response from message")
}
func kickoffFollow(w http.ResponseWriter, r *http.Request) {
type Inbound struct {
Id string
Target string
From string `json:"from"`
To string `json:"to"`
}
var data Inbound
dec := json.NewDecoder(r.Body)

View file

@ -44,8 +44,6 @@ func BuildAuthorizedFetchCheck(forNonGet bool, forGet bool) webutils.HandlerBuil
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log := hlog.FromRequest(r)
log.Info().Msg("AuthFetch middleware")
defer log.Info().Msg("AuhFetch completed")
path := r.URL.Path
// Check always open path first
for _, re := range publicPaths {

View file

@ -29,6 +29,7 @@ package webpublic
import (
"context"
"fmt"
"io/fs"
"net/http"
webutils "git.mstar.dev/mstar/goutils/http"
@ -41,7 +42,7 @@ type Server struct {
server *http.Server
}
func New(addr string, duckImg *string) *Server {
func New(addr string, duckImg *string, duckFs fs.FS) *Server {
handler := http.NewServeMux()
handler.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
@ -53,11 +54,8 @@ func New(addr string, duckImg *string) *Server {
handler.HandleFunc("GET /nodeinfo/2.1", api.NodeInfo21)
handler.HandleFunc("GET /nodeinfo/2.0", api.NodeInfo20)
handler.HandleFunc("GET /errors/{name}", errorTypeHandler)
handler.HandleFunc("GET /default-image", func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "image/web")
w.Header().Add("Content-Disposition", "attachment; filename=\"duck.webp\"")
fmt.Fprint(w, *duckImg)
})
handler.HandleFunc("GET /default-image", buildServeDefaultImage(duckImg, duckFs))
handler.HandleFunc("GET /default-image.webp", buildServeDefaultImage(duckImg, duckFs))
server := http.Server{
Handler: webutils.ChainMiddlewares(
handler,
@ -76,3 +74,15 @@ func (s *Server) Start() error {
func (s *Server) Stop() error {
return s.server.Shutdown(context.Background())
}
func buildServeDefaultImage(
duckImg *string,
duckFs fs.FS,
) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
http.ServeFileFS(w, r, duckFs, "duck.webp")
// w.Header().Add("Content-Type", "image/webp")
// w.Header().Add("Content-Disposition", "attachment; filename=\"duck.webp\"")
// fmt.Fprint(w, *duckImg)
}
}

View file

@ -5,10 +5,12 @@ import (
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"io"
"net/http"
"slices"
"time"
"github.com/rs/zerolog/log"
"github.com/yaronf/httpsign"
"git.mstar.dev/mstar/linstrom/config"
@ -77,11 +79,16 @@ func RequestSignedCavage(
body []byte,
actor *models.User,
) (*http.Response, error) {
req, err := NewRequest(method, target, nil)
var bodyReader io.Reader
if body != nil {
bodyReader = bytes.NewReader(body)
}
req, err := NewRequest(method, target, bodyReader)
if err != nil {
return nil, err
}
req.Header.Add("Accept", "application/activity+json")
req.Header.Add("Content-Type", "application/activity+json")
var keyBytes []byte
if config.GlobalConfig.Experimental.UseEd25519Keys {
@ -101,6 +108,7 @@ func RequestSignedCavage(
if err != nil {
return nil, err
}
log.Debug().Bytes("body", body).Any("headers", req.Header).Msg("Sending signed request")
return RequestClient.Do(req)
}
@ -119,7 +127,7 @@ func applyBodyHash(headers http.Header, body []byte) error {
return nil
}
hash := sha256.Sum256(body)
based := base64.StdEncoding.EncodeToString(hash[:])
headers.Set("Digest", "SHA-256="+based)
header := "SHA-256=" + base64.StdEncoding.EncodeToString(hash[:])
headers.Set("Digest", header)
return nil
}

View file

@ -5,7 +5,7 @@ import "strings"
// TODO: Define linstrom uri type
var hardcodedUrls = map[string]string{
"default-media": "/default-image",
"default-media": "/default-image.webp",
}
func EnsurePublicUrl(rawUrl string) string {