Skip to content

Commit 73682c3

Browse files
security: remove exposed credentials from .env.example and strip token logging
- Replace real Supabase keys, GitHub OAuth credentials in .env.example with placeholder values (real keys were committed and are in git history) - Remove all console.log(token) calls from daily-note route that were leaking JWT tokens (containing GitHub access tokens) to server logs - Fix daily-note route: return generic error instead of raw DB error message to avoid leaking internal schema details to clients - Fix unauthorized response code: 400 → 401
1 parent 9ce5706 commit 73682c3

2 files changed

Lines changed: 70 additions & 102 deletions

File tree

.env.example

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# -------------------------------------------------------
22
# Supabase
33
# Project Settings → API → Project URL
4-
NEXT_PUBLIC_SUPABASE_URL=https://supabase.com/dashboard/project/dxvccvuzcvpisjytnrqc
4+
NEXT_PUBLIC_SUPABASE_URL=https://<project-ref>.supabase.co
55

66
# Project Settings → API → anon / public key
7-
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImR4dmNjdnV6Y3ZwaXNqeXRucnFjIiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODAxNTA1NTQsImV4cCI6MjA5NTcyNjU1NH0.i6KJ7SBLQ5LpsN-d8q3-O0sMJbSIFVy2JNzm1kr41lg
7+
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
88

99
# Project Settings → API → service_role secret (server-side only — never expose client-side)
10-
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImR4dmNjdnV6Y3ZwaXNqeXRucnFjIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc4MDE1MDU1NCwiZXhwIjoyMDk1NzI2NTU0fQ.gip54uSJ1K63zTek58je6BKl0wRt7TC6IoAt33rsOF4
10+
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key
1111

1212
# -------------------------------------------------------
1313
# NextAuth
@@ -28,10 +28,10 @@ NEXTAUTH_SECRET=your_nextauth_secret
2828
# -------------------------------------------------------
2929
# GitHub OAuth App
3030
# github.com/settings/applications/new → Client ID
31-
GITHUB_ID=Ov23litbr03dy9vWnQSh
31+
GITHUB_ID=your_github_oauth_client_id
3232

3333
# github.com/settings/applications/new → Client Secret
34-
GITHUB_SECRET=bdfa094aa67c8b619044bc36dafce3ffe40ec458
34+
GITHUB_SECRET=your_github_oauth_client_secret
3535

3636
# -------------------------------------------------------
3737
# GitHub Webhook (optional — enables real-time metric refresh on push)
@@ -66,7 +66,7 @@ UPSTASH_REDIS_REST_TOKEN=your_upstash_redis_rest_token
6666
# Groq API Key (optional — enables AI-generated weekly summaries in the
6767
# AI Mentor widget using Llama-3).
6868
# console.groq.com → API Keys
69-
GROQ_API_KEY=gsk_...
69+
GROQ_API_KEY=your_groq_api_key
7070

7171
# -------------------------------------------------------
7272
# Leaderboard Configuration
@@ -75,4 +75,3 @@ GROQ_API_KEY=gsk_...
7575
# Higher values = faster builds but more resource usage
7676
# WARNING: Do not exceed 100 without load testing — risks memory exhaustion
7777
LEADERBOARD_USER_CONCURRENCY=5
78-

src/app/api/daily-note/route.ts

Lines changed: 64 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,90 @@
1-
import { NextResponse ,NextRequest} from "next/server";
1+
import { NextResponse, NextRequest } from "next/server";
22
import { supabaseAdmin } from "@/lib/supabase";
33
import { getToken } from "next-auth/jwt";
44

