Files
dumpsterChat/internal/permissions/checker.go
T
hobokenchicken af1de3d140 Phase 6: Permissions, Push, WebAuthn scaffolding
Backend:
- internal/permissions/permissions.go: permission bitflags (VIEW_CHANNEL through SHARE_SCREEN)
- internal/permissions/checker.go: permission checker with role aggregation
- internal/middleware/permission.go: RequirePermission middleware
- internal/push/handlers.go: push subscription CRUD, VAPID key endpoint, SendPush
- internal/auth/webauthn.go: WebAuthn passkey scaffolding (begin/finish endpoints)
- internal/db/db.go: is_default on roles, push_subscriptions table, webauthn_credentials table
- go.mod: added webpush-go, go-webauthn dependencies

Frontend:
- stores/role.ts: Zustand store for role management
- RoleManager.tsx: role CRUD with permission checkboxes
- MemberRoleAssign.tsx: assign roles to members
- App.tsx: /servers/:serverId/roles route
2026-06-28 17:53:44 -04:00

83 lines
2.0 KiB
Go

package permissions
import (
"context"
"database/sql"
)
// Checker verifies user permissions against the database.
type Checker struct {
db *sql.DB
}
// NewChecker creates a new Checker backed by the given database connection.
func NewChecker(db *sql.DB) *Checker {
return &Checker{db: db}
}
// GetUserPermissions returns the effective (OR'd) permissions for a user in a server.
// It aggregates all permissions from the roles assigned to the user, plus the
// @everyone role for that server.
func (c *Checker) GetUserPermissions(ctx context.Context, serverID string, userID string) (int64, error) {
rows, err := c.db.QueryContext(ctx, `
SELECT r.permissions
FROM roles r
INNER JOIN member_roles mr ON mr.role_id = r.id
WHERE mr.user_id = $1 AND mr.server_id = $2
`, userID, serverID)
if err != nil {
return 0, err
}
defer rows.Close()
var effective int64
found := false
for rows.Next() {
var perm int64
if err := rows.Scan(&perm); err != nil {
return 0, err
}
effective |= perm
found = true
}
if err := rows.Err(); err != nil {
return 0, err
}
// Also include the @everyone role permissions for this server.
var everyonePerm int64
err = c.db.QueryRowContext(ctx, `
SELECT permissions FROM roles
WHERE server_id = $1 AND is_default = TRUE
LIMIT 1
`, serverID).Scan(&everyonePerm)
if err != nil && err != sql.ErrNoRows {
return 0, err
}
effective |= everyonePerm
if everyonePerm != 0 {
found = true
}
if !found {
return 0, nil
}
return effective, nil
}
// CheckPermission reports whether the user has all the required permission bits
// in the given server. ADMINISTRATOR bypasses all checks.
func (c *Checker) CheckPermission(ctx context.Context, serverID string, userID string, required int64) (bool, error) {
perms, err := c.GetUserPermissions(ctx, serverID, userID)
if err != nil {
return false, err
}
// Administrator bypasses everything.
if Has(perms, ADMINISTRATOR) {
return true, nil
}
return Has(perms, required), nil
}