From b6a417f40b4f3273015118d788ee5c25e3fdb690 Mon Sep 17 00:00:00 2001
From: Troy <troynovsak@gmail.com>
Date: Fri, 16 Feb 2024 23:08:21 -0500
Subject: [PATCH] adjusted breaches
---
backend/breaches/__init__.py | 0
backend/breaches/admin.py | 6 ++
backend/breaches/apps.py | 6 ++
backend/breaches/migrations/0001_initial.py | 27 +++++
backend/breaches/migrations/__init__.py | 0
backend/breaches/models.py | 8 ++
backend/breaches/tests.py | 3 +
backend/breaches/urls.py | 6 ++
backend/breaches/views.py | 80 ++++++++++++++
backend/db.sqlite3 | Bin 131072 -> 147456 bytes
backend/watchstone_backend/settings.py | 1 +
backend/watchstone_backend/urls.py | 21 +---
frontend/src/views/modules/Breaches.js | 109 +++++++++++++++-----
13 files changed, 224 insertions(+), 43 deletions(-)
create mode 100644 backend/breaches/__init__.py
create mode 100644 backend/breaches/admin.py
create mode 100644 backend/breaches/apps.py
create mode 100644 backend/breaches/migrations/0001_initial.py
create mode 100644 backend/breaches/migrations/__init__.py
create mode 100644 backend/breaches/models.py
create mode 100644 backend/breaches/tests.py
create mode 100644 backend/breaches/urls.py
create mode 100644 backend/breaches/views.py
diff --git a/backend/breaches/__init__.py b/backend/breaches/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/backend/breaches/admin.py b/backend/breaches/admin.py
new file mode 100644
index 000000000..b85e51012
--- /dev/null
+++ b/backend/breaches/admin.py
@@ -0,0 +1,6 @@
+from django.contrib import admin
+from .models import MonitoredEmail
+
+@admin.register(MonitoredEmail)
+class MonitoredEmailAdmin(admin.ModelAdmin):
+ list_display = ('email', 'added_on')
diff --git a/backend/breaches/apps.py b/backend/breaches/apps.py
new file mode 100644
index 000000000..d6eb14128
--- /dev/null
+++ b/backend/breaches/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class BreachesConfig(AppConfig):
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "breaches"
diff --git a/backend/breaches/migrations/0001_initial.py b/backend/breaches/migrations/0001_initial.py
new file mode 100644
index 000000000..dd19cac13
--- /dev/null
+++ b/backend/breaches/migrations/0001_initial.py
@@ -0,0 +1,27 @@
+# Generated by Django 4.2.9 on 2024-02-16 23:50
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ initial = True
+
+ dependencies = []
+
+ operations = [
+ migrations.CreateModel(
+ name="Account",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("email", models.EmailField(max_length=254, unique=True)),
+ ],
+ ),
+ ]
diff --git a/backend/breaches/migrations/__init__.py b/backend/breaches/migrations/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/backend/breaches/models.py b/backend/breaches/models.py
new file mode 100644
index 000000000..e9c6d574b
--- /dev/null
+++ b/backend/breaches/models.py
@@ -0,0 +1,8 @@
+from django.db import models
+
+class MonitoredEmail(models.Model):
+ email = models.EmailField(unique=True)
+ added_on = models.DateTimeField(auto_now_add=True)
+
+ def __str__(self):
+ return self.email
diff --git a/backend/breaches/tests.py b/backend/breaches/tests.py
new file mode 100644
index 000000000..7ce503c2d
--- /dev/null
+++ b/backend/breaches/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/backend/breaches/urls.py b/backend/breaches/urls.py
new file mode 100644
index 000000000..462f72fdf
--- /dev/null
+++ b/backend/breaches/urls.py
@@ -0,0 +1,6 @@
+from django.urls import path
+from . import views
+
+urlpatterns = [
+ path('upload/', views.upload_breaches, name='upload_breaches'),
+]
diff --git a/backend/breaches/views.py b/backend/breaches/views.py
new file mode 100644
index 000000000..14bdf4324
--- /dev/null
+++ b/backend/breaches/views.py
@@ -0,0 +1,80 @@
+from django.http import JsonResponse
+from .models import MonitoredEmail
+from django.views.decorators.http import require_http_methods
+import csv
+from io import StringIO
+from rest_framework.decorators import api_view, permission_classes
+from rest_framework.permissions import IsAuthenticated
+from django.http import JsonResponse
+from django.views.decorators.http import require_http_methods
+from django.views.decorators.csrf import csrf_exempt
+from rest_framework.decorators import api_view, permission_classes
+from rest_framework.permissions import IsAuthenticated
+import csv
+from io import StringIO
+from .models import MonitoredEmail
+from rest_framework.parsers import JSONParser
+
+@require_http_methods(["POST"])
+@permission_classes([IsAuthenticated])
+@csrf_exempt
+def upload_breaches(request):
+ # Initialize a list to hold emails
+ emails = []
+
+ # Extracting emails sent as 'email'
+ email = request.POST.get('email')
+ if email:
+ emails.append(email)
+
+ # Extracting emails sent as 'emails[index]'
+ for key in request.POST.keys():
+ if key.startswith('emails['):
+ emails.append(request.POST[key])
+
+ # Handle file if it's uploaded
+ file = request.FILES.get('file')
+ if file:
+ file_data = file.read().decode('utf-8')
+ csv_data = csv.reader(StringIO(file_data))
+ next(csv_data, None) # Skip the header row
+ for row in csv_data:
+ if row: # Ensure row is not empty
+ emails.append(row[0])
+
+ # Process each email
+ for email in emails:
+ MonitoredEmail.objects.get_or_create(email=email)
+
+ if emails:
+ return JsonResponse({'message': f'{len(emails)} emails added for monitoring.'}, status=201)
+ else:
+ return JsonResponse({'error': 'No emails provided.'}, status=400)
+
+
+@require_http_methods(["POST"])
+def check_email_breaches(request):
+ email = request.POST.get('email')
+ file = request.FILES.get('file')
+ results = {}
+
+ if email:
+ # Check the single email against breaches
+ results[email] = check_breach(email)
+
+ if file:
+ # Check each email in the CSV against breaches
+ file_data = file.read().decode('utf-8')
+ csv_data = csv.reader(StringIO(file_data))
+ for row in csv_data:
+ email = row[0]
+ results[email] = check_breach(email)
+
+ return JsonResponse({'results': results}, status=200)
+
+
+def check_breach(email):
+ # Placeholder for breach checking logic
+ # This could involve querying your own database or calling an external API
+ # For demonstration, it returns a dummy response
+ return "Not breached" # or "Breached" based on actual check
diff --git a/backend/db.sqlite3 b/backend/db.sqlite3
index 41edd444f67de71615187c74d2c0db5a4f1d0dac..39a81d346f3fd73efa2982e4f5fbf9b9663658d6 100644
GIT binary patch
delta 7351
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
Th%~VSk;b+l(#Qrx8d?JY0LBh=
delta 762
zcmZo@;B08%m>?~v%)r2)z<>Z&6LpLkl{Y5L=jRaSWnf?s;trV1E}*(uQ9*@!bAa>~
z79lqNG6w#a{8#vQ^Ox~=^RMBr*sNHPz^^9E!mQ1hSXz=1Uyxdqn^|0(nV%=Y%gL<B
z0TxUz$}cToV3<5dUyhAcoSE5}aq>YPVKz2lCT3lZ$v5@YM1{B*7#P_2yBYZ3@t@|u
z#lM$-0e|;q#e#DF$=&vq%o02ali3{%H!CV=@N7=-S;EXL!6!eNJpd%~oOiQ)+#^Oo
z1_lOJUVaAtOuox}w!F)D`8O*n{N-V36k+9^yee05vPo_cOQQ%2h%=d`QJ9%`vSZ#P
zmPTPF-pSWN3=u}&$+`Jcz~=CuW#E6s|Aqf7|3m)kn*|$o^BZ$Ai!+wwnV6Wef>}lR
zl}0Qa%%Y4XdHH3`Afckv#N-ktZf04|lGNgo(&E&jO&eGgI2Z)L0nD{kkm(Emq5}e(
z4zLI?OYoOYX1`##S+T&De|q75Mw!hM?-wU1aj{Hg;8)?h#CetN5N|n87n=xcILlP-
z?=Z;pce|Pc<3h&i_gop-H=koX&b0A@F4OiyZj7dkOpFgU|76!?1_k6raYaSO#_Z{g
z$&8YdJ-JtKae~~?)F>d#KHbrQal-a)AI36aU1oO%VTR8P{8@Yjyjyu*a6RX;;atga
zmqUo{6`KfaF4Jb_Nah1f4UAn(&J3R?8w&JTGP^VG5!cjYY||}COv*{kOD&I&2gfkT
zyQn;N=O9<d5Lbl|M<*Xwh3)2vj3G=y%zX?(f!d4=nR#sbY#=u=Oz%!+GzBq@T;-=v
zOlFkj2N@OLY@*8!wn%yVfn-K?c9!NkY4+`}vl!nnZ(rlVsL9C4wVCn3fB#7nSOnPk
uyBPT2^55h?#lMGtK7ZF{#ey>a>0Rd;t2VPdU>DfV{ebZ&|7MnkKl}jlJJ<{W
diff --git a/backend/watchstone_backend/settings.py b/backend/watchstone_backend/settings.py
index c48b24f23..ba29334f2 100644
--- a/backend/watchstone_backend/settings.py
+++ b/backend/watchstone_backend/settings.py
@@ -41,6 +41,7 @@ INSTALLED_APPS = [
"rest_framework",
"rest_framework_simplejwt",
"corsheaders",
+ "breaches",
]
MIDDLEWARE = [
diff --git a/backend/watchstone_backend/urls.py b/backend/watchstone_backend/urls.py
index 1cc09dbf9..d98ae5086 100644
--- a/backend/watchstone_backend/urls.py
+++ b/backend/watchstone_backend/urls.py
@@ -1,26 +1,9 @@
-"""
-URL configuration for watchstone_backend project.
-
-The `urlpatterns` list routes URLs to views. For more information please see:
- https://docs.djangoproject.com/en/4.2/topics/http/urls/
-Examples:
-Function views
- 1. Add an import: from my_app import views
- 2. Add a URL to urlpatterns: path('', views.home, name='home')
-Class-based views
- 1. Add an import: from other_app.views import Home
- 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
-Including another URLconf
- 1. Import the include() function: from django.urls import include, path
- 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
-"""
-# watchstone_backend/urls.py
-
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
- path('api/', include('core.urls')), # This line includes your app URLs
+ path('api/', include('core.urls')), # Core app URLs
path('api/auth/', include('auth_app.urls')),
+ path('api/breaches/', include('breaches.urls')), # Include breaches app URLs
]
diff --git a/frontend/src/views/modules/Breaches.js b/frontend/src/views/modules/Breaches.js
index 46daf8c99..68af94267 100644
--- a/frontend/src/views/modules/Breaches.js
+++ b/frontend/src/views/modules/Breaches.js
@@ -12,42 +12,94 @@ import {
CRow,
} from '@coreui/react'
import CIcon from '@coreui/icons-react'
-import { cilTrash, cilPlus } from '@coreui/icons'
+import { cilTrash, cilPlus, cilCloudDownload } from '@coreui/icons'
+import axios from 'axios'
const Breaches = () => {
const [email, setEmail] = useState('')
const [file, setFile] = useState(null)
const [accounts, setAccounts] = useState([{ email: '' }])
+ // Function to handle email change
const handleEmailChange = (e) => setEmail(e.target.value)
- const handleFileChange = (e) => {
- setFile(e.target.files[0])
- }
+ // Function to handle file change
+ const handleFileChange = (e) => setFile(e.target.files[0])
- const handleAccountChange = (index, event) => {
+ // Function to handle account email changes
+ const handleAccountChange = (index, e) => {
const newAccounts = [...accounts]
- newAccounts[index][event.target.name] = event.target.value
+ newAccounts[index].email = e.target.value
setAccounts(newAccounts)
}
+ // Function to add a new account input field
const handleAddAccount = () => {
setAccounts([...accounts, { email: '' }])
}
+ // Function to remove an account input field
const handleRemoveAccount = (index) => {
const newAccounts = [...accounts]
newAccounts.splice(index, 1)
setAccounts(newAccounts)
}
- const handleSubmit = (e) => {
+ // Function to handle the download of a CSV template
+ const handleDownloadTemplate = () => {
+ const templateData = 'Email\nexample@example.com'
+ const blob = new Blob([templateData], { type: 'text/csv;charset=utf-8;' })
+ const link = document.createElement('a')
+ link.href = URL.createObjectURL(blob)
+ link.download = 'email_template.csv'
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+ }
+
+ // Function to handle form submission for adding to database
+ const handleAddToDatabase = async (e) => {
+ e.preventDefault()
+ const formData = new FormData()
+
+ // Add single email to formData if provided
+ if (email) formData.append('email', email)
+
+ // Add file to formData if provided
+ if (file) formData.append('file', file)
+
+ // Add manually added accounts to formData
+ accounts.forEach((account, index) => {
+ if (account.email) formData.append(`emails[${index}]`, account.email)
+ })
+
+ // Retrieve the token from localStorage
+ const token = localStorage.getItem('token')
+
+ try {
+ await axios.post('http://localhost:8000/api/breaches/upload/', formData, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ 'Content-Type': 'multipart/form-data',
+ },
+ })
+ alert('Data submitted successfully')
+
+ // Reset form fields
+ setEmail('')
+ setFile(null)
+ setAccounts([{ email: '' }])
+ } catch (error) {
+ console.error('Error uploading data:', error)
+ alert('Error submitting data')
+ }
+ }
+
+ // Function for quick check (stubbed, not implemented)
+ const handleSubmitCheck = async (e) => {
e.preventDefault()
- // Integration with backend to handle the form data goes here
- console.log('Email:', email, 'File:', file, 'Accounts:', accounts)
- setEmail('')
- setFile(null)
- setAccounts([{ email: '' }])
+ // Implement the quick check functionality here
+ alert('Quick check functionality not implemented yet')
}
return (
@@ -56,7 +108,9 @@ const Breaches = () => {
<CCard>
<CCardHeader>Check for Breaches</CCardHeader>
<CCardBody>
- <CForm onSubmit={handleSubmit}>
+ <CForm>
+ {/* Quick Check Section */}
+ <CCardHeader>Quick Check</CCardHeader>
<CInputGroup className="mb-3">
<CInputGroupText>@</CInputGroupText>
<CFormInput
@@ -64,15 +118,11 @@ const Breaches = () => {
type="email"
value={email}
onChange={handleEmailChange}
- required
/>
</CInputGroup>
- <CInputGroup className="mb-3">
- <CFormInput type="file" id="fileInput" onChange={handleFileChange} accept=".csv" />
- </CInputGroup>
-
- <CCardHeader>Add Accounts Manually</CCardHeader>
+ {/* Add Monitored Emails Section */}
+ <CCardHeader>Add Monitored Emails</CCardHeader>
{accounts.map((account, index) => (
<CInputGroup key={index} className="mb-3">
<CFormInput
@@ -80,8 +130,7 @@ const Breaches = () => {
placeholder="Account Email"
name="email"
value={account.email}
- onChange={(event) => handleAccountChange(index, event)}
- required
+ onChange={(e) => handleAccountChange(index, e)}
/>
<CButton
type="button"
@@ -96,9 +145,21 @@ const Breaches = () => {
<CButton color="primary" className="mb-3" onClick={handleAddAccount}>
<CIcon icon={cilPlus} /> Add Another Account
</CButton>
- <div className="d-grid">
- <CButton type="submit" color="success">
- Submit
+
+ {/* File Upload Section */}
+ <CInputGroup className="mb-3">
+ <CFormInput type="file" id="fileInput" onChange={handleFileChange} accept=".csv" />
+ </CInputGroup>
+ <CButton color="secondary" className="mb-3" onClick={handleDownloadTemplate}>
+ <CIcon icon={cilCloudDownload} /> Download CSV Template
+ </CButton>
+
+ <div className="d-grid gap-2">
+ <CButton color="success" onClick={handleSubmitCheck}>
+ Check
+ </CButton>
+ <CButton color="info" onClick={handleAddToDatabase}>
+ Add to Database
</CButton>
</div>
</CForm>
--
GitLab