diff --git a/fed/apgateway.go b/fed/apgateway.go index 7ed6f5d4..6f007994 100644 --- a/fed/apgateway.go +++ b/fed/apgateway.go @@ -28,8 +28,6 @@ import ( "github.com/dimkr/tootik/ap" "github.com/dimkr/tootik/danger" - "github.com/dimkr/tootik/data" - "github.com/dimkr/tootik/httpsig" ) var ( @@ -50,9 +48,8 @@ func (l *Listener) handleAPGatewayPost(w http.ResponseWriter, r *http.Request) { receiver := "ap://" + m[1] - var actor ap.Actor - var rsaPrivKeyPem, ed25519PrivKeyMultibase string - if err := l.DB.QueryRowContext(r.Context(), `select json(actor), rsaprivkey, ed25519privkey from persons where cid = ? and ed25519privkey is not null`, receiver).Scan(&actor, &rsaPrivKeyPem, &ed25519PrivKeyMultibase); errors.Is(err, sql.ErrNoRows) { + var exists int + if err := l.DB.QueryRowContext(r.Context(), `select exists (select 1 from persons where cid = ? and ed25519privkey is not null)`, receiver).Scan(&exists); err == nil && exists == 0 { slog.Debug("Receiving user does not exist", "receiver", receiver) w.WriteHeader(http.StatusNotFound) return @@ -62,28 +59,11 @@ func (l *Listener) handleAPGatewayPost(w http.ResponseWriter, r *http.Request) { return } - rsaPrivKey, err := data.ParseRSAPrivateKey(rsaPrivKeyPem) - if err != nil { - slog.Warn("Failed to parse RSA private key", "receiver", receiver, "error", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - ed25519PrivKey, err := data.DecodeEd25519PrivateKey(ed25519PrivKeyMultibase) - if err != nil { - slog.Warn("Failed to decode Ed25519 private key", "receiver", receiver, "error", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - l.doHandleInbox(w, r, [2]httpsig.Key{ - {ID: actor.PublicKey.ID, PrivateKey: rsaPrivKey}, - {ID: actor.AssertionMethod[0].ID, PrivateKey: ed25519PrivKey}, - }) + l.doHandleInbox(w, r) } func (l *Listener) handleApGatewayFollowers(w http.ResponseWriter, r *http.Request, did string) { - _, sender, err := l.verifyRequest(r, nil, ap.InstanceActor, l.ActorKeys) + _, sender, err := l.verifyRequest(r, nil, ap.InstanceActor) if err != nil { slog.Warn("Failed to verify followers request", "error", err) w.WriteHeader(http.StatusUnauthorized) diff --git a/fed/followers.go b/fed/followers.go index bcfd9c4c..d72d425f 100644 --- a/fed/followers.go +++ b/fed/followers.go @@ -129,7 +129,7 @@ func (f partialFollowers) Digest(ctx context.Context, db *sql.DB, domain string, func (l *Listener) handleFollowers(w http.ResponseWriter, r *http.Request) { name := r.PathValue("username") - _, sender, err := l.verifyRequest(r, nil, ap.InstanceActor, l.ActorKeys) + _, sender, err := l.verifyRequest(r, nil, ap.InstanceActor) if err != nil { slog.Warn("Failed to verify followers request", "error", err) w.WriteHeader(http.StatusUnauthorized) diff --git a/fed/inbox.go b/fed/inbox.go index 228ddbc2..c2e31995 100644 --- a/fed/inbox.go +++ b/fed/inbox.go @@ -19,7 +19,6 @@ package fed import ( "bytes" "context" - "database/sql" "encoding/json" "errors" "fmt" @@ -219,8 +218,8 @@ func (l *Listener) validateActivity(activity *ap.Activity, origin string, depth return nil } -func (l *Listener) fetchObject(ctx context.Context, id string, keys [2]httpsig.Key) (bool, []byte, error) { - resp, err := l.Resolver.Get(ctx, keys, id) +func (l *Listener) fetchObject(ctx context.Context, id string) (bool, []byte, error) { + resp, err := l.Resolver.Get(ctx, l.ActorKeys, id) if err != nil { if resp != nil && (resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusGone) { return false, nil, err @@ -282,15 +281,14 @@ func (l *Listener) fetchObject(ctx context.Context, id string, keys [2]httpsig.K } func (l *Listener) handleSharedInbox(w http.ResponseWriter, r *http.Request) { - l.doHandleInbox(w, r, l.ActorKeys) + l.doHandleInbox(w, r) } func (l *Listener) handleInbox(w http.ResponseWriter, r *http.Request) { receiver := r.PathValue("username") - var actor ap.Actor - var rsaPrivKeyPem, ed25519PrivKeyMultibase string - if err := l.DB.QueryRowContext(r.Context(), `select json(actor), rsaprivkey, ed25519privkey from persons where actor->>'$.preferredUsername' = ? and ed25519privkey is not null`, receiver).Scan(&actor, &rsaPrivKeyPem, &ed25519PrivKeyMultibase); errors.Is(err, sql.ErrNoRows) { + var exists int + if err := l.DB.QueryRowContext(r.Context(), `select exists (select 1 from persons where actor->>'$.preferredUsername' = ? and ed25519privkey is not null)`, receiver).Scan(&exists); err == nil && exists == 0 { slog.Debug("Receiving user does not exist", "receiver", receiver) w.WriteHeader(http.StatusNotFound) return @@ -300,27 +298,10 @@ func (l *Listener) handleInbox(w http.ResponseWriter, r *http.Request) { return } - rsaPrivKey, err := data.ParseRSAPrivateKey(rsaPrivKeyPem) - if err != nil { - slog.Warn("Failed to parse RSA private key", "receiver", receiver, "error", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - ed25519PrivKey, err := data.DecodeEd25519PrivateKey(ed25519PrivKeyMultibase) - if err != nil { - slog.Warn("Failed to decode Ed25519 private key", "receiver", receiver, "error", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - l.doHandleInbox(w, r, [2]httpsig.Key{ - {ID: actor.PublicKey.ID, PrivateKey: rsaPrivKey}, - {ID: actor.AssertionMethod[0].ID, PrivateKey: ed25519PrivKey}, - }) + l.doHandleInbox(w, r) } -func (l *Listener) doHandleInbox(w http.ResponseWriter, r *http.Request, keys [2]httpsig.Key) { +func (l *Listener) doHandleInbox(w http.ResponseWriter, r *http.Request) { if r.ContentLength > l.Config.MaxRequestBodySize { slog.Warn("Ignoring big request", "size", r.ContentLength) w.WriteHeader(http.StatusRequestEntityTooLarge) @@ -359,7 +340,7 @@ func (l *Listener) doHandleInbox(w http.ResponseWriter, r *http.Request, keys [2 var sig *httpsig.Signature if activity.Proof != (ap.Proof{}) { // if activity has an integrity proof, pretend it was sent by its actor even if forwarded by another - sender, err = l.verifyProof(r.Context(), activity.Proof, &activity, rawActivity, flags, keys) + sender, err = l.verifyProof(r.Context(), activity.Proof, &activity, rawActivity, flags) if err != nil { slog.Warn("Failed to verify integrity proof", "activity", &activity, "proof", &activity.Proof, "error", err) w.WriteHeader(http.StatusUnauthorized) @@ -374,7 +355,7 @@ func (l *Listener) doHandleInbox(w http.ResponseWriter, r *http.Request, keys [2 json.NewEncoder(w).Encode(map[string]any{"error": "integrity proof is required"}) return } else { - sig, sender, err = l.verifyRequest(r, rawActivity, flags, keys) + sig, sender, err = l.verifyRequest(r, rawActivity, flags) if err != nil { if errors.Is(err, ErrActorGone) { w.WriteHeader(http.StatusAccepted) @@ -491,7 +472,7 @@ func (l *Listener) doHandleInbox(w http.ResponseWriter, r *http.Request, keys [2 slog.Info("Fetching forwarded object", "activity", &activity, "id", id, "sender", sender.ID) - if exists, fetched, err := l.fetchObject(r.Context(), id, keys); !exists && queued.Type == ap.Delete { + if exists, fetched, err := l.fetchObject(r.Context(), id); !exists && queued.Type == ap.Delete { queued = &ap.Activity{ ID: queued.ID, Type: ap.Delete, diff --git a/fed/verify.go b/fed/verify.go index 6b7c4605..0626b9d8 100644 --- a/fed/verify.go +++ b/fed/verify.go @@ -59,7 +59,7 @@ func getKeyByID(actor *ap.Actor, keyID string) (ed25519.PublicKey, error) { return nil, fmt.Errorf("key %s does not exist", keyID) } -func (l *Listener) verifyRequest(r *http.Request, body []byte, flags ap.ResolverFlag, keys [2]httpsig.Key) (*httpsig.Signature, *ap.Actor, error) { +func (l *Listener) verifyRequest(r *http.Request, body []byte, flags ap.ResolverFlag) (*httpsig.Signature, *ap.Actor, error) { sig, err := httpsig.Extract(r, body, l.Domain, time.Now(), l.Config.MaxRequestAge) if err != nil { return nil, nil, fmt.Errorf("failed to verify message: %w", err) @@ -79,7 +79,7 @@ func (l *Listener) verifyRequest(r *http.Request, body []byte, flags ap.Resolver return nil, nil, fmt.Errorf("failed to verify message using %s: %w", sig.KeyID, err) } - actor, err := l.Resolver.ResolveID(r.Context(), keys, sig.KeyID, flags) + actor, err := l.Resolver.ResolveID(r.Context(), l.ActorKeys, sig.KeyID, flags) if err != nil { return nil, nil, fmt.Errorf("failed to fetch %s: %w", sig.KeyID, err) } @@ -89,7 +89,7 @@ func (l *Listener) verifyRequest(r *http.Request, body []byte, flags ap.Resolver } } - actor, err := l.Resolver.ResolveID(r.Context(), keys, sig.KeyID, flags) + actor, err := l.Resolver.ResolveID(r.Context(), l.ActorKeys, sig.KeyID, flags) if err != nil { return nil, nil, fmt.Errorf("failed to get key %s to verify message: %w", sig.KeyID, err) } @@ -124,7 +124,7 @@ func (l *Listener) verifyRequest(r *http.Request, body []byte, flags ap.Resolver return sig, actor, nil } -func (l *Listener) verifyProof(ctx context.Context, p ap.Proof, activity *ap.Activity, raw []byte, flags ap.ResolverFlag, keys [2]httpsig.Key) (*ap.Actor, error) { +func (l *Listener) verifyProof(ctx context.Context, p ap.Proof, activity *ap.Activity, raw []byte, flags ap.ResolverFlag) (*ap.Actor, error) { if m := ap.KeyRegex.FindStringSubmatch(p.VerificationMethod); m != nil { if m2 := ap.GatewayURLRegex.FindStringSubmatch(activity.Actor); m2 != nil { if m2[1] != m[1] { @@ -140,11 +140,11 @@ func (l *Listener) verifyProof(ctx context.Context, p ap.Proof, activity *ap.Act return nil, fmt.Errorf("failed to verify proof using %s: %w", p.VerificationMethod, err) } - return l.Resolver.ResolveID(ctx, keys, activity.Actor, flags) + return l.Resolver.ResolveID(ctx, l.ActorKeys, activity.Actor, flags) } } - actor, err := l.Resolver.ResolveID(ctx, keys, p.VerificationMethod, flags) + actor, err := l.Resolver.ResolveID(ctx, l.ActorKeys, p.VerificationMethod, flags) if err != nil { return nil, fmt.Errorf("failed to get key %s to verify proof: %w", p.VerificationMethod, err) }