rohanv56 commited on
Commit
d83fa13
Β·
1 Parent(s): 092a51e

update API endpoints

Browse files
.gitignore ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ pip-wheel-metadata/
20
+ share/python-wheels/
21
+ *.egg-info/
22
+ .installed.cfg
23
+ *.egg
24
+ MANIFEST
25
+
26
+ # Virtual environments
27
+ venv/
28
+ env/
29
+ ENV/
30
+ env.bak/
31
+ venv.bak/
32
+
33
+ # IDEs
34
+ .vscode/
35
+ .idea/
36
+ *.swp
37
+ *.swo
38
+ *~
39
+ .DS_Store
40
+
41
+ # Environment variables
42
+ .env
43
+ .env.local
44
+ .env.*.local
45
+
46
+ # Logs
47
+ *.log
48
+ logs/
49
+
50
+ # Cache
51
+ .cache/
52
+ *.cache
53
+ .pytest_cache/
54
+
55
+ # OS
56
+ .DS_Store
57
+ Thumbs.db
58
+
59
+ # Project specific
60
+ __pycache__/
61
+ *.pkl
62
+ *.joblib
63
+ .vscode/settings.json
64
+
65
+ # Temporary files
66
+ *.tmp
67
+ *.temp
68
+ *.bak
backend/.env CHANGED
@@ -1,4 +1,5 @@
1
- VIRUSTOTAL_API_KEY=your_virustotal_key_here
2
- GOOGLE_SAFE_BROWSING_KEY=your_google_key_here
3
  APP_SECRET=phishguard_secret_2024
4
- DEBUG=True
 
 
1
+ VIRUSTOTAL_API_KEY=bb70b1af05e004605b7667a9eab263e36a08048ec854a7f1c030a958094e58a5
2
+ SAFE_BROWSING_API_KEY=AIzaSyCpElL0PeB1Llkq_Jo58k-gjejwNIk5B4k
3
  APP_SECRET=phishguard_secret_2024
4
+ DEBUG=True
5
+ ALLOWED_ORIGINS=https://rohanv56-phishing-detection-api.hf.space,http://localhost:8000
backend/__pycache__/ml_engine.cpython-313.pyc CHANGED
Binary files a/backend/__pycache__/ml_engine.cpython-313.pyc and b/backend/__pycache__/ml_engine.cpython-313.pyc differ
 
backend/ml_engine.py CHANGED
@@ -83,11 +83,13 @@ class MLEngine:
83
  def load_models(self) -> None:
84
  errors = []
85
 
86
- # URL model
87
  try:
88
- with open(URL_MODEL_PATH, "rb") as f:
89
- self.url_model = pickle.load(f)
90
  logger.info(f"URL model loaded from {URL_MODEL_PATH}")
 
 
 
91
  except FileNotFoundError:
92
  errors.append(f"URL model not found at {URL_MODEL_PATH}")
93
  except Exception as e:
@@ -95,8 +97,7 @@ class MLEngine:
95
 
96
  # URL feature columns
97
  try:
98
- with open(URL_COLS_PATH, "rb") as f:
99
- self.url_feature_cols = pickle.load(f)
100
  logger.info(f"URL feature cols loaded ({len(self.url_feature_cols)} features)")
101
  except FileNotFoundError:
102
  # Fall back to the canonical 30-feature list defined at top of file
@@ -109,6 +110,9 @@ class MLEngine:
109
  try:
110
  self.sms_model = joblib.load(SMS_MODEL_PATH)
111
  logger.info(f"SMS model loaded from {SMS_MODEL_PATH}")
 
 
 
112
  except FileNotFoundError:
113
  errors.append(f"SMS model not found at {SMS_MODEL_PATH}")
114
  except Exception as e:
 
83
  def load_models(self) -> None:
84
  errors = []
85
 
86
+ # URL model - use joblib to load (consistent with joblib.dump in training)
87
  try:
88
+ self.url_model = joblib.load(URL_MODEL_PATH)
 
89
  logger.info(f"URL model loaded from {URL_MODEL_PATH}")
90
+ # Verify that it's a valid sklearn model
91
+ if not hasattr(self.url_model, 'predict') or not hasattr(self.url_model, 'predict_proba'):
92
+ raise TypeError(f"URL model is not a valid sklearn model. Type: {type(self.url_model)}")
93
  except FileNotFoundError:
94
  errors.append(f"URL model not found at {URL_MODEL_PATH}")
95
  except Exception as e:
 
97
 
98
  # URL feature columns
99
  try:
100
+ self.url_feature_cols = joblib.load(URL_COLS_PATH)
 
101
  logger.info(f"URL feature cols loaded ({len(self.url_feature_cols)} features)")
102
  except FileNotFoundError:
103
  # Fall back to the canonical 30-feature list defined at top of file
 
110
  try:
111
  self.sms_model = joblib.load(SMS_MODEL_PATH)
112
  logger.info(f"SMS model loaded from {SMS_MODEL_PATH}")
