BOLO-KESARI commited on
Commit
2033599
Β·
1 Parent(s): 5a8126f

Switch to direct bcrypt to fix 72-byte error

Browse files
Files changed (3) hide show
  1. backend/app/core/security.py +17 -24
  2. test_deployment.py +21 -46
  3. test_log.txt +16 -0
backend/app/core/security.py CHANGED
@@ -13,38 +13,31 @@ from .config import settings
13
  from .database import get_db
14
  from ..models.user import User
15
 
16
- # Password hashing context
17
- pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
18
 
19
  # HTTP Bearer token scheme
20
  security = HTTPBearer()
21
 
22
-
23
  def hash_password(password: str) -> str:
24
- """
25
- Hash a plain text password using bcrypt.
26
-
27
- Args:
28
- password: Plain text password
29
-
30
- Returns:
31
- Hashed password string
32
- """
33
- return pwd_context.hash(password)
34
 
35
 
36
  def verify_password(plain_password: str, hashed_password: str) -> bool:
37
- """
38
- Verify a plain text password against a hashed password.
39
-
40
- Args:
41
- plain_password: Plain text password to verify
42
- hashed_password: Hashed password from database
43
-
44
- Returns:
45
- True if password matches, False otherwise
46
- """
47
- return pwd_context.verify(plain_password, hashed_password)
48
 
49
 
50
  def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
 
13
  from .database import get_db
14
  from ..models.user import User
15
 
16
+ import bcrypt
17
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
18
 
19
  # HTTP Bearer token scheme
20
  security = HTTPBearer()
21
 
 
22
  def hash_password(password: str) -> str:
23
+ """Hash a plain text password using bcrypt."""
24
+ # Bcrypt has a 72-byte limit. We'll truncate just in case, though
25
+ # passwords shouldn't be that long.
26
+ pwd_bytes = password.encode('utf-8')[:72]
27
+ salt = bcrypt.gensalt()
28
+ hashed = bcrypt.hashpw(pwd_bytes, salt)
29
+ return hashed.decode('utf-8')
 
 
 
30
 
31
 
32
  def verify_password(plain_password: str, hashed_password: str) -> bool:
33
+ """Verify a plain text password against a hashed password."""
34
+ try:
35
+ return bcrypt.checkpw(
36
+ plain_password.encode('utf-8')[:72],
37
+ hashed_password.encode('utf-8')
38
+ )
39
+ except Exception:
40
+ return False
 
 
 
41
 
42
 
43
  def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
test_deployment.py CHANGED
@@ -2,10 +2,14 @@
2
  import requests
3
  import json
4
  import time
 
5
 
6
  BASE_URL = "https://pranit144-finance.hf.space"
7
- # Optional: test local if needed
8
- # BASE_URL = "http://localhost:8000"
 
 
 
9
 
10
  def test_endpoint(name, method, path, data=None, token=None):
11
  url = f"{BASE_URL}{path}"
@@ -13,8 +17,7 @@ def test_endpoint(name, method, path, data=None, token=None):
13
  if token:
14
  headers["Authorization"] = f"Bearer {token}"
15
 
16
- print(f"\nπŸš€ Testing {name}...")
17
- print(f" {method} {url}")
18
 
19
  try:
20
  if method == "GET":
@@ -22,55 +25,27 @@ def test_endpoint(name, method, path, data=None, token=None):
22
  elif method == "POST":
23
  response = requests.post(url, headers=headers, json=data, timeout=15)
24
 
25
- print(f" Status: {response.status_code}")
26
  try:
27
  body = response.json()
28
- print(f" Response: {json.dumps(body, indent=2)}")
29
  return body
30
  except:
31
- print(f" Response: {response.text[:200]}")
32
  return None
33
  except Exception as e:
34
- print(f" ❌ Error: {e}")
35
  return None
36
 
