Anish-530 commited on
Commit
8a0d65c
·
1 Parent(s): 0edd56d

[Vercel Deployment]

Browse files
backend/app/security/turnstile.py CHANGED
@@ -17,7 +17,7 @@ async def verify_turnstile_token(token: str, ip_address: str = None) -> bool:
17
 
18
  verify_url = "https://challenges.cloudflare.com/turnstile/v0/siteverify"
19
  payload = {
20
- "secret": settings.TURNSTILE_SECRET_KEY or "1x0000000000000000000000000000000AA",
21
  "response": token
22
  }
23
 
 
17
 
18
  verify_url = "https://challenges.cloudflare.com/turnstile/v0/siteverify"
19
  payload = {
20
+ "secret": settings.TURNSTILE_SECRET_KEY,
21
  "response": token
22
  }
23
 
backend/main.py CHANGED
@@ -2,6 +2,8 @@ from fastapi import FastAPI
2
  from fastapi.middleware.cors import CORSMiddleware
3
  from fastapi.staticfiles import StaticFiles
4
  from contextlib import asynccontextmanager
 
 
5
  from slowapi import _rate_limit_exceeded_handler
6
  from slowapi.errors import RateLimitExceeded
7
  from app.api.user_routes import router as user_router
@@ -23,16 +25,32 @@ async def lifespan(app: FastAPI):
23
  pass
24
  yield
25
 
 
 
26
  app = FastAPI(
27
  title="Spotix",
28
- lifespan=lifespan
 
 
 
 
 
 
 
 
 
 
 
29
  )
30
 
31
- app.add_middleware(SessionMiddleware, secret_key="neural-vault-oauth-session-secret-9912")
 
 
 
32
 
