package user import ( "errors" "testing" "time" "git.golem15.com/golem15/summercms/modules/bouncer" ) // TestAppBlacklist: the jwt guard's store resolves the app's published // bouncer.BlacklistStore on every call. With none published (or only an // appBlacklist, which would recurse) no token is blacklisted and Add and // Sweep do nothing; otherwise calls are delegated and a store error comes // back unchanged, so the guard still fails closed. func TestAppBlacklist(t *testing.T) { ctx := t.Context() now := time.Now() newApp := func() *appBlacklist { return &appBlacklist{app: sessionUserApp(t, "SUMMER_GOLEM15__USER__JWT__SECRET="+sessionSecret)} } assertNoStore := func(t *testing.T, bl *appBlacklist) { t.Helper() if got, err := bl.IsBlacklisted(ctx, "jti-none"); got || err != nil { t.Fatalf("IsBlacklisted with no store = %v, %v", got, err) } if err := bl.Add(ctx, "jti-none", now.Add(time.Hour), now); err != nil { t.Fatalf("Add with no store = %v", err) } if err := bl.Sweep(ctx, now); err != nil { t.Fatalf("Sweep with no store = %v", err) } } t.Run("no store", func(t *testing.T) { assertNoStore(t, newApp()) }) t.Run("wrapper published as the store", func(t *testing.T) { bl := newApp() if err := bl.app.Publish[bouncer.BlacklistStore](&appBlacklist{app: bl.app}); err != nil { t.Fatal(err) } assertNoStore(t, bl) }) t.Run("delegates", func(t *testing.T) { bl := newApp() mem := bouncer.NewMemoryBlacklist() if err := bl.app.Publish[bouncer.BlacklistStore](mem); err != nil { t.Fatal(err) } // Blacklisted from now on, kept for an hour. if err := bl.Add(ctx, "jti-ended", now.Add(time.Hour), now); err != nil { t.Fatal(err) } if got, err := mem.IsBlacklisted(ctx, "jti-ended"); !got || err != nil { t.Fatalf("memory store after Add through the wrapper = %v, %v", got, err) } if got, err := bl.IsBlacklisted(ctx, "jti-ended"); !got || err != nil { t.Fatalf("IsBlacklisted(jti-ended) = %v, %v", got, err) } if got, err := bl.IsBlacklisted(ctx, "jti-other"); got || err != nil { t.Fatalf("IsBlacklisted(jti-other) = %v, %v", got, err) } if err := bl.Sweep(ctx, now); err != nil { t.Fatal(err) } }) t.Run("store error passes through", func(t *testing.T) { bl := newApp() if err := bl.app.Publish[bouncer.BlacklistStore](failingBlacklist{}); err != nil { t.Fatal(err) } if _, err := bl.IsBlacklisted(ctx, "jti"); !errors.Is(err, errBlacklistDown) { t.Fatalf("IsBlacklisted error = %v", err) } if err := bl.Add(ctx, "jti", now.Add(time.Hour), now); !errors.Is(err, errBlacklistDown) { t.Fatalf("Add error = %v", err) } if err := bl.Sweep(ctx, now); !errors.Is(err, errBlacklistDown) { t.Fatalf("Sweep error = %v", err) } }) }