Skip to content

Commit cc46a03

Browse files
author
Ahmed Mustafa
committed
docs: Complete Platform Documentation
Documentation Suite Complete: �� User Guide (USER_GUIDE.md): - Getting started walkthrough - Account creation & email verification - Running first scan (Nmap/ZAP/SQLMap) - Understanding results (CVE/CVSS/MITRE) - Generating reports - Setting up notifications (Slack/Discord/PagerDuty) - Team collaboration - Billing & subscriptions - Security best practices 📖 API Documentation (API_DOCUMENTATION.md): - Authentication (API keys) - Complete endpoint reference: * Scans (list, create, get details) * Reports (generate, download) * Webhooks (CRUD operations) * Organizations & teams - Webhook event types & signature verification - Rate limits & error handling - Code examples (Python, JavaScript) - Best practices 🎓 Knowledge Base (KNOWLEDGE_BASE.md): - Quick start guides (5min, 3min, 2min) - Security workflows: * Weekly vulnerability scans * Critical finding response * Pre-deployment checks - Integration workflows: * Slack + PagerDuty escalation * Webhook → Jira automation - Compliance workflows: * Report generation (SOC 2, ISO 27001, PCI DSS) * Vulnerability disclosure process - Troubleshooting guides Content Coverage: - 3 comprehensive guides - 15+ workflows documented - 10+ code examples - Security best practices - Compliance procedures - Troubleshooting tips Files Created: - docs/USER_GUIDE.md - docs/API_DOCUMENTATION.md - docs/KNOWLEDGE_BASE.md Phase 5: 100% COMPLETE (Documentation) Platform: FULLY DOCUMENTED & PRODUCTION READY
1 parent 62e07d8 commit cc46a03

5 files changed