113
+ # Verify it's a valid sklearn model/pipeline
114
+ if not hasattr(self.sms_model, 'predict') or not hasattr(self.sms_model, 'predict_proba'):
115
+ raise TypeError(f"SMS model is not a valid sklearn model. Type: {type(self.sms_model)}")
116
  except FileNotFoundError:
117
  errors.append(f"SMS model not found at {SMS_MODEL_PATH}")
118
  except Exception as e:
backend/models/__pycache__/schemas.cpython-313.pyc CHANGED
Binary files a/backend/models/__pycache__/schemas.cpython-313.pyc and b/backend/models/__pycache__/schemas.cpython-313.pyc differ
 
backend/models/schemas.py CHANGED
@@ -16,6 +16,7 @@ class ThreatLevel(str, Enum):
16
 
17
  class URLScanRequest(BaseModel):
18
  url: str = Field(..., description="The URL to scan", example="http://example.com/login")
 
19
 
20
  class MLURLResult(BaseModel):
21
  prediction: str # "phishing" | "legitimate"
 
16
 
17
  class URLScanRequest(BaseModel):
18
  url: str = Field(..., description="The URL to scan", example="http://example.com/login")
19
+ features: Optional[Dict[str, Any]] = Field(default_factory=dict, description="Pre-extracted URL features (30 binary features). If not provided, defaults to empty dict.")
20
 
21
  class MLURLResult(BaseModel):
22
  prediction: str # "phishing" | "legitimate"
backend/routes/__pycache__/scan.cpython-313.pyc CHANGED
Binary files a/backend/routes/__pycache__/scan.cpython-313.pyc and b/backend/routes/__pycache__/scan.cpython-313.pyc differ
 
backend/routes/scan.py CHANGED
@@ -149,26 +149,6 @@ async def scan_url(request: URLScanRequest):
149
  )
150
 
151
 
152
- # Extend schema to include features field
153
- from pydantic import BaseModel
154
- from typing import Optional
155
-
156
- class URLScanRequestFull(URLScanRequest):
157
- features: Optional[Dict[str, Any]] = {}
158
-
159
- # Override the endpoint to use the extended model
160
- router.routes = [r for r in router.routes if getattr(r, "path", "") != "/scan-url"]
161
-
162
- @router.post(
163
- "/scan-url",
164
- response_model=URLScanResponse,
165
- summary="Scan a URL for phishing / malware",
166
- tags=["Scanning"],
167
- )
168
- async def scan_url_full(request: URLScanRequestFull):
169
- return await scan_url(request)
170
-
171
-
172
  # ─── POST /scan-sms ───────────────────────────────────────────────────────────
173
 
174
  @router.post(
@@ -229,10 +209,10 @@ async def scan_qr(request: QRScanRequest):
229
  t0 = time.monotonic()
230
 
231
  # Reuse URL scan logic
232
- url_request = URLScanRequestFull(url=request.decoded_url, features={})
233
 
234
  try:
235
- url_scan_result = await scan_url_full(url_request)
236
  except HTTPException:
237
  raise
238
  except Exception as e:
 
149
  )
150
 
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  # ─── POST /scan-sms ───────────────────────────────────────────────────────────
153
 
