Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apiproxy/validateToken.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import (
func CompareToken(hashes []db.ApiKey, apiKey string) (string, error) {

for _, hash := range hashes {
if hash.Deactivated {
continue
}
err := bcrypt.CompareHashAndPassword([]byte(hash.ApiKey), []byte(apiKey))
// log.Printf("Compared %s with %s", apiKey, hash.ApiKey)
if err == nil {
Expand Down
58 changes: 58 additions & 0 deletions apiproxy/validateToken_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package apiproxy

import (
"testing"

db "openai-api-proxy/db"

"golang.org/x/crypto/bcrypt"
)

func mustHash(t *testing.T, plain string) string {
t.Helper()
hash, err := bcrypt.GenerateFromPassword([]byte(plain), bcrypt.MinCost)
if err != nil {
t.Fatalf("failed to hash token: %v", err)
}
return string(hash)
}

func TestCompareToken_IgnoresDeactivatedKeys(t *testing.T) {
activeToken := "active-secret"
deactivatedToken := "deactivated-secret"

keys := []db.ApiKey{
{
UUID: "dead-key",
ApiKey: mustHash(t, deactivatedToken),
Deactivated: true,
},
{
UUID: "active-key",
ApiKey: mustHash(t, activeToken),
Deactivated: false,
},
}

if got, err := CompareToken(keys, activeToken); err != nil || got != "active-key" {
t.Fatalf("expected active key to validate, got uuid=%q err=%v", got, err)
}

if got, err := CompareToken(keys, deactivatedToken); err == nil {
t.Fatalf("expected deactivated key to be rejected, got uuid=%q", got)
}
}

func TestCompareToken_AllDeactivatedRejected(t *testing.T) {
keys := []db.ApiKey{
{
UUID: "dead-1",
ApiKey: mustHash(t, "dead-secret"),
Deactivated: true,
},
}

if got, err := CompareToken(keys, "dead-secret"); err == nil {
t.Fatalf("expected deactivated key to be rejected, got uuid=%q", got)
}
}
2 changes: 2 additions & 0 deletions app/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
Always run `npm run typecheck` after making changes that affect TypeScript types.
Always run `npm run check:write` to auto-fix Biome issues and surface remaining errors.
Always run `npm run build` when finishing a feature to do a final check.
Always add new feature entries to `app/RELEASE_NOTES.md`.
When finishing a feature, ask the user whether a new version should be added to `app/RELEASE_NOTES.md`.
4 changes: 4 additions & 0 deletions app/RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Release Notes

## 0.1.0 - 2026-03-04
- Initial release notes tracking.
1 change: 1 addition & 0 deletions app/drizzle/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export const apikeys = pgTable(
owner: varchar({ length: 255 }).notNull(),
aiapi: varchar({ length: 255 }),
description: varchar({ length: 255 }),
deactivated: boolean("deactivated").default(false).notNull(),
},
(table) => [
foreignKey({
Expand Down
Loading