Files
Charon/backend/internal/models/user_test.go
akanealw eec8c28fb3
Some checks failed
Go Benchmark / Performance Regression Check (push) Has been cancelled
Cerberus Integration / Cerberus Security Stack Integration (push) Has been cancelled
Upload Coverage to Codecov / Backend Codecov Upload (push) Has been cancelled
Upload Coverage to Codecov / Frontend Codecov Upload (push) Has been cancelled
CodeQL - Analyze / CodeQL analysis (go) (push) Has been cancelled
CodeQL - Analyze / CodeQL analysis (javascript-typescript) (push) Has been cancelled
CrowdSec Integration / CrowdSec Bouncer Integration (push) Has been cancelled
Docker Build, Publish & Test / build-and-push (push) Has been cancelled
Quality Checks / Auth Route Protection Contract (push) Has been cancelled
Quality Checks / Codecov Trigger/Comment Parity Guard (push) Has been cancelled
Quality Checks / Backend (Go) (push) Has been cancelled
Quality Checks / Frontend (React) (push) Has been cancelled
Rate Limit integration / Rate Limiting Integration (push) Has been cancelled
Security Scan (PR) / Trivy Binary Scan (push) Has been cancelled
Supply Chain Verification (PR) / Verify Supply Chain (push) Has been cancelled
WAF integration / Coraza WAF Integration (push) Has been cancelled
Docker Build, Publish & Test / Security Scan PR Image (push) Has been cancelled
Repo Health Check / Repo health (push) Has been cancelled
History Rewrite Dry-Run / Dry-run preview for history rewrite (push) Has been cancelled
Prune Renovate Branches / prune (push) Has been cancelled
Renovate / renovate (push) Has been cancelled
Nightly Build & Package / sync-development-to-nightly (push) Has been cancelled
Nightly Build & Package / Trigger Nightly Validation Workflows (push) Has been cancelled
Nightly Build & Package / build-and-push-nightly (push) Has been cancelled
Nightly Build & Package / test-nightly-image (push) Has been cancelled
Nightly Build & Package / verify-nightly-supply-chain (push) Has been cancelled
Update GeoLite2 Checksum / update-checksum (push) Has been cancelled
Container Registry Prune / prune-ghcr (push) Has been cancelled
Container Registry Prune / prune-dockerhub (push) Has been cancelled
Container Registry Prune / summarize (push) Has been cancelled
Supply Chain Verification / Verify SBOM (push) Has been cancelled
Supply Chain Verification / Verify Release Artifacts (push) Has been cancelled
Supply Chain Verification / Verify Docker Image Supply Chain (push) Has been cancelled
Monitor Caddy Major Release / check-caddy-major (push) Has been cancelled
Weekly Nightly to Main Promotion / Verify Nightly Branch Health (push) Has been cancelled
Weekly Nightly to Main Promotion / Create Promotion PR (push) Has been cancelled
Weekly Nightly to Main Promotion / Trigger Missing Required Checks (push) Has been cancelled
Weekly Nightly to Main Promotion / Notify on Failure (push) Has been cancelled
Weekly Nightly to Main Promotion / Workflow Summary (push) Has been cancelled
Weekly Security Rebuild / Security Rebuild & Scan (push) Has been cancelled
changed perms
2026-04-22 18:19:14 +00:00

222 lines
5.4 KiB
Go
Executable File