154
  @router.post(
 
209
  t0 = time.monotonic()
210
 
211
  # Reuse URL scan logic
212
+ url_request = URLScanRequest(url=request.decoded_url, features={})
213
 
214
  try:
215
+ url_scan_result = await scan_url(url_request)
216
  except HTTPException:
217
  raise
218
  except Exception as e:
ml_models/sms_model.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:5ed863367581f7acb795ea5fd90283d37149949d6f3e38b3c18b410dfd737254
3
  size 231057
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6a61c57c417f8d3aa2feb613609202b688e689d6610fde57753a97863b512304
3
  size 231057
ml_models/train_url_classifier.py CHANGED
@@ -103,10 +103,13 @@ def train_models(X, y, feature_cols):
103
  best_acc = max(rf_acc, xgb_acc)
104
  print(f"\n[+] Best model: {best_name} ({best_acc*100:.2f}%)")
105
 
106
- joblib.dump(rf, os.path.join(MODEL_DIR, "url_rf_model.pkl"))
107
- joblib.dump(xgb, os.path.join(MODEL_DIR, "url_xgb_model.pkl"))
108
- joblib.dump(best, os.path.join(MODEL_DIR, "url_best_model.pkl"))
109
- joblib.dump(feature_cols, os.path.join(MODEL_DIR, "url_feature_cols.pkl"))
 
 
 
110
 
111
  with open(os.path.join(MODEL_DIR, "url_model_info.txt"), "w") as f:
112
  f.write(f"Best model: {best_name}\n")
@@ -114,9 +117,14 @@ def train_models(X, y, feature_cols):
114
  f.write(f"RF Accuracy: {rf_acc*100:.2f}%\n")
115
  f.write(f"XGB Accuracy: {xgb_acc*100:.2f}%\n")
116
  f.write(f"Features: {feature_cols}\n")
 
117
 
118
  print("[+] Saved: url_best_model.pkl, url_rf_model.pkl, url_xgb_model.pkl, url_feature_cols.pkl")
119
 
 
 
 
 
120
  importances = pd.Series(best.feature_importances_, index=feature_cols)
121
  top5 = importances.nlargest(5)
122
  print("\n[*] Top 5 most important features:")
 
103
  best_acc = max(rf_acc, xgb_acc)
104
  print(f"\n[+] Best model: {best_name} ({best_acc*100:.2f}%)")
105
 
106
+ os.makedirs(MODEL_DIR, exist_ok=True)
107
+
108
+ # Use joblib consistently for all models to ensure compatibility
109
+ joblib.dump(rf, os.path.join(MODEL_DIR, "url_rf_model.pkl"), compress=3)
110
+ joblib.dump(xgb, os.path.join(MODEL_DIR, "url_xgb_model.pkl"), compress=3)
111
+ joblib.dump(best, os.path.join(MODEL_DIR, "url_best_model.pkl"), compress=3)
112
+ joblib.dump(feature_cols, os.path.join(MODEL_DIR, "url_feature_cols.pkl"), compress=3)
113
 
114
  with open(os.path.join(MODEL_DIR, "url_model_info.txt"), "w") as f:
115
  f.write(f"Best model: {best_name}\n")
 
117
  f.write(f"RF Accuracy: {rf_acc*100:.2f}%\n")
118
  f.write(f"XGB Accuracy: {xgb_acc*100:.2f}%\n")
119
  f.write(f"Features: {feature_cols}\n")
120
+ f.write(f"Model type saved: {type(best).__name__}\n")
121
 
122
  print("[+] Saved: url_best_model.pkl, url_rf_model.pkl, url_xgb_model.pkl, url_feature_cols.pkl")
123
 
124
+ # Verify that best is a proper sklearn model with required methods
125
+ if not hasattr(best, 'predict') or not hasattr(best, 'predict_proba'):
126
+ raise ValueError(f"ERROR: Saved model does not have required methods. Type: {type(best)}")
127
+
128
  importances = pd.Series(best.feature_importances_, index=feature_cols)
129
  top5 = importances.nlargest(5)
130
  print("\n[*] Top 5 most important features:")
ml_models/url_best_model.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:67299c44b7830768da2f21a6a4b934185f21e20206bbe7ad64f1b8397e32b127
3
- size 8387401
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e9e4a21643333d824248c3f892eb449ce4574e8ce0f9ec5785ea6f06afbaccd4
3
+ size 1745423
ml_models/url_feature_cols.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:0a70fbbd450056aa56b42ccb03f9df051473fdc915ff954b71af168efd351dd7
3
- size 458
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:54fa299350458e68d6bf45da4ae9a761159896b1c1cb78698ddc5c79bb8bf129
3
+ size 332
ml_models/url_model_info.txt CHANGED
@@ -3,3 +3,4 @@ Accuracy: 97.11%
3
  RF Accuracy: 97.11%
4
  XGB Accuracy: 96.83%
5
  Features: ['UsingIP', 'LongURL', 'ShortURL', 'Symbol@', 'Redirecting//', 'PrefixSuffix-', 'SubDomains', 'HTTPS', 'DomainRegLen', 'Favicon', 'NonStdPort', 'HTTPSDomainURL', 'RequestURL', 'AnchorURL', 'LinksInScriptTags', 'ServerFormHandler', 'InfoEmail', 'AbnormalURL', 'WebsiteForwarding', 'StatusBarCust', 'DisableRightClick', 'UsingPopupWindow', 'IframeRedirection', 'AgeofDomain', 'DNSRecording', 'WebsiteTraffic', 'PageRank', 'GoogleIndex', 'LinksPointingToPage', 'StatsReport']
 
 
3
  RF Accuracy: 97.11%
4
  XGB Accuracy: 96.83%
5
  Features: ['UsingIP', 'LongURL', 'ShortURL', 'Symbol@', 'Redirecting//', 'PrefixSuffix-', 'SubDomains', 'HTTPS', 'DomainRegLen', 'Favicon', 'NonStdPort', 'HTTPSDomainURL', 'RequestURL', 'AnchorURL', 'LinksInScriptTags', 'ServerFormHandler', 'InfoEmail', 'AbnormalURL', 'WebsiteForwarding', 'StatusBarCust', 'DisableRightClick', 'UsingPopupWindow', 'IframeRedirection', 'AgeofDomain', 'DNSRecording', 'WebsiteTraffic', 'PageRank', 'GoogleIndex', 'LinksPointingToPage', 'StatsReport']
6
+ Model type saved: RandomForestClassifier
ml_models/url_rf_model.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:67299c44b7830768da2f21a6a4b934185f21e20206bbe7ad64f1b8397e32b127
3
- size 8387401
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e9e4a21643333d824248c3f892eb449ce4574e8ce0f9ec5785ea6f06afbaccd4
3
+ size 1745423
ml_models/url_xgb_model.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:863f307294721af7431889d8a2989581812a2149e9eb392762f37e35ab12b0d6
3
- size 255997
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2520fe1afc7aac37af02c6b138be94d2f137ccbfed0c114ab11e5d936eec5e96
3
+ size 79523