33
  app.add_middleware(
34
  CORSMiddleware,
35
- allow_origins=["http://localhost:3000"],
36
  allow_credentials=True,
37
  allow_methods=["*"],
38
  allow_headers=["*"],
 
2
  from fastapi.middleware.cors import CORSMiddleware
3
  from fastapi.staticfiles import StaticFiles
4
  from contextlib import asynccontextmanager
5
+ import os
6
+ from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
7
  from slowapi import _rate_limit_exceeded_handler
8
  from slowapi.errors import RateLimitExceeded
9
  from app.api.user_routes import router as user_router
 
25
  pass
26
  yield
27
 
28
+ is_production = os.environ.get("ENVIRONMENT", "development") == "production"
29
+
30
  app = FastAPI(
31
  title="Spotix",
32
+ lifespan=lifespan,
33
+ docs_url=None if is_production else "/docs",
34
+ redoc_url=None if is_production else "/redoc",
35
+ openapi_url=None if is_production else "/openapi.json"
36
+ )
37
+
38
+ app.add_middleware(ProxyHeadersMiddleware, trusted_hosts=["*"])
39
+
40
+ app.add_middleware(
41
+ SessionMiddleware,
42
+ secret_key=os.environ.get("SESSION_SECRET_KEY", "neural-vault-oauth-session-secret-9912"),
43
+ https_only=is_production
44
  )
45
 
46
+ frontend_url = os.environ.get("FRONTEND_URL", "http://localhost:3000")
47
+ origins = [frontend_url]
48
+ if frontend_url != "http://localhost:3000":
49
+ origins.append("http://localhost:3000")
50
 
51
  app.add_middleware(
52
  CORSMiddleware,
53
+ allow_origins=origins,
54
  allow_credentials=True,
55
  allow_methods=["*"],
56
  allow_headers=["*"],
frontend/app/login/page.tsx CHANGED
@@ -74,14 +74,15 @@ export default function LoginPage() {
74
  }
75
 
76
  try {
 
77
  if (mode === 'login') {
78
- const res = await axios.post("http://localhost:8000/auth/login", { identifier, password }, {
79
  headers: { "cf-turnstile-response": turnstileToken }
80
  });
81
  localStorage.setItem("access_token", res.data.access_token);
82
  window.location.href = "/dashboard";
83
  } else {
84
- const res = await axios.post("http://localhost:8000/users/register", { email, username, password }, {
85
  headers: { "cf-turnstile-response": turnstileToken }
86
  });
87
  setSuccessMessage(res.data.message || "Account created! Check your email to verify.");
@@ -206,7 +207,7 @@ export default function LoginPage() {
206
 
207
  <div className="flex justify-center mt-4">
208
  <Turnstile
209
- siteKey={process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY || '1x00000000000000000000AA'}
210
  onSuccess={(token) => setTurnstileToken(token)}
211
  onError={() => setError("Turnstile security check failed.")}
212
  onExpire={() => setTurnstileToken("")}
@@ -244,7 +245,7 @@ export default function LoginPage() {
244
  </div>
245
 
246
  <a
247
- href="http://localhost:8000/auth/google/login"
248
  className="w-full mt-8 py-4 rounded-xl flex items-center justify-center gap-3 bg-theme-text/5 hover:bg-[var(--theme-text)]/10 border border-theme-border transition group cursor-pointer"
249
  >
250
  <svg className="w-5 h-5" viewBox="0 0 24 24">
 
74
  }
75
 
76
  try {
77
+ const baseUrl = process.env.NEXT_PUBLIC_BACKEND_URL || "http://localhost:8000";
78
  if (mode === 'login') {
79
+ const res = await axios.post(`${baseUrl}/auth/login`, { identifier, password }, {
80
  headers: { "cf-turnstile-response": turnstileToken }
81
  });
82
  localStorage.setItem("access_token", res.data.access_token);
83
  window.location.href = "/dashboard";
84
  } else {
85
+ const res = await axios.post(`${baseUrl}/users/register`, { email, username, password }, {
86
  headers: { "cf-turnstile-response": turnstileToken }
87
  });
88
  setSuccessMessage(res.data.message || "Account created! Check your email to verify.");
 
207
 
208
  <div className="flex justify-center mt-4">
209
  <Turnstile
210
+ siteKey={process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY!}
211
  onSuccess={(token) => setTurnstileToken(token)}
212
  onError={() => setError("Turnstile security check failed.")}
213
  onExpire={() => setTurnstileToken("")}
 
245
  </div>
246
 
247
  <a
248
+ href={`${process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'}/auth/google/login`}
249
  className="w-full mt-8 py-4 rounded-xl flex items-center justify-center gap-3 bg-theme-text/5 hover:bg-[var(--theme-text)]/10 border border-theme-border transition group cursor-pointer"
250
  >
251
  <svg className="w-5 h-5" viewBox="0 0 24 24">
frontend/components/upload/UploadZone.tsx CHANGED
@@ -53,7 +53,8 @@ export default function UploadZone({ autoAnalyze = false }: { autoAnalyze?: bool
53
  };
54
  if (token) headers["Authorization"] = `Bearer ${token}`;
55
 
56
- const uploadRes = await axios.post("http://localhost:8000/files/upload", formData, {
 
57
  withCredentials: true,
58
  headers
59
  });
@@ -66,7 +67,8 @@ export default function UploadZone({ autoAnalyze = false }: { autoAnalyze?: bool
66
  const pollInterval = setInterval(async () => {
67
  if (!polling) return;
68
  try {
69
- const statusRes = await axios.get(`http://localhost:8000/files/${fileId}`, {
 
70
  withCredentials: true,
71
  headers
72
  });
 
53
  };
54
  if (token) headers["Authorization"] = `Bearer ${token}`;
55
 
56
+ const baseUrl = process.env.NEXT_PUBLIC_BACKEND_URL || "http://localhost:8000";
57
+ const uploadRes = await axios.post(`${baseUrl}/files/upload`, formData, {
58
  withCredentials: true,
59
  headers
60
  });
 
67
  const pollInterval = setInterval(async () => {
68
  if (!polling) return;
69
  try {
70
+ const baseUrl = process.env.NEXT_PUBLIC_BACKEND_URL || "http://localhost:8000";
71
+ const statusRes = await axios.get(`${baseUrl}/files/${fileId}`, {
72
  withCredentials: true,
73
  headers
74
  });
frontend/lib/api.ts CHANGED
@@ -9,7 +9,7 @@ const getToken = () => {
9
  };
10
 
11
  export const api = axios.create({
12
- baseURL: 'http://localhost:8000',
13
  withCredentials: true
14
  });
15
 
 
9
  };
10
 
11
  export const api = axios.create({
12
+ baseURL: process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000',
13
  withCredentials: true
14
  });
15
 
render.yaml ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ services:
2
+ - type: web
3
+ name: spotix-api
4
+ env: python
5
+ buildCommand: "cd backend && pip install -r requirements.txt"
6
+ startCommand: "cd backend && uvicorn main:app --host 0.0.0.0 --port $PORT --forwarded-allow-ips='*' --proxy-headers"
7
+ envVars:
8
+ - key: DATABASE_URL
9
+ sync: false
10
+ - key: REDIS_URL
11
+ sync: false
12
+ - key: JWT_SECRET
13
+ generateValue: true
14
+ - key: TURNSTILE_SECRET_KEY
15
+ sync: false
16
+ - key: ENVIRONMENT
17
+ value: production
18
+ - key: FRONTEND_URL
19
+ sync: false
20
+ - key: R2_ENDPOINT_URL
21
+ sync: false
22
+ - key: R2_ACCESS_KEY_ID
23
+ sync: false
24
+ - key: R2_SECRET_ACCESS_KEY
25
+ sync: false
26
+ - key: R2_BUCKET_NAME
27
+ sync: false
28
+
29
+ - type: worker
30
+ name: spotix-celery
31
+ env: python
32
+ buildCommand: "cd backend && pip install -r requirements.txt"
33
+ startCommand: "cd backend && celery -A app.worker.celery_app worker --loglevel=info -P solo"
34
+ envVars:
35
+ - key: DATABASE_URL
36
+ fromService:
37
+ type: web
38
+ name: spotix-api
39
+ envVarKey: DATABASE_URL
40
+ - key: REDIS_URL
41
+ fromService:
42
+ type: web
43
+ name: spotix-api
44
+ envVarKey: REDIS_URL
45
+ - key: R2_ENDPOINT_URL
46
+ fromService:
47
+ type: web
48
+ name: spotix-api
49
+ envVarKey: R2_ENDPOINT_URL
50
+ - key: R2_ACCESS_KEY_ID
51
+ fromService:
52
+ type: web
53
+ name: spotix-api
54
+ envVarKey: R2_ACCESS_KEY_ID
55
+ - key: R2_SECRET_ACCESS_KEY
56
+ fromService:
57
+ type: web
58
+ name: spotix-api
59
+ envVarKey: R2_SECRET_ACCESS_KEY
60
+ - key: R2_BUCKET_NAME
61
+ fromService:
62
+ type: web
63
+ name: spotix-api
64
+ envVarKey: R2_BUCKET_NAME