fix: surface clear error when joining encrypted room without invitation

- membership server returns 403 + human-readable message on missing sealed key (was leaking 'sql: no rows in result set')
- client doJSON unwraps the server's {"error"} field instead of pasting the raw HTTP envelope
This commit is contained in:
agent
2026-06-03 21:33:42 +02:00
parent c203ba63e6
commit b1d1f64c16
2 changed files with 16 additions and 1 deletions
+8
View File
@@ -126,6 +126,14 @@ func (c *Client) doJSON(method, path string, body, out any) error {
defer resp.Body.Close() defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body) respBody, _ := io.ReadAll(resp.Body)
if resp.StatusCode >= 300 { if resp.StatusCode >= 300 {
// Surface the server's structured {"error": "..."} message when present,
// instead of leaking the raw HTTP envelope (method, path, status, JSON body).
var er struct {
Error string `json:"error"`
}
if json.Unmarshal(respBody, &er) == nil && er.Error != "" {
return fmt.Errorf("%s (HTTP %d)", er.Error, resp.StatusCode)
}
return fmt.Errorf("client: %s %s -> %d: %s", method, path, resp.StatusCode, string(respBody)) return fmt.Errorf("client: %s %s -> %d: %s", method, path, resp.StatusCode, string(respBody))
} }
if out != nil { if out != nil {
+8 -1
View File
@@ -1,7 +1,9 @@
package membership package membership
import ( import (
"database/sql"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@@ -235,7 +237,12 @@ func (s *Server) handleGetKey(w http.ResponseWriter, r *http.Request) {
} }
ep, sealed, err := s.store.GetSealedKey(roomID, endpoint, epoch) ep, sealed, err := s.store.GetSealedKey(roomID, endpoint, epoch)
if err != nil { if err != nil {
writeErr(w, http.StatusNotFound, err.Error()) if errors.Is(err, sql.ErrNoRows) {
writeErr(w, http.StatusForbidden,
"not invited to this encrypted room: no key has been sealed for your identity. Ask the room owner to invite you before joining.")
return
}
writeErr(w, http.StatusInternalServerError, err.Error())
return return
} }
writeJSON(w, http.StatusOK, keyResp{Epoch: ep, SealedKey: sealed}) writeJSON(w, http.StatusOK, keyResp{Epoch: ep, SealedKey: sealed})