All checks were successful
check / check (push) Successful in 2m11s
- Add username and hostname columns to sessions table (001_initial.sql) - Accept optional username field in session creation and registration endpoints; defaults to nick if not provided - Resolve hostname via reverse DNS of connecting client IP at session creation time (supports X-Forwarded-For and X-Real-IP headers) - Display real username and hostname in WHOIS (311 RPL_WHOISUSER) and WHO (352 RPL_WHOREPLY) responses instead of nick/servername - Add FormatHostmask helper for nick!user@host format - Add SessionHostInfo type and GetSessionHostInfo query - Include username/hostname in MemberInfo and ChannelMembers results - Extract validateHashcash and resolveUsername helpers to stay under funlen limits - Add comprehensive unit tests for all new DB functions, hostmask formatting, and integration tests for WHOIS/WHO responses - Update README with hostmask documentation, new API fields, and updated schema reference
242 lines
4.2 KiB
Go
242 lines
4.2 KiB
Go
package db_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
func TestRegisterUser(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
database := setupTestDB(t)
|
|
ctx := t.Context()
|
|
|
|
sessionID, clientID, token, err :=
|
|
database.RegisterUser(ctx, "reguser", "password123", "", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if sessionID == 0 || clientID == 0 || token == "" {
|
|
t.Fatal("expected valid ids and token")
|
|
}
|
|
|
|
// Verify session works via token lookup.
|
|
sid, cid, nick, err :=
|
|
database.GetSessionByToken(ctx, token)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if sid != sessionID || cid != clientID {
|
|
t.Fatal("session/client id mismatch")
|
|
}
|
|
|
|
if nick != "reguser" {
|
|
t.Fatalf("expected reguser, got %s", nick)
|
|
}
|
|
}
|
|
|
|
func TestRegisterUserWithUserHost(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
database := setupTestDB(t)
|
|
ctx := t.Context()
|
|
|
|
sessionID, _, _, err := database.RegisterUser(
|
|
ctx, "reguhost", "password123",
|
|
"myident", "example.org",
|
|
)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
info, err := database.GetSessionHostInfo(
|
|
ctx, sessionID,
|
|
)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if info.Username != "myident" {
|
|
t.Fatalf(
|
|
"expected myident, got %s", info.Username,
|
|
)
|
|
}
|
|
|
|
if info.Hostname != "example.org" {
|
|
t.Fatalf(
|
|
"expected example.org, got %s",
|
|
info.Hostname,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestRegisterUserDefaultUsername(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
database := setupTestDB(t)
|
|
ctx := t.Context()
|
|
|
|
sessionID, _, _, err := database.RegisterUser(
|
|
ctx, "regdefault", "password123", "", "",
|
|
)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
info, err := database.GetSessionHostInfo(
|
|
ctx, sessionID,
|
|
)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if info.Username != "regdefault" {
|
|
t.Fatalf(
|
|
"expected regdefault, got %s",
|
|
info.Username,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestRegisterUserDuplicateNick(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
database := setupTestDB(t)
|
|
ctx := t.Context()
|
|
|
|
regSID, regCID, regToken, err :=
|
|
database.RegisterUser(ctx, "dupnick", "password123", "", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_ = regSID
|
|
_ = regCID
|
|
_ = regToken
|
|
|
|
dupSID, dupCID, dupToken, dupErr :=
|
|
database.RegisterUser(ctx, "dupnick", "other12345", "", "")
|
|
if dupErr == nil {
|
|
t.Fatal("expected error for duplicate nick")
|
|
}
|
|
|
|
_ = dupSID
|
|
_ = dupCID
|
|
_ = dupToken
|
|
}
|
|
|
|
func TestLoginUser(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
database := setupTestDB(t)
|
|
ctx := t.Context()
|
|
|
|
regSID, regCID, regToken, err :=
|
|
database.RegisterUser(ctx, "loginuser", "mypassword", "", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_ = regSID
|
|
_ = regCID
|
|
_ = regToken
|
|
|
|
sessionID, clientID, token, err :=
|
|
database.LoginUser(ctx, "loginuser", "mypassword")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if sessionID == 0 || clientID == 0 || token == "" {
|
|
t.Fatal("expected valid ids and token")
|
|
}
|
|
|
|
// Verify the new token works.
|
|
_, _, nick, err :=
|
|
database.GetSessionByToken(ctx, token)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if nick != "loginuser" {
|
|
t.Fatalf("expected loginuser, got %s", nick)
|
|
}
|
|
}
|
|
|
|
func TestLoginUserWrongPassword(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
database := setupTestDB(t)
|
|
ctx := t.Context()
|
|
|
|
regSID, regCID, regToken, err :=
|
|
database.RegisterUser(ctx, "wrongpw", "correctpass", "", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_ = regSID
|
|
_ = regCID
|
|
_ = regToken
|
|
|
|
loginSID, loginCID, loginToken, loginErr :=
|
|
database.LoginUser(ctx, "wrongpw", "wrongpass12")
|
|
if loginErr == nil {
|
|
t.Fatal("expected error for wrong password")
|
|
}
|
|
|
|
_ = loginSID
|
|
_ = loginCID
|
|
_ = loginToken
|
|
}
|
|
|
|
func TestLoginUserNoPassword(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
database := setupTestDB(t)
|
|
ctx := t.Context()
|
|
|
|
// Create anonymous session (no password).
|
|
anonSID, anonCID, anonToken, err :=
|
|
database.CreateSession(ctx, "anon", "", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_ = anonSID
|
|
_ = anonCID
|
|
_ = anonToken
|
|
|
|
loginSID, loginCID, loginToken, loginErr :=
|
|
database.LoginUser(ctx, "anon", "anything1")
|
|
if loginErr == nil {
|
|
t.Fatal(
|
|
"expected error for login on passwordless account",
|
|
)
|
|
}
|
|
|
|
_ = loginSID
|
|
_ = loginCID
|
|
_ = loginToken
|
|
}
|
|
|
|
func TestLoginUserNonexistent(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
database := setupTestDB(t)
|
|
ctx := t.Context()
|
|
|
|
loginSID, loginCID, loginToken, err :=
|
|
database.LoginUser(ctx, "ghost", "password123")
|
|
if err == nil {
|
|
t.Fatal("expected error for nonexistent user")
|
|
}
|
|
|
|
_ = loginSID
|
|
_ = loginCID
|
|
_ = loginToken
|
|
}
|