37
- def run_all_tests():
38
- print(f"=== DEPLOYMENT TEST SUITE: {BASE_URL} ===")
39
-
40
- # 1. Health
41
- test_endpoint("Health Check", "GET", "/health")
42
-
43
- # 2. Signup
44
- timestamp = int(time.time())
45
- test_email = f"test_user_{timestamp}@example.com"
46
- signup_data = {
47
- "email": test_email,
48
- "password": "password123",
49
- "name": "Test User",
50
- "role": "STAFF"
51
- }
52
- signup_res = test_endpoint("Signup", "POST", "/auth/signup", data=signup_data)
53
-
54
- # 3. Login
55
- login_data = {
56
- "email": test_email,
57
- "password": "password123"
58
- }
59
- login_res = test_endpoint("Login", "POST", "/auth/login", data=login_data)
60
 
61
- token = None
62
- if login_res and "access_token" in login_res:
63
- token = login_res["access_token"]
64
- print(" βœ… Got Auth Token!")
65
- else:
66
- print(" ❌ Failed to get auth token")
67
- return
68
-
69
- # 4. Protected: Get Popular Stocks
70
- test_endpoint("Popular Stocks (Auth)", "GET", "/stocks/popular", token=token)
71
 
72
- # 5. Protected: Get Portfolio (Expected empty)
73
- test_endpoint("Get Portfolio (Auth)", "GET", "/portfolio/", token=token)
74
-
75
- if __name__ == "__main__":
76
- run_all_tests()
 
2
  import requests
3
  import json
4
  import time
5
+ import sys
6
 
7
  BASE_URL = "https://pranit144-finance.hf.space"
8
+
9
+ def log_test(msg):
10
+ with open("test_log.txt", "a", encoding="utf-8") as f:
11
+ f.write(msg + "\n")
12
+ print(msg)
13
 
14
  def test_endpoint(name, method, path, data=None, token=None):
15
  url = f"{BASE_URL}{path}"
 
17
  if token:
18
  headers["Authorization"] = f"Bearer {token}"
19
 
20
+ log_test(f"\nπŸš€ Testing {name}...")
 
21
 
22
  try:
23
  if method == "GET":
 
25
  elif method == "POST":
26
  response = requests.post(url, headers=headers, json=data, timeout=15)
27
 
28
+ log_test(f" Status: {response.status_code}")
29
  try:
30
  body = response.json()
31
+ log_test(f" Response: {json.dumps(body, indent=2)}")
32
  return body
33
  except:
34
+ log_test(f" Response: {response.text[:1000]}")
35
  return None
36
  except Exception as e:
37
+ log_test(f" ❌ Error: {e}")
38
  return None
39
 
40
+ if __name__ == "__main__":
41
+ with open("test_log.txt", "w", encoding="utf-8") as f:
42
+ f.write("=== LOG START ===\n")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
+ # Health
45
+ test_endpoint("Health", "GET", "/health")
 
 
 
 
 
 
 
 
46
 
47
+ # Signup
48
+ ts = int(time.time())
49
+ email = f"user_{ts}@test.com"
50
+ signup_data = {"email": email, "password": "password123", "name": "Test User", "role": "STAFF"}
51
+ test_endpoint("Signup", "POST", "/auth/signup", data=signup_data)
test_log.txt ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === LOG START ===
2
+
3
+ πŸš€ Testing Health...
4
+ Status: 200
5
+ Response: {
6
+ "status": "healthy",
7
+ "api": "operational",
8
+ "database": "connected (tables: portfolio, users)",
9
+ "sqlite_path": "sqlite:///./stock_analysis_prod.db"
10
+ }
11
+
12
+ πŸš€ Testing Signup...
13
+ Status: 500
14
+ Response: {
15
+ "detail": "Database error: password cannot be longer than 72 bytes, truncate manually if necessary (e.g. my_password[:72]) | Trace: hecksum\n hash = _bcrypt.hashpw(secret, config)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nValueError: password cannot be longer than 72 bytes, truncate manually if necessary (e.g. my_password[:72])\n"
16
+ }