Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added jobfinder/__pycache__/app.cpython-311.pyc
Binary file not shown.
Binary file added jobfinder/__pycache__/app.cpython-312.pyc
Binary file not shown.
Binary file added jobfinder/__pycache__/db.cpython-311.pyc
Binary file not shown.
Binary file added jobfinder/__pycache__/models.cpython-311.pyc
Binary file not shown.
Binary file modified jobfinder/__pycache__/models.cpython-312.pyc
Binary file not shown.
120 changes: 109 additions & 11 deletions jobfinder/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from instance.config import Config
from db import db
from datetime import datetime
from sqlalchemy import text
import hashlib # Add this import

app = Flask(__name__)
app.config.from_object(Config)
Expand All @@ -18,15 +20,27 @@ def home():
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
email = request.form['email']
password = request.form['password']

user = User.query.filter_by(email=email).first()
if user and user.password == password:
session['current_user'] = user.id # Store user ID in session
username = request.form['username']
# Hash the input password for comparison
password = hashlib.md5(request.form['password'].encode()).hexdigest()

# More vulnerable SQL query implementation
conn = db.engine.raw_connection()
cursor = conn.cursor()
query = f"SELECT * FROM user WHERE username = '{username}' AND password = '{password}'"
cursor.execute(query)
user = cursor.fetchone()
conn.close()

if user:
# Vulnerable: No session timeout set
session['current_user'] = user[0] # Just stores user ID without any expiration
# Vulnerable: No session regeneration
# Vulnerable: No remember-me token
flash("Login successful!")
return redirect(url_for('main_page'))
else:
# Vulnerable: No login attempt counting
flash("Invalid login credentials")
return redirect(url_for('login'))

Expand All @@ -35,16 +49,24 @@ def login():
@app.route('/signup', methods=['GET', 'POST'])
def signup():
if request.method == 'POST':
username = request.form['username']
name = request.form['name']
email = request.form['email']
password = request.form['password']
password = hashlib.md5(request.form['password'].encode()).hexdigest()
favorite_color = request.form['favorite_color']

existing_user = User.query.filter_by(email=email).first()
existing_user = User.query.filter_by(username=username).first()
if existing_user:
flash('Email already exists!')
flash('Username already exists!')
return redirect(url_for('signup'))

new_user = User(name=name, email=email, password=password)
new_user = User(
username=username,
name=name,
email=email,
password=password,
favorite_color=favorite_color
)
db.session.add(new_user)
db.session.commit()

Expand Down Expand Up @@ -76,7 +98,8 @@ def main_page():

@app.route('/logout')
def logout():
session.pop('current_user', None) # Remove the user from the session
# Vulnerable: Doesn't invalidate on server side
session.pop('current_user', None)
return redirect(url_for('login'))

@app.route('/post_job')
Expand Down Expand Up @@ -110,6 +133,81 @@ def post_job():
flash('Job posted successfully!')
return redirect(url_for('main_page'))

@app.route('/delete_job/<int:job_id>', methods=['GET'])
def delete_job(job_id):
# Vulnerable: No authentication check!
job = Job.query.get(job_id)
if job:
db.session.delete(job)
db.session.commit()
flash('Job deleted successfully!')
return redirect(url_for('main_page'))

@app.route('/admin_panel')
def admin_panel():
# Vulnerable: No admin check!
users = User.query.all()
jobs = Job.query.all()
return render_template('admin.html', users=users, jobs=jobs)

@app.route('/delete_user/<int:user_id>')
def delete_user(user_id):
# Vulnerable: No authentication check!
user = User.query.get(user_id)
if user:
db.session.delete(user)
db.session.commit()
flash('User deleted successfully!')
return redirect(url_for('admin_panel'))

@app.route('/forgot_password', methods=['GET', 'POST'])
def forgot_password():
if request.method == 'POST':
username = request.form['username']
user = User.query.filter_by(username=username).first()

if user:
session['reset_user'] = user.username
return redirect(url_for('security_question'))
else:
flash('Username not found')

return render_template('forgot_password.html')

@app.route('/security_question', methods=['GET', 'POST'])
def security_question():
if 'reset_user' not in session:
return redirect(url_for('forgot_password'))

if request.method == 'POST':
color = request.form['color']
user = User.query.filter_by(username=session['reset_user']).first()

if user and color == user.favorite_color:
return redirect(url_for('reset_password'))
else:
flash('Incorrect answer')

return render_template('security_question.html')

@app.route('/reset_password', methods=['GET', 'POST'])
def reset_password():
if 'reset_user' not in session:
return redirect(url_for('forgot_password'))

if request.method == 'POST':
new_password = request.form['new_password']
user = User.query.filter_by(username=session['reset_user']).first()