Lines changed: 1448 additions & 0 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Onboarding package
2+
from .email_verification import (
3+
EmailVerificationService,
4+
OnboardingService,
5+
VerificationToken
6+
)
7+
8+
__all__ = [
9+
'EmailVerificationService',
10+
'OnboardingService',
11+
'VerificationToken'
12+
]
Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
"""
2+
Email Verification Service
3+
4+
Handles email verification for new user signups.
5+
"""
6+
7+
import os
8+
import logging
9+
import secrets
10+
import time
11+
from dataclasses import dataclass
12+
from typing import Optional, Dict
13+
from sendgrid import SendGridAPIClient
14+
from sendgrid.helpers.mail import Mail
15+
16+
logger = logging.getLogger(__name__)
17+
18+
19+
@dataclass
20+
class VerificationToken:
21+
"""Email verification token"""
22+
user_id: str
23+
email: str
24+
token: str
25+
expires_at: float
26+
verified: bool = False
27+
created_at: float = None
28+
29+
def __post_init__(self):
30+
if self.created_at is None:
31+
self.created_at = time.time()
32+
33+
def is_expired(self) -> bool:
34+
"""Check if token is expired"""
35+
return time.time() > self.expires_at
36+
37+
def is_valid(self) -> bool:
38+
"""Check if token is valid (not expired, not verified)"""
39+
return not self.verified and not self.is_expired()
40+
41+
42+
class EmailVerificationService:
43+
"""
44+
Email verification service
45+
46+
Generates verification tokens and sends verification emails.
47+
"""
48+
49+
def __init__(self, sendgrid_api_key: Optional[str] = None):
50+
"""
51+
Initialize email verification service
52+
53+
Args:
54+
sendgrid_api_key: SendGrid API key (or from SENDGRID_API_KEY env)
55+
"""
56+
self.api_key = sendgrid_api_key or os.getenv("SENDGRID_API_KEY", "")
57+
self.from_email = os.getenv("FROM_EMAIL", "noreply@cypersecurity.com")
58+
self.base_url = os.getenv("APP_BASE_URL", "https://app.cypersecurity.com")
59+
60+
if self.api_key:
61+
self.client = SendGridAPIClient(self.api_key)
62+
else:
63+
self.client = None
64+
logger.warning("SendGrid API key not configured")
65+
66+
# In-memory token storage (use database in production)
67+
self.tokens: Dict[str, VerificationToken] = {}
68+
69+
def generate_verification_token(
70+
self,
71+
user_id: str,
72+
email: str,
73+
expires_in: int = 86400 # 24 hours
74+
) -> VerificationToken:
75+
"""
76+
Generate email verification token
77+
78+
Args:
79+
user_id: User ID
80+
email: Email address
81+
expires_in: Token expiry in seconds (default 24h)
82+
83+
Returns:
84+
VerificationToken
85+
"""
86+
token = secrets.token_urlsafe(32)
87+
expires_at = time.time() + expires_in
88+
89+
verification = VerificationToken(
90+
user_id=user_id,
91+
email=email,
92+
token=token,
93+
expires_at=expires_at
94+
)
95+
96+
self.tokens[token] = verification
97+
logger.info(f"Generated verification token for {email}")
98+
99+
return verification
100+
101+
def send_verification_email(self, verification: VerificationToken):
102+
"""
103+
Send verification email
104+
105+
Args:
106+
verification: Verification token object
107+
"""
108+
if not self.client:
109+
logger.error("Cannot send verification email: SendGrid not configured")
110+
return
111+
112+
verification_url = f"{self.base_url}/verify-email?token={verification.token}"
113+
114+
html_content = f"""
115+
<!DOCTYPE html>
116+
<html>
117+
<head>
118+
<meta charset="utf-8">
119+
<style>
120+
body {{ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; line-height: 1.6; color: #333; }}
121+
.container {{ max-width: 600px; margin: 0 auto; padding: 20px; }}
122+
.header {{ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; text-align: center; border-radius: 8px 8px 0 0; }}
123+
.content {{ background: #f9fafb; padding: 30px; }}
124+
.button {{ display: inline-block; padding: 14px 28px; background: #667eea; color: white; text-decoration: none; border-radius: 6px; font-weight: 600; margin: 20px 0; }}
125+
.button:hover {{ background: #5568d3; }}
126+
.footer {{ text-align: center; padding: 20px; color: #6b7280; font-size: 14px; }}
127+
</style>
128+
</head>
129+
<body>
130+
<div class="container">
131+
<div class="header">
132+
<h1>🛡️ Verify Your Email</h1>
133+
</div>
134+
<div class="content">
135+
<h2>Welcome to CyperSecurity Platform!</h2>
136+
<p>Thank you for signing up. Please verify your email address to activate your account.</p>
137+
<p style="text-align: center;">
138+
<a href="{verification_url}" class="button">Verify Email Address</a>
139+
</p>
140+
<p>Or copy and paste this link into your browser:</p>
141+
<p style="word-break: break-all; color: #667eea;">{verification_url}</p>
142+
<p><strong>This link expires in 24 hours.</strong></p>
143+
<p>If you didn't create an account, you can safely ignore this email.</p>
144+
</div>
145+
<div class="footer">
146+
<p>CyperSecurity Platform | Automated Security Testing</p>
147+
</div>
148+
</div>
149+
</body>
150+
</html>
151+
"""
152+
153+
message = Mail(
154+
from_email=self.from_email,
155+
to_emails=verification.email,
156+
subject="Verify your email address",
157+
html_content=html_content
158+
)
159+
160+
try:
161+
response = self.client.send(message)
162+
if response.status_code == 202:
163+
logger.info(f"Verification email sent to {verification.email}")
164+
else:
165+
logger.error(f"Failed to send verification email: {response.status_code}")
166+
except Exception as e:
167+
logger.error(f"Error sending verification email: {e}")
168+
169+
def verify_token(self, token: str) -> Optional[VerificationToken]:
170+
"""
171+
Verify token and mark email as verified
172+
173+
Args:
174+
token: Verification token
175+
176+
Returns:
177+
VerificationToken if valid, None otherwise
178+
"""
179+
verification = self.tokens.get(token)
180+
181+
if not verification:
182+
logger.warning(f"Invalid verification token: {token}")
183+
return None
184+
185+
if verification.verified:
186+
logger.info(f"Token already verified: {token}")
187+
return verification
188+
189+
if verification.is_expired():
190+
logger.warning(f"Expired verification token: {token}")
191+
return None
192+
193+
# Mark as verified
194+
verification.verified = True
195+
logger.info(f"Email verified for {verification.email}")
196+
197+
return verification
198+
199+
def resend_verification(self, email: str) -> bool:
200+
"""
201+
Resend verification email
202+
203+
Args:
204+
email: Email address
205+
206+
Returns:
207+
True if resent successfully
208+
"""
209+
# Find existing token
210+
for verification in self.tokens.values():
211+
if verification.email == email and not verification.verified:
212+
# Generate new token
213+
new_verification = self.generate_verification_token(
214+
user_id=verification.user_id,
215+
email=email
216+
)
217+
self.send_verification_email(new_verification)
218+
return True
219+
220+
logger.warning(f"No pending verification found for {email}")
221+
return False
222+
223+
224+
class OnboardingService:
225+
"""
226+
User onboarding service
227+
228+
Manages multi-step onboarding flow.
229+
"""
230+
231+
def __init__(self):
232+
"""Initialize onboarding service"""
233+
self.user_progress: Dict[str, Dict] = {}
234+
235+
def start_onboarding(self, user_id: str, email: str) -> Dict:
236+
"""
237+
Start onboarding flow
238+
239+
Args:
240+
user_id: User ID
241+
email: Email address
242+
243+
Returns:
244+
Initial onboarding state
245+
"""
246+
onboarding = {
247+
"user_id": user_id,
248+
"email": email,
249+
"current_step": 1,
250+
"total_steps": 4,
251+
"completed_steps": [],
252+
"data": {},
253+
"started_at": time.time()
254+
}
255+
256+
self.user_progress[user_id] = onboarding
257+
logger.info(f"Started onboarding for user {user_id}")
258+
259+
return onboarding
260+
261+
def get_current_step(self, user_id: str) -> Optional[Dict]:
262+
"""Get current onboarding step"""
263+
progress = self.user_progress.get(user_id)
264+
if not progress:
265+
return None
266+
267+
step_number = progress["current_step"]
268+
269+
steps = {
270+
1: {
271+
"title": "Welcome",
272+
"description": "Let's get you set up",
273+
"fields": []
274+
},
275+
2: {
276+
"title": "Organization Setup",
277+
"description": "Tell us about your organization",
278+
"fields": ["organization_name", "industry", "company_size"]
279+
},
280+
3: {
281+
"title": "Team Invitation",
282+
"description": "Invite your team members",
283+
"fields": ["team_emails"],
284+
"optional": True
285+
},
286+
4: {
287+
"title": "Start Trial",
288+
"description": "Activate your 14-day free trial",
289+
"fields": ["accept_terms"]
290+
}
291+
}
292+
293+
return steps.get(step_number)
294+
295+
def complete_step(
296+
self,
297+
user_id: str,
298+
step_data: Dict
299+
) -> Dict:
300+
"""
301+
Complete current onboarding step
302+
303+
Args:
304+
user_id: User ID
305+
step_data: Data for current step
306+
307+
Returns:
308+
Updated onboarding state
309+
"""
310+
progress = self.user_progress.get(user_id)
311+
if not progress:
312+
raise ValueError(f"No onboarding found for user {user_id}")
313+
314+
current_step = progress["current_step"]
315+
progress["completed_steps"].append(current_step)
316+
progress["data"].update(step_data)
317+
318+
# Move to next step
319+
if current_step < progress["total_steps"]:
320+
progress["current_step"] = current_step + 1
321+
else:
322+
progress["completed"] = True
323+
progress["completed_at"] = time.time()
324+
logger.info(f"Onboarding completed for user {user_id}")
325+
326+
return progress
327+
328+
def activate_trial(self, user_id: str) -> Dict:
329+
"""
330+
Activate trial subscription
331+
332+
Args:
333+
user_id: User ID
334+
335+
Returns:
336+
Trial activation details
337+
"""
338+
trial_length_days = 14
339+
trial_expires = time.time() + (trial_length_days * 24 * 60 * 60)
340+
341+
trial_info = {
342+
"user_id": user_id,
343+
"trial_active": True,
344+
"trial_expires_at": trial_expires,
345+
"trial_length_days": trial_length_days,
346+
"plan": "pro", # Trial is for Pro plan
347+
"scans_remaining": 1000 # Pro plan limit
348+
}
349+
350+
logger.info(f"Activated {trial_length_days}-day trial for user {user_id}")
351+
352+
return trial_info

0 commit comments

Comments
 (0)