diff --git a/backend/db.sqlite3 b/backend/db.sqlite3 index 2594849a915f05ef5472c2475ef5937c13cae8d9..219bc0559ba613849eb8340c804a76b59e2e16c2 100644 Binary files a/backend/db.sqlite3 and b/backend/db.sqlite3 differ diff --git a/backend/requirements.txt b/backend/requirements.txt index c8b177103be63220263ac01f39bab6a89a42645d..d15ecff9f18c0db817c7addbcf9f8c7b86cecda4 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -8,4 +8,6 @@ pytz==2023.3.post1 sqlparse==0.4.4 typing_extensions==4.9.0 tzdata==2023.4 -requests==2.26.0 \ No newline at end of file +requests==2.26.0 +django-truncate +shodan \ No newline at end of file diff --git a/frontend/src/components/AppFooter.js b/frontend/src/components/AppFooter.js index c853f5b87e51153e32dcb5d8e7445d5ea51422fd..9c4c680abb4ddfc91a485d84aebe6e0f55a000de 100644 --- a/frontend/src/components/AppFooter.js +++ b/frontend/src/components/AppFooter.js @@ -5,16 +5,7 @@ const AppFooter = () => { return ( <CFooter> <div> - <a href="https://coreui.io" target="_blank" rel="noopener noreferrer"> - CoreUI - </a> - <span className="ms-1">© 2023 creativeLabs.</span> - </div> - <div className="ms-auto"> - <span className="me-1">Powered by</span> - <a href="https://coreui.io/react" target="_blank" rel="noopener noreferrer"> - CoreUI React Admin & Dashboard Template - </a> + <span className="ms-1">© 2024 Data Guardian.</span> </div> </CFooter> ) diff --git a/frontend/src/index.js b/frontend/src/index.js index d19a3bcd3e9ed9f42132ba6de1e49b616ada1ab7..17c75829527d4181860665cd5de177015679c5e6 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -6,6 +6,19 @@ import App from './App' import reportWebVitals from './reportWebVitals' import { Provider } from 'react-redux' import store from './store' +import axios from 'axios' + +// Setting up Axios Interceptors +axios.interceptors.response.use( + (response) => response, + (error) => { + if (error.response && error.response.status === 401) { + // Redirect to the login page + window.location.href = '/login' + } + return Promise.reject(error) + }, +) createRoot(document.getElementById('root')).render( <Provider store={store}> diff --git a/frontend/src/views/emails/BreachesEmails.js b/frontend/src/views/emails/BreachesEmails.js index 738a7f8778bf4d8de4c54c2ec50674d04f6faaab..11eff4d26009931c206db2d22b8606774b0d8281 100644 --- a/frontend/src/views/emails/BreachesEmails.js +++ b/frontend/src/views/emails/BreachesEmails.js @@ -1,9 +1,10 @@ // BreachesPasswords.js import React, { useState, useEffect } from 'react' +import { useNavigate } from 'react-router-dom' const BreachesEmails = () => { const [breachResults, setBreachResults] = useState([]) - + const navigate = useNavigate() useEffect(() => { fetchBreachResultsData() }, []) @@ -19,6 +20,7 @@ const BreachesEmails = () => { if (response.status === 401) { console.error('Unauthorized access to the API') + navigate('/login') return } diff --git a/frontend/src/views/pages/login/Login.js b/frontend/src/views/pages/login/Login.js index ad2d38464af9839a85e9baf0c2e9e71d75a470d9..8d08d612263c87ee241beea5430ea639acd79f6c 100644 --- a/frontend/src/views/pages/login/Login.js +++ b/frontend/src/views/pages/login/Login.js @@ -1,6 +1,5 @@ import React, { useState } from 'react' -import { Link } from 'react-router-dom' -import { useNavigate } from 'react-router-dom' +import { Link, useNavigate } from 'react-router-dom' import axios from 'axios' import { CButton, @@ -21,6 +20,7 @@ import { logo } from '../../../assets/brand/logo' const Login = () => { const [loginData, setLoginData] = useState({ username: '', password: '' }) + const [error, setError] = useState('') // State to hold login error const navigate = useNavigate() const handleChange = (e) => { @@ -29,15 +29,18 @@ const Login = () => { const handleSubmit = async (e) => { e.preventDefault() + setError('') // Clear previous errors try { const response = await axios.post('http://localhost:8000/api/auth/login/', loginData) localStorage.setItem('token', response.data.access) // Save token console.log('Login successful:', response.data) - // Handle successful login (redirect to dashboard, etc.) navigate('/dashboard') } catch (error) { - console.error('Login error:', error.response) - // Handle login errors (show error message, etc.) + if (error.response && error.response.status === 401) { + setError('Invalid username or password.') + } else { + setError('Something went wrong. Please try again.') + } } } @@ -53,6 +56,7 @@ const Login = () => { <CIcon className="sidebar-brand-full" icon={logo} height={35} /> <h1>Welcome back!</h1> <p className="text-medium-emphasis">Sign In to your account</p> + {error && <p className="text-danger">{error}</p>} {/* Display login error */} <CInputGroup className="mb-3"> <CInputGroupText> <CIcon icon={cilUser} /> diff --git a/frontend/src/views/pages/register/Register.js b/frontend/src/views/pages/register/Register.js index 26f07f6af432f0fb8931fd080e7396f4580689fa..8a6fe6105987bd11814d0f0e880f56cc9e750348 100644 --- a/frontend/src/views/pages/register/Register.js +++ b/frontend/src/views/pages/register/Register.js @@ -23,6 +23,7 @@ const Register = () => { password: '', confirmPassword: '', }) + const [error, setError] = useState('') const navigate = useNavigate() const handleChange = (e) => { @@ -31,8 +32,15 @@ const Register = () => { const handleSubmit = async (e) => { e.preventDefault() + setError('') // Clear previous errors + if (!isPasswordComplex(userData.password)) { + setError( + 'Password must be at least 8 characters long, include uppercase and lowercase letters, a number, and a special character.', + ) + return + } if (userData.password !== userData.confirmPassword) { - alert('Passwords do not match') + setError('Passwords do not match.') return } try { @@ -42,14 +50,18 @@ const Register = () => { password: userData.password, }) console.log(response.data) - // Handle success - redirect or clear form navigate('/login') } catch (error) { console.error('Registration error:', error.response) - // Handle errors - show error message + setError('Failed to register. Please try again.') } } + function isPasswordComplex(password) { + const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/ + return regex.test(password) + } + return ( <div className="bg-light min-vh-100 d-flex flex-row align-items-center"> <CContainer> @@ -60,6 +72,7 @@ const Register = () => { <CForm onSubmit={handleSubmit}> <h1>Register</h1> <p className="text-medium-emphasis">Create your account</p> + {error && <p className="text-danger">{error}</p>} {/* Display error message */} <CInputGroup className="mb-3"> <CInputGroupText> <CIcon icon={cilUser} /> diff --git a/frontend/src/views/passwords/BreachesPasswords.js b/frontend/src/views/passwords/BreachesPasswords.js index ce07cf20a5fa8934ed7a4f23e942df61d2bb9292..a74ee3c063f117d937c1e728769ddc2faac6e60a 100644 --- a/frontend/src/views/passwords/BreachesPasswords.js +++ b/frontend/src/views/passwords/BreachesPasswords.js @@ -1,9 +1,10 @@ // BreachesPasswords.js import React, { useState, useEffect } from 'react' +import { useNavigate } from 'react-router-dom' const BreachesPasswords = () => { const [breachResults, setBreachResults] = useState([]) - + const navigate = useNavigate() useEffect(() => { fetchBreachResultsData() }, []) @@ -11,6 +12,7 @@ const BreachesPasswords = () => { const fetchBreachResultsData = async () => { try { const token = localStorage.getItem('token') + const response = await fetch('http://localhost:8000/api/breaches/passwords/details/', { headers: { Authorization: `Bearer ${token}`, @@ -19,6 +21,7 @@ const BreachesPasswords = () => { if (response.status === 401) { console.error('Unauthorized access to the API') + navigate('/login') return } diff --git a/frontend/src/views/widgets/WidgetsDropdown.js b/frontend/src/views/widgets/WidgetsDropdown.js index 66e7a5cc026ecb5c19a73a5a941a54c82d621d56..f79b8c66f6523f8696704ccfd74673dabb05e205 100644 --- a/frontend/src/views/widgets/WidgetsDropdown.js +++ b/frontend/src/views/widgets/WidgetsDropdown.js @@ -13,10 +13,10 @@ import CIcon from '@coreui/icons-react' import { cilArrowBottom, cilArrowTop, cilOptions } from '@coreui/icons' import { countUniqueEmails } from '../emails/BreachesEmails' import React, { useState, useEffect } from 'react' - +import { useNavigate } from 'react-router-dom' const WidgetsDropdown = () => { const [breachResults, setBreachResults] = useState([]) - + const navigate = useNavigate() useEffect(() => { // Fetch or set your breachResults data // Example: Fetching data using an async function @@ -31,6 +31,7 @@ const WidgetsDropdown = () => { if (response.status === 401) { console.error('Unauthorized access to the API') + navigate('/login') return }