if user:
user.password = hashlib.md5(new_password.encode()).hexdigest()
db.session.commit()
session.pop('reset_user', None)
flash('Password reset successful!')
return redirect(url_for('login'))

return render_template('reset_password.html')

if __name__ == '__main__':
with app.app_context():
db.create_all() # Ensure tables exist before running
Expand Down
16 changes: 15 additions & 1 deletion jobfinder/create_db.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
from app import app
from db import db
from models import User, Job
import hashlib

with app.app_context():
# Drop all tables and recreate them
db.drop_all()
db.create_all()

# Create a test user
test_user = User(
username='test',
name='Test User',
email='test@example.com',
password=hashlib.md5('test123'.encode()).hexdigest(),
favorite_color='blue'
)
db.session.add(test_user)
db.session.commit()

print("Database created successfully!")
print("Database created successfully with test user!")



Binary file not shown.
Binary file modified jobfinder/instance/__pycache__/config.cpython-312.pyc
Binary file not shown.
Binary file modified jobfinder/instance/site.db
Binary file not shown.
8 changes: 5 additions & 3 deletions jobfinder/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False) # Added name field
email = db.Column(db.String(120), unique=True, nullable=False)
username = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(120), nullable=False)
name = db.Column(db.String(120), nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
favorite_color = db.Column(db.String(20), nullable=False)

def __repr__(self):
return f'<User {self.email}>'
return f'<User {self.username}>'

class Job(db.Model): # This defines a "job" table
id = db.Column(db.Integer, primary_key=True)
Expand Down
45 changes: 45 additions & 0 deletions jobfinder/static/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -333,4 +333,49 @@ textarea:focus {
color: #166534;
}

/* Admin panel styles */
.admin-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}

.admin-table th,
.admin-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid var(--gray-light);
}

.admin-table th {
background-color: var(--primary);
color: white;
}

.delete-btn {
background-color: #ef4444;
color: white;
padding: 6px 12px;
border-radius: 4px;
text-decoration: none;
font-size: 14px;
}

.delete-btn:hover {
background-color: #dc2626;
}

.forgot-password {
display: block;
text-align: right;
font-size: 0.9rem;
color: var(--primary);
text-decoration: none;
margin-top: 0.5rem;
}

.forgot-password:hover {
color: var(--primary-dark);
}


57 changes: 57 additions & 0 deletions jobfinder/templates/admin.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Panel - JobFinder</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<div class="container">
<h1>Admin Panel</h1>

<h2>Users</h2>
<table class="admin-table">
<tr>
<th>ID</th>
<th>Username</th>
<th>Email</th>
<th>Actions</th>
</tr>
{% for user in users %}
<tr>
<td>{{ user.id }}</td>
<td>{{ user.username }}</td>
<td>{{ user.email }}</td>
<td>
<a href="{{ url_for('delete_user', user_id=user.id) }}" class="delete-btn">Delete</a>
</td>
</tr>
{% endfor %}
</table>

<h2>Jobs</h2>
<table class="admin-table">
<tr>
<th>ID</th>
<th>Title</th>
<th>Company</th>
<th>Posted By</th>
<th>Actions</th>
</tr>
{% for job in jobs %}
<tr>
<td>{{ job.id }}</td>
<td>{{ job.title }}</td>
<td>{{ job.company }}</td>
<td>{{ job.posted_by }}</td>
<td>
<a href="{{ url_for('delete_job', job_id=job.id) }}" class="delete-btn">Delete</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</body>
</html>
40 changes: 40 additions & 0 deletions jobfinder/templates/forgot_password.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Forgot Password - JobFinder</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body class="auth-page">
<div class="auth-container">
<div class="auth-box">
<div class="auth-header">
<h1>Forgot Password</h1>
<p>Enter your username to reset your password</p>
</div>

{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<div class="message">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}

<form action="{{ url_for('forgot_password') }}" method="POST" class="auth-form">
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" name="username" required>
</div>
<button type="submit" class="auth-button">Continue</button>
</form>

<div class="auth-footer">
<p><a href="{{ url_for('login') }}">Back to Login</a></p>
</div>
</div>
</div>
</body>
</html>
7 changes: 4 additions & 3 deletions jobfinder/templates/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@ <h1>JobFinder</h1>

<form action="{{ url_for('login') }}" method="POST" class="auth-form">
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" required
placeholder="Enter your email">
<label for="username">Username</label>
<input type="text" id="username" name="username" required
placeholder="Enter your username">
</div>

<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" required
placeholder="Enter your password">
<a href="{{ url_for('forgot_password') }}" class="forgot-password">Forgot Password?</a>
</div>

<button type="submit" class="auth-button">Login</button>
Expand Down
Loading