5-
export async function GET(req: NextRequest){
6-
7-
try{
5+
export async function GET(req: NextRequest) {
6+
try {
87
const token = await getToken({
98
req,
109
secret: process.env.NEXTAUTH_SECRET,
1110
});
12-
console.log(token)
13-
11+
1412
const userId = token?.githubId;
1513

16-
if(!userId){
17-
return NextResponse.json(
18-
{error: `Unauthorized`},
19-
{status: 400}
20-
);
14+
if (!userId) {
15+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
2116
}
2217

2318
const today = new Date();
2419
const todayDate = today.toISOString().split("T")[0];
2520

2621
const yesterday = new Date();
27-
yesterday.setDate(yesterday.getDate() -1);
28-
22+
yesterday.setDate(yesterday.getDate() - 1);
2923
const yesterdayDate = yesterday.toISOString().split("T")[0];
3024

31-
const {data : todayData} = await supabaseAdmin
32-
.from("daily_notes")
33-
.select("*")
34-
.eq("user_id",userId)
35-
.eq("date",todayDate)
36-
.single();
37-
38-
const {data : yesterdayData} = await supabaseAdmin
39-
.from("daily_notes")
40-
.select("*")
41-
.eq("user_id",userId)
42-
.eq("date",yesterdayDate)
43-
.single();
44-
console.log(todayData,yesterdayData);
25+
const { data: todayData } = await supabaseAdmin
26+
.from("daily_notes")
27+
.select("*")
28+
.eq("user_id", userId)
29+
.eq("date", todayDate)
30+
.single();
31+
32+
const { data: yesterdayData } = await supabaseAdmin
33+
.from("daily_notes")
34+
.select("*")
35+
.eq("user_id", userId)
36+
.eq("date", yesterdayDate)
37+
.single();
38+
4539
return NextResponse.json({
4640
todayNote: todayData?.note || "",
4741
yesterdayNote: yesterdayData?.note || "",
4842
});
49-
50-
}catch(error){
51-
return NextResponse.json(
52-
{error: `Something went wrong `},
53-
{status: 500}
54-
);
55-
43+
} catch {
44+
return NextResponse.json({ error: "Something went wrong" }, { status: 500 });
5645
}
5746
}
5847

5948
export async function POST(req: NextRequest) {
60-
try{
61-
62-
const token = await getToken({
63-
req,
64-
secret: process.env.NEXTAUTH_SECRET,
65-
});
66-
console.log(token)
67-
68-
const userId = token?.githubId;
69-
const body = await req.json();
70-
console.log(body);
71-
const { note} = body;
72-
if(!userId){
73-
console.log("no user id");
74-
return NextResponse.json(
75-
{error: "User id is requied "},
76-
{status: 400}
77-
);
78-
}
79-
if(!note || !note.trim()){
80-
console.log("no note ");
81-
return NextResponse.json(
82-
{error: "Note cannot be empty"},
83-
{status: 400}
84-
);
85-
}
86-
if(note.length >280){
87-
console.log("max len ");
88-
return NextResponse.json(
89-
{error: "Maximum 280 characters allowed"},
90-
{status: 400}
91-
);
92-
}
93-
const today = new Date().toISOString().split("T")[0];
94-
const {data, error} = await supabaseAdmin
95-
.from("daily_notes")
96-
.upsert({
97-
user_id: userId,
98-
date: today,
99-
note: note.trim(),
100-
},{
101-
onConflict:"user_id,date"
102-
})
103-
.select()
104-
.single();
105-
if(error){
106-
console.log(error.message);
107-
return NextResponse.json(
108-
{error: error.message},
109-
{status:500}
110-
);
49+
try {
50+
const token = await getToken({
51+
req,
52+
secret: process.env.NEXTAUTH_SECRET,
53+
});
54+
55+
const userId = token?.githubId;
56+
57+
if (!userId) {
58+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
59+
}
60+
61+
const body = await req.json();
62+
const { note } = body;
63+
64+
if (!note || !note.trim()) {
65+
return NextResponse.json({ error: "Note cannot be empty" }, { status: 400 });
66+
}
67+
68+
if (note.length > 280) {
69+
return NextResponse.json({ error: "Maximum 280 characters allowed" }, { status: 400 });
70+
}
71+
72+
const today = new Date().toISOString().split("T")[0];
73+
const { data, error } = await supabaseAdmin
74+
.from("daily_notes")
75+
.upsert(
76+
{ user_id: userId, date: today, note: note.trim() },
77+
{ onConflict: "user_id,date" }
78+
)
79+
.select()
80+
.single();
81+
82+
if (error) {
83+
return NextResponse.json({ error: "Failed to save note" }, { status: 500 });
84+
}
85+
86+
return NextResponse.json(data);
87+
} catch {
88+
return NextResponse.json({ error: "Something went wrong" }, { status: 500 });
11189
}
112-
console.log(data);
113-
return NextResponse.json(data);
114-
}catch(error){
115-
console.log(error);
116-
return NextResponse.json(
117-
{error: "Something went wrong"},
118-
{status:500}
119-
);
120-
}
121-
}
90+
}

0 commit comments

Comments
 (0)