1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
import { NextResponse } from "next/server"
import { createSupabaseServerClient } from "@/lib/supabase/server"
import { createSupabaseAdminClient } from "@/lib/supabase/admin"
import { generateApiKey } from "@/lib/api-key"
import { TIER_LIMITS, type SubscriptionTier } from "@asa-news/shared"
import { rateLimit } from "@/lib/rate-limit"
const MAXIMUM_ACTIVE_KEYS = 5
export async function GET() {
const supabaseClient = await createSupabaseServerClient()
const {
data: { user },
} = await supabaseClient.auth.getUser()
if (!user) {
return NextResponse.json({ error: "Not authenticated" }, { status: 401 })
}
const adminClient = createSupabaseAdminClient()
const { data: keys, error } = await adminClient
.from("api_keys")
.select("id, key_prefix, label, created_at, last_used_at, revoked_at")
.eq("user_id", user.id)
.order("created_at", { ascending: false })
if (error) {
return NextResponse.json(
{ error: "Failed to load API keys" },
{ status: 500 }
)
}
return NextResponse.json({
keys: keys.map((key) => ({
identifier: key.id,
keyPrefix: key.key_prefix,
label: key.label,
createdAt: key.created_at,
lastUsedAt: key.last_used_at,
isRevoked: key.revoked_at !== null,
})),
})
}
export async function POST(request: Request) {
const supabaseClient = await createSupabaseServerClient()
const {
data: { user },
} = await supabaseClient.auth.getUser()
if (!user) {
return NextResponse.json({ error: "Not authenticated" }, { status: 401 })
}
const rateLimitResult = rateLimit(`api-keys:${user.id}`, 10, 60_000)
if (!rateLimitResult.success) {
return NextResponse.json({ error: "Too many requests" }, { status: 429 })
}
const adminClient = createSupabaseAdminClient()
const { data: userProfile } = await adminClient
.from("user_profiles")
.select("tier")
.eq("id", user.id)
.single()
if (
!userProfile ||
!TIER_LIMITS[userProfile.tier as SubscriptionTier]?.allowsApiAccess
) {
return NextResponse.json(
{ error: "API access requires the developer plan" },
{ status: 403 }
)
}
const { count: activeKeyCount } = await adminClient
.from("api_keys")
.select("id", { count: "exact", head: true })
.eq("user_id", user.id)
.is("revoked_at", null)
if ((activeKeyCount ?? 0) >= MAXIMUM_ACTIVE_KEYS) {
return NextResponse.json(
{ error: `Maximum of ${MAXIMUM_ACTIVE_KEYS} active keys allowed` },
{ status: 400 }
)
}
const body = await request.json().catch(() => ({}))
const label = typeof body.label === "string" ? body.label.trim() || null : null
const { fullKey, keyHash, keyPrefix } = generateApiKey()
const { error: insertError } = await adminClient.from("api_keys").insert({
user_id: user.id,
key_hash: keyHash,
key_prefix: keyPrefix,
label,
})
if (insertError) {
return NextResponse.json(
{ error: "Failed to create API key" },
{ status: 500 }
)
}
return NextResponse.json({
key: fullKey,
keyPrefix,
label,
})
}
|