fix(build): make build-web works; gofmt all Go files

This commit is contained in:
2026-06-30 10:01:11 -04:00
parent 30e159cbdb
commit d3b7f39b9e
13 changed files with 479 additions and 480 deletions
+10 -10
View File
@@ -17,8 +17,8 @@ import (
// Handler handles direct-message conversations.
type Handler struct {
db *sql.DB
hub *gateway.Hub
db *sql.DB
hub *gateway.Hub
logger *slog.Logger
}
@@ -256,14 +256,14 @@ func (h *Handler) buildResponse(ctx context.Context, convID string) (conversatio
}
type messageResponse struct {
ID string `json:"id"`
ConversationID string `json:"conversation_id"`
AuthorID string `json:"author_id"`
AuthorName string `json:"author_username"`
DisplayName *string `json:"author_display_name"`
Content string `json:"content"`
EditedAt *string `json:"edited_at"`
CreatedAt string `json:"created_at"`
ID string `json:"id"`
ConversationID string `json:"conversation_id"`
AuthorID string `json:"author_id"`
AuthorName string `json:"author_username"`
DisplayName *string `json:"author_display_name"`
Content string `json:"content"`
EditedAt *string `json:"edited_at"`
CreatedAt string `json:"created_at"`
}
// ListMessages lists messages in a conversation.
+3 -3
View File
@@ -12,8 +12,8 @@ import (
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/embed"
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/gateway"
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/moderation"
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/middleware"
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/moderation"
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/push"
"github.com/go-chi/chi/v5"
)
@@ -136,8 +136,8 @@ func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusTooManyRequests)
json.NewEncoder(w).Encode(map[string]interface{}{
"error": "slowmode",
"retry_after": retryAfter,
"error": "slowmode",
"retry_after": retryAfter,
"retry_after_ms": retryAfter * 1000,
})
return
+105 -105
View File
@@ -1,105 +1,105 @@
package middleware
import (
"net/http"
"strings"
)
// CSRFProtect returns middleware that validates the Origin header on
// state-changing methods (POST, PUT, PATCH, DELETE).
//
// An origin is trusted if:
// 1. It's in the explicit additionalOrigins list, OR
// 2. Its hostname matches the configured host, OR
// 3. Its hostname matches the request's own Host header (same-origin check)
func CSRFProtect(host, port string, additionalOrigins []string) func(http.Handler) http.Handler {
originSet := make(map[string]struct{})
for _, o := range additionalOrigins {
o = strings.TrimSpace(o)
if o != "" {
originSet[o] = struct{}{}
}
}
hostname := host
if idx := strings.LastIndex(hostname, ":"); idx > 0 {
hostname = hostname[:idx]
}
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "POST", "PUT", "PATCH", "DELETE":
origin := r.Header.Get("Origin")
if origin == "" {
referer := r.Header.Get("Referer")
if referer != "" {
for o := range originSet {
if strings.HasPrefix(referer, o) {
origin = o
break
}
}
}
}
if origin != "" {
// Extract request host for same-origin check
reqHost := r.Host
if idx := strings.LastIndex(reqHost, ":"); idx > 0 {
reqHost = reqHost[:idx]
}
if !isOriginTrusted(origin, hostname, port, reqHost, originSet) {
http.Error(w, `{"error":"forbidden origin"}`, http.StatusForbidden)
return
}
}
}
next.ServeHTTP(w, r)
})
}
}
func isOriginTrusted(origin, host, port, reqHost string, originSet map[string]struct{}) bool {
if _, ok := originSet[origin]; ok {
return true
}
withoutScheme := origin
if idx := strings.Index(withoutScheme, "://"); idx >= 0 {
withoutScheme = withoutScheme[idx+3:]
}
if idx := strings.Index(withoutScheme, "/"); idx >= 0 {
withoutScheme = withoutScheme[:idx]
}
originHost := withoutScheme
originPort := ""
if idx := strings.LastIndex(originHost, ":"); idx >= 0 {
originPort = originHost[idx+1:]
originHost = originHost[:idx]
}
originHost = strings.TrimPrefix(originHost, "[")
originHost = strings.TrimSuffix(originHost, "]")
// Match configured host
if host != "" && originHost == host {
return true
}
// Match request's own Host header (same-origin)
if reqHost != "" && originHost == reqHost {
return true
}
// Localhost variants
if originHost == "localhost" || originHost == "127.0.0.1" || originHost == "::1" {
if port == "" || originPort == "" || originPort == port {
return true
}
}
return false
}
package middleware
import (
"net/http"
"strings"
)
// CSRFProtect returns middleware that validates the Origin header on
// state-changing methods (POST, PUT, PATCH, DELETE).
//
// An origin is trusted if:
// 1. It's in the explicit additionalOrigins list, OR
// 2. Its hostname matches the configured host, OR
// 3. Its hostname matches the request's own Host header (same-origin check)
func CSRFProtect(host, port string, additionalOrigins []string) func(http.Handler) http.Handler {
originSet := make(map[string]struct{})
for _, o := range additionalOrigins {
o = strings.TrimSpace(o)
if o != "" {
originSet[o] = struct{}{}
}
}
hostname := host
if idx := strings.LastIndex(hostname, ":"); idx > 0 {
hostname = hostname[:idx]
}
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "POST", "PUT", "PATCH", "DELETE":
origin := r.Header.Get("Origin")
if origin == "" {
referer := r.Header.Get("Referer")
if referer != "" {
for o := range originSet {
if strings.HasPrefix(referer, o) {
origin = o
break
}
}
}
}
if origin != "" {
// Extract request host for same-origin check
reqHost := r.Host
if idx := strings.LastIndex(reqHost, ":"); idx > 0 {
reqHost = reqHost[:idx]
}
if !isOriginTrusted(origin, hostname, port, reqHost, originSet) {
http.Error(w, `{"error":"forbidden origin"}`, http.StatusForbidden)
return
}
}
}
next.ServeHTTP(w, r)
})
}
}
func isOriginTrusted(origin, host, port, reqHost string, originSet map[string]struct{}) bool {
if _, ok := originSet[origin]; ok {
return true
}
withoutScheme := origin
if idx := strings.Index(withoutScheme, "://"); idx >= 0 {
withoutScheme = withoutScheme[idx+3:]
}
if idx := strings.Index(withoutScheme, "/"); idx >= 0 {
withoutScheme = withoutScheme[:idx]
}
originHost := withoutScheme
originPort := ""
if idx := strings.LastIndex(originHost, ":"); idx >= 0 {
originPort = originHost[idx+1:]
originHost = originHost[:idx]
}
originHost = strings.TrimPrefix(originHost, "[")
originHost = strings.TrimSuffix(originHost, "]")
// Match configured host
if host != "" && originHost == host {
return true
}
// Match request's own Host header (same-origin)
if reqHost != "" && originHost == reqHost {
return true
}
// Localhost variants
if originHost == "localhost" || originHost == "127.0.0.1" || originHost == "::1" {
if port == "" || originPort == "" || originPort == port {
return true
}
}
return false
}
+21 -21
View File
@@ -2,28 +2,28 @@ package permissions
// Permission bitflags.
const (
VIEW_CHANNEL int64 = 1 << 0
SEND_MESSAGES int64 = 1 << 1
MANAGE_MESSAGES int64 = 1 << 2
KICK_MEMBERS int64 = 1 << 3
BAN_MEMBERS int64 = 1 << 4
MANAGE_SERVER int64 = 1 << 5
MANAGE_CHANNELS int64 = 1 << 6
ADMINISTRATOR int64 = 1 << 7
CONNECT_VOICE int64 = 1 << 8
SPEAK_VOICE int64 = 1 << 9
SHARE_SCREEN int64 = 1 << 10
MUTE_MEMBERS int64 = 1 << 11
VIEW_CHANNEL int64 = 1 << 0
SEND_MESSAGES int64 = 1 << 1
MANAGE_MESSAGES int64 = 1 << 2
KICK_MEMBERS int64 = 1 << 3
BAN_MEMBERS int64 = 1 << 4
MANAGE_SERVER int64 = 1 << 5
MANAGE_CHANNELS int64 = 1 << 6
ADMINISTRATOR int64 = 1 << 7
CONNECT_VOICE int64 = 1 << 8
SPEAK_VOICE int64 = 1 << 9
SHARE_SCREEN int64 = 1 << 10
MUTE_MEMBERS int64 = 1 << 11
CREATE_INSTANT_INVITE int64 = 1 << 12
CHANGE_NICKNAME int64 = 1 << 13
MANAGE_NICKNAMES int64 = 1 << 14
MANAGE_ROLES int64 = 1 << 15
MANAGE_WEBHOOKS int64 = 1 << 16
EMBED_LINKS int64 = 1 << 17
ATTACH_FILES int64 = 1 << 18
ADD_REACTIONS int64 = 1 << 19
USE_EXTERNAL_EMOJIS int64 = 1 << 20
MENTION_EVERYONE int64 = 1 << 21
CHANGE_NICKNAME int64 = 1 << 13
MANAGE_NICKNAMES int64 = 1 << 14
MANAGE_ROLES int64 = 1 << 15
MANAGE_WEBHOOKS int64 = 1 << 16
EMBED_LINKS int64 = 1 << 17
ATTACH_FILES int64 = 1 << 18
ADD_REACTIONS int64 = 1 << 19
USE_EXTERNAL_EMOJIS int64 = 1 << 20
MENTION_EVERYONE int64 = 1 << 21
)
// DefaultEveryonePermissions is granted to the @everyone role when a server is created.
+1 -2
View File
@@ -183,8 +183,6 @@ func (h *Handler) SendPush(ctx context.Context, userID string, payload map[strin
}
}
// SendChannelNotification sends a push notification to all server members (except the author)
// when a new message is posted in a channel.
func (h *Handler) SendChannelNotification(ctx context.Context, channelID, authorID, channelName, content string) {
@@ -254,6 +252,7 @@ func (h *Handler) SendChannelNotification(ctx context.Context, channelID, author
}
}
}
// GenerateVAPIDKeys generates a new VAPID key pair.
func GenerateVAPIDKeys() (publicKey, privateKey string, err error) {
privateKeyBytes := make([]byte, 32)
+3 -3
View File
@@ -148,9 +148,9 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
h.hub.BroadcastToServer(serverID, gateway.Event{
Type: gateway.EventReactionAdd,
Data: map[string]interface{}{
"reaction": reaction,
"channel_id": channelID,
"message_id": messageID,
"reaction": reaction,
"channel_id": channelID,
"message_id": messageID,
},
})
+6 -6
View File
@@ -5,15 +5,15 @@ import (
"fmt"
"time"
lksdk "github.com/livekit/server-sdk-go/v2"
"github.com/livekit/protocol/auth"
"github.com/livekit/protocol/livekit"
lksdk "github.com/livekit/server-sdk-go/v2"
)
type Client struct {
apiKey string
apiSecret string
url string
apiKey string
apiSecret string
url string
roomClient *lksdk.RoomServiceClient
}
@@ -62,8 +62,8 @@ func (c *Client) CreateRoom(name string) (*livekit.Room, error) {
}
room, err := c.roomClient.CreateRoom(context.Background(), &livekit.CreateRoomRequest{
Name: name,
EmptyTimeout: 300, // 5 minutes before auto-delete when empty
Name: name,
EmptyTimeout: 300, // 5 minutes before auto-delete when empty
MaxParticipants: 20,
})
if err != nil {