package models
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestUser_SetPassword(t *testing.T) {
u := &User{}
err := u.SetPassword("password123")
assert.NoError(t, err)
assert.NotEmpty(t, u.PasswordHash)
assert.NotEqual(t, "password123", u.PasswordHash)
// Test with empty password (should still work but hash empty string)
u2 := &User{}
err = u2.SetPassword("")
assert.NoError(t, err)
assert.NotEmpty(t, u2.PasswordHash)
// Test with special characters
u3 := &User{}
err = u3.SetPassword("P@ssw0rd!#$%^&*()")
assert.NoError(t, err)
assert.NotEmpty(t, u3.PasswordHash)
assert.True(t, u3.CheckPassword("P@ssw0rd!#$%^&*()"))
}
func TestUser_CheckPassword(t *testing.T) {
u := &User{}
_ = u.SetPassword("password123")
assert.True(t, u.CheckPassword("password123"))
assert.False(t, u.CheckPassword("wrongpassword"))
}
func TestUser_HasPendingInvite(t *testing.T) {
tests := []struct {
name string
user User
expected bool
}{
{
name: "no invite token",
user: User{InviteToken: "", InviteStatus: ""},
expected: false,
},
{
name: "expired invite",
user: User{
InviteToken: "token123",
InviteExpires: timePtr(time.Now().Add(-1 * time.Hour)),
InviteStatus: "pending",
},
expected: false,
},
{
name: "valid pending invite",
user: User{
InviteToken: "token123",
InviteExpires: timePtr(time.Now().Add(24 * time.Hour)),
InviteStatus: "pending",
},
expected: true,
},
{
name: "already accepted invite",
user: User{
InviteToken: "token123",
InviteExpires: timePtr(time.Now().Add(24 * time.Hour)),
InviteStatus: "accepted",
},
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := tt.user.HasPendingInvite()
assert.Equal(t, tt.expected, result)
})
}
}
func TestUser_CanAccessHost_AllowAll(t *testing.T) {
// User with allow_all mode (blacklist) - can access everything except listed hosts
user := User{
Role: RoleUser,
PermissionMode: PermissionModeAllowAll,
PermittedHosts: []ProxyHost{
{ID: 1}, // Blocked host
{ID: 2}, // Blocked host
},
}
// Should NOT be able to access hosts in the blacklist
assert.False(t, user.CanAccessHost(1))
assert.False(t, user.CanAccessHost(2))
// Should be able to access other hosts
assert.True(t, user.CanAccessHost(3))
assert.True(t, user.CanAccessHost(100))
}
func TestUser_CanAccessHost_DenyAll(t *testing.T) {
// User with deny_all mode (whitelist) - can only access listed hosts
user := User{
Role: RoleUser,
PermissionMode: PermissionModeDenyAll,
PermittedHosts: []ProxyHost{
{ID: 5}, // Allowed host
{ID: 6}, // Allowed host
},
}
// Should be able to access hosts in the whitelist
assert.True(t, user.CanAccessHost(5))
assert.True(t, user.CanAccessHost(6))
// Should NOT be able to access other hosts
assert.False(t, user.CanAccessHost(1))
assert.False(t, user.CanAccessHost(100))
}
func TestUser_CanAccessHost_AdminBypass(t *testing.T) {
// Admin users should always have access regardless of permission mode
adminUser := User{
Role: RoleAdmin,
PermissionMode: PermissionModeDenyAll,
PermittedHosts: []ProxyHost{}, // No hosts in whitelist
}
// Admin should still be able to access any host
assert.True(t, adminUser.CanAccessHost(1))
assert.True(t, adminUser.CanAccessHost(999))
}
func TestUser_CanAccessHost_DefaultBehavior(t *testing.T) {
// User with empty/default permission mode should behave like allow_all
user := User{
Role: RoleUser,
PermissionMode: "", // Empty = default
PermittedHosts: []ProxyHost{
{ID: 1}, // Should be blocked
},
}
assert.False(t, user.CanAccessHost(1))
assert.True(t, user.CanAccessHost(2))
}
func TestUser_CanAccessHost_EmptyPermittedHosts(t *testing.T) {
tests := []struct {
name string
permissionMode PermissionMode
hostID uint
expected bool
}{
{
name: "allow_all with no exceptions allows all",
permissionMode: PermissionModeAllowAll,
hostID: 1,
expected: true,
},
{
name: "deny_all with no exceptions denies all",
permissionMode: PermissionModeDenyAll,
hostID: 1,
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
user := User{
Role: RoleUser,
PermissionMode: tt.permissionMode,
PermittedHosts: []ProxyHost{},
}
result := user.CanAccessHost(tt.hostID)
assert.Equal(t, tt.expected, result)
})
}
}
func TestPermissionMode_Constants(t *testing.T) {
assert.Equal(t, PermissionMode("allow_all"), PermissionModeAllowAll)
assert.Equal(t, PermissionMode("deny_all"), PermissionModeDenyAll)
}
func TestUserRole_Constants(t *testing.T) {
assert.Equal(t, UserRole("admin"), RoleAdmin)
assert.Equal(t, UserRole("user"), RoleUser)
assert.Equal(t, UserRole("passthrough"), RolePassthrough)
}
func TestUserRole_IsValid(t *testing.T) {
tests := []struct {
role UserRole
expected bool
}{
{RoleAdmin, true},
{RoleUser, true},
{RolePassthrough, true},
{UserRole("viewer"), false},
{UserRole("superadmin"), false},
{UserRole(""), false},
}
for _, tt := range tests {
t.Run(string(tt.role), func(t *testing.T) {
assert.Equal(t, tt.expected, tt.role.IsValid())
})
}
}
// Helper function to create time pointers
func timePtr(t time.Time) *time.Time {
return &t
}