Fix Bug48: Implememt Password Recovery Using Security Questions #73

Open
boussouf wants to merge 3 commits from Bug48-Aya into Hui-Organize
13 changed files with 659 additions and 60 deletions

5
.gitignore vendored
View File

@ -1,2 +1,3 @@
.vscode
.DS_Store
venv/
__pycache__/
*.pyc

View File

@ -0,0 +1,87 @@
<?php
include 'NoDirectPhpAcess.php';
include 'Header.php';
include "get_mysql_credentials.php"; // Database credentials
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Connect to the database
$con = mysqli_connect("localhost", $mysql_username, $mysql_password, "lrr");
if (mysqli_connect_errno()) {
die("Connection failed: " . mysqli_connect_error());
}
// Check if user is logged in
if (isset($_SESSION['email'])) {
$email = $_SESSION['email'];
// Check if form is submitted
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Get the submitted answers
$answer1 = strtolower(trim($_POST['answer1']));
$answer2 = strtolower(trim($_POST['answer2']));
// Fetch correct answers from the database
$sql = "SELECT user_id, answer1, answer2 FROM password_recovery_security_questions WHERE email = '$email'";
$result = mysqli_query($con, $sql);
if ($row = mysqli_fetch_assoc($result)) {
// Compare submitted answers with stored answers
if (hash_equals($row['answer1'], $answer1) && hash_equals($row['answer2'], $answer2)) {
$_SESSION['user_id'] = $row['user_id'];
header("Location: ResetPassword.php"); // Redirect to password reset page
exit;
} else {
$error_message = "Incorrect answers. Please try again.";
}
} else {
echo '<div class="container mt-5"><div class="alert alert-warning" role="alert">No security questions found for this user.</div></div>';
}
}
// Fetch security questions from the database for display
$sql = "SELECT question1, question2 FROM password_recovery_security_questions WHERE email = '$email'";
$result = mysqli_query($con, $sql);
if ($row = mysqli_fetch_assoc($result)) {
// Display the questions in a form
echo'<br/><br/><br/>';
echo '<div class="container">';
echo '<div class="row">';
echo '<div class="col-md-5"></div>';
echo '<div class="col-md-5">';
if (isset($error_message)) {
echo '<div id="alertbad" class="alert alert-danger" role="alert">' . $error_message . '</div>'; // Display error message
}
//echo '<center>';
echo '<form action="" method="POST" class="">';
echo '<legend>Answer Your Security Questions.</legend>';
// Question 1
echo '<div class="mb-3">';
echo '<label class="form-label">' . htmlspecialchars($row['question1']) . '</label>';
echo '<input type="text" class="form-control" name="answer1" required>';
echo '</div>';
echo'<br/>';
// Question 2
echo '<div class="mb-3">';
echo '<label class="form-label">' . htmlspecialchars($row['question2']) . '</label>';
echo '<input type="text" class="form-control" name="answer2" required>';
echo '</div>';
echo '<button id="sub" type="submit" class="btn btn-primary">Submit Answers</button>';
echo '</form>';
echo '</div></div></div>'; // Close container
} else {
echo '<div class="container mt-5"><div class="alert alert-warning" role="alert">No security questions found for this user.</div></div>';
}
} else {
header("Location: RecoverPassword.php"); // Redirect if session data is missing
exit;
}
mysqli_close($con);
?>

View File

@ -1,3 +1,8 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
?>
<?php
session_start();
error_reporting(0);
@ -157,7 +162,7 @@ if (mysqli_connect_errno()) {
<?php
if (isset($_SESSION["user_fullname"])) {
if ($_SESSION['user_type'] == "Student" || $_SESSION['user_type'] == 'Lecturer') {
if ($_SESSION['user_type'] == "Student" || $_SESSION['user_type'] == 'Lecturer' || $_SESSION['user_type'] == 'TA') {
echo "<a class='nav-link' href='~\..\Courses.php'><i class='fa fa-book'></i> My courses </a>";
}
?>

View File

@ -15,11 +15,9 @@ include 'Header.php';
<form method="post" action="Script.php">
<legend>Recover password</legend>
<input type="hidden" name="form_recover_password" value="true"/>
Student number
<input type="text" name="sno" placeholder="Enter your student number" class="form-control" required="required" value="<?php echo htmlspecialchars($_SESSION['student_number']); ?>"> <br/>
Email
<input type="text" name="email" placeholder="Enter your email address" class="form-control" required="required" value="<?php echo htmlspecialchars($_SESSION['user_email']); ?>"> <br/>
<button type="submit" class="btn btn-primary">Recover</button>
<button id="rec" type="submit" class="btn btn-primary">Recover</button>
</form>
</div>
</div>

78
ResetPassword.php Normal file
View File

@ -0,0 +1,78 @@
<?php
require_once 'Header.php';
require_once 'NoDirectPhpAcess.php';
require_once "get_mysql_credentials.php";
ini_set('display_errors', 0);
error_reporting(E_ALL);
$con = mysqli_connect("localhost", $mysql_username, $mysql_password, "lrr");
if (mysqli_connect_errno()) {
error_log("Database connection failed: " . mysqli_connect_error());
die("An error occurred. Please try again later.");
}
// Check if user_id is set in the session
if (!isset($_SESSION['email'])) {
die("Session expired. Please log in again.");
}
$email = $_SESSION['email'];
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Handle password reset
if (isset($_POST['new_password']) && isset($_POST['confirm_password'])) {
$new_password = $_POST['new_password'];
$confirm_password = $_POST['confirm_password'];
if (!preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\d\s]).{8,}$/', $new_password)) {
echo '<div class="alert alert-danger">Password must be at least 8 characters long and include uppercase and lowercase letters, numbers, and special characters.</div>';
} elseif ($new_password !== $confirm_password) {
echo '<div class="alert alert-danger">Passwords do not match. Please try again.</div>';
} else {
$hashed_password = password_hash($new_password, PASSWORD_ARGON2ID);
$user_id = $_SESSION['user_id'];
$stmt = $con->prepare("UPDATE users_table SET Password = ? WHERE email = ? AND user_id = ?");
$stmt->bind_param("sss", $hashed_password, $email, $user_id);
if ($stmt->execute()) {
echo '<div class="alert alert-success">Password reset successfully. You can now log in with your new password.</div>';
unset($_SESSION['user_id']); // Clear user_id after successful password reset
header("Location: index.php");
} else {
error_log("Error updating password for user ID: $user_id");
echo '<div class="alert alert-danger">An error occurred. Please try again later.</div>';
}
$stmt->close();
}
}
}
// Display the reset password form
echo '
<br/><br/><br/>
<div class="container">
<div class="row">
<div class="col-md-5"></div>
<div class="col-md-5">
<form action="" method="POST" class="">
<legend>Reset Your Password</legend><br/>
New Password <label class="form-text">Must include uppercase and lowercase letters, digits and special characters.</label>
<input type="password" name="new_password" placeholder=" Enter New Password" class="form-control" required>
<br/>
Confirm New Password
<input type="password" name="confirm_password" placeholder="Confirm New Password" class="form-control" required>
<br/>
<button id="butt" type="submit" class="btn btn-primary">Reset Password</button>
</form>
</div></div></div>
<style>
.guideline { display: none;}
#newPassword:focus + .guideline {display: block;}
';
mysqli_close($con);
?>

View File

@ -177,7 +177,14 @@ if (!empty($_POST["form_signup"])) {
$_SESSION['user_fullname'] =$_SESSION['user_fullname_temp'];
if ($con->query($sql) === TRUE) {
header("Location: Courses.php");
// Get the newly inserted user's ID
$user_id = $con->insert_id;
//Set the user_id in the session
$_SESSION['user_id'] = $user_id;
//Redirect to SecurityQuestions.php
header("Location: SecurityQuestions.php");
} else {
echo "Something really bad (SQL insertion error) happened during sign up.";
}
@ -224,20 +231,50 @@ if (!empty($_POST["form_login"])) {
$_SESSION['user_type'] = $row['UserType'];
$_SESSION['user_fullname'] = $row['Full_Name'];
// Check if the user is a student and has not set up their password recovery yet
if ($_SESSION['user_type'] == "Student") {
header("Location: Courses.php");
// Query to check if the student has completed the password recovery setup
$recovery_result = mysqli_query($con, "SELECT * FROM password_recovery_security_questions WHERE Student_ID = '" . $row['Student_ID'] . "'");
if (mysqli_num_rows($recovery_result) == 0) {
// If the student has not set up password recovery, redirect to the setup page
header("Location: SecurityQuestions.php");
exit();
} else {
// If the student has set up password recovery, redirect to the Courses page
header("Location: Courses.php");
}
}
// Redirect other user types to their respective pages
if ($_SESSION['user_type'] == "Lecturer") {
header("Location: Courses.php");
$recovery_result = mysqli_query($con, "SELECT * FROM password_recovery_security_questions WHERE user_id = '" . $row['User_ID'] . "' AND user_type = 'Lecturer'");
if (mysqli_num_rows($recovery_result) == 0) {
header("Location: SecurityQuestions.php");
exit();
} else {
header("Location: Courses.php"); }
}
if ($_SESSION['user_type'] == "TA") {
header("Location: Courses.php");
$recovery_result = mysqli_query($con, "SELECT * FROM password_recovery_security_questions WHERE user_id = '" . $row['User_ID'] . "' AND user_type = 'TA'");
if (mysqli_num_rows($recovery_result) == 0) {
header("Location: SecurityQuestions.php");
exit();
} else {
header("Location: Courses.php"); }
}
if ($_SESSION['user_type'] == "Admin") {
header("Location: Admin.php");
$recovery_result = mysqli_query($con, "SELECT * FROM password_recovery_security_questions WHERE user_id = '" . $row['User_ID'] . "' AND user_type = 'Admin'");
if (mysqli_num_rows($recovery_result) == 0) {
header("Location: SecurityQuestions.php");
exit();
} else {
header("Location: Admin.php"); }
}
// report wrong pass if not correct
return;
@ -250,43 +287,79 @@ if (!empty($_POST["form_login"])) {
header("Location: index.php");
exit(); // Add this line to prevent further execution after redirect
}
// Add the following line to reset the session variable when needed
// Reset the session variable when needed
unset($_SESSION["failed_login_user"]);
}
}
}
// ################################ Recover Password #####################################
if (!empty($_POST["form_recover_password"])) {
$student_id = mysqli_real_escape_string($con, $_POST["sno"]);
$email = mysqli_real_escape_string($con, $_POST["email"]);
// validate student number
if (strlen($student_id) != 12 || is_numeric($student_id) == FALSE) {
$_SESSION["info_recover_password"] = "Invalid student number.";
header("Location: recover_password.php");
return;
}
// validate email
// Validate email
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$_SESSION["info_recover_password"] = "Invalid email address.";
// echo "Invalid email address.";
header("Location: recover_password.php");
header("Location: RecoverPassword.php");
return;
}
$result = mysqli_query($con, "SELECT * FROM users_table WHERE Email='$email' and Student_ID='$student_id'");
// Check if user exists in the database
$result = mysqli_query($con, "SELECT * FROM users_table WHERE Email='$email'");
if (mysqli_num_rows($result) == 0) {
$_SESSION["info_recover_password"] = "Email address is not recognized.";
header("Location: RecoverPassword.php");
} else {
// Store the student ID and email in the session
$_SESSION['email'] = $email;
header("Location: AnswerSecurityQuestions.php");
}
}
// ################################ RESET Password #####################################
if (!empty($_POST["form_reset_password"])) {
$password = mysqli_real_escape_string($con, $_POST["password"]);
$token = mysqli_real_escape_string($con, $_POST["token"]);
$email = mysqli_real_escape_string($con, $_POST["email"]);
$result = mysqli_query(
$con,
"SELECT * FROM Users_Table WHERE email='$email'"
);
if (mysqli_num_rows($result) == 0) {
$_SESSION["info_recover_password"] = "Email address is not recognised.";
$_SESSION["info_recover_password"] = "Identity not recognized. Try again or send an inquiry email message to lanhui at zjnu.edu.cn.";
header("Location: recover_password.php");
echo "invalid email";
return;
} else {
$result = mysqli_query($con, "DELETE FROM users_table WHERE Email='$email' and Student_ID='$student_id'");
header("Location: signup.php");
while ($row = mysqli_fetch_assoc($result)) {
$userid = $row['User_ID'];
$email = $row['Email'];
$id = $row['Student_ID'];
$user_token = $userid * $userid * $userid + $userid * 0.00343;
if ($user_token == $token) {
// Password Update
// Password Update
$hashed_password = hash('sha512', $password);
$sql = "UPDATE users_table set HashPassword='$hashed_password' where User_ID='$userid';";
if ($con->query($sql) === TRUE) {
error_reporting(0);
$_SESSION["info_login"] = " Password changed successfully , you can login now with your new password ";
header("Location: index.php");
} else {
echo "Error: " . $sql . "<br>" . $con->error;
}
} else {
echo "Invalid Token ";
}
}
}
}

139
SecurityQuestions.php Normal file
View File

@ -0,0 +1,139 @@
<?php
session_start();
error_reporting(0);
date_default_timezone_set('Asia/Shanghai');
include 'NoDirectPhpAcess.php';
include "get_mysql_credentials.php"; // Database credentials
error_reporting(E_ALL);
ini_set('display_errors', 1);
$con = mysqli_connect("localhost", $mysql_username, $mysql_password, "lrr");
if (mysqli_connect_errno()) {
die("Connection failed: " . mysqli_connect_error());
}
// Check if user_id is set in the session
if (!isset($_SESSION['user_id'])) {
echo '<div class="alert alert-danger" role="alert">Session expired. Please log in again.</div>';
exit(); // Stop script execution if user_id is not set
}
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Get the security questions and answers from the form
$question1 = mysqli_real_escape_string($con, $_POST['security_question1']);
$answer1 = strtolower(mysqli_real_escape_string($con, $_POST['security_answer1']));
$question2 = mysqli_real_escape_string($con, $_POST['security_question2']);
$answer2 = strtolower(mysqli_real_escape_string($con, $_POST['security_answer2']));
// Get the user ID and user type from the session
$user_id = $_SESSION['user_id']; // Use user_id from session
$user_type = $_SESSION['user_type']; //Get user type from session
$email = $_SESSION['user_email'];
$student_id = isset($_SESSION['user_student_id']) ? $_SESSION['user_student_id'] : NULL; //Handle student_id for students
// Prepare SQL statement
if($user_type == 'Student') {
$sql = "INSERT INTO password_recovery_security_questions (user_id,user_type, student_id, email, question1, answer1, question2, answer2)
VALUES ('$user_id', '$user_type', '$student_id', '$email', '$question1', '$answer1', '$question2', '$answer2')
ON DUPLICATE KEY UPDATE
question1='$question1',
answer1='$answer1',
question2='$question2',
answer2='$answer2'";
} else {
// For non-students (Lecturer, TA, etc.), exclude student_id
$sql = "INSERT INTO password_recovery_security_questions (user_id, user_type, email, question1, answer1, question2, answer2)
VALUES ('$user_id', '$user_type', '$email', '$question1', '$answer1', '$question2', '$answer2')
ON DUPLICATE KEY UPDATE
question1='$question1',
answer1='$answer1',
question2='$question2',
answer2='$answer2'";
}
// Execute the query and check for success
if (mysqli_query($con, $sql)) {
echo '<div id="alertgood" class="alert alert-success" role="alert">Password recovery details set successfully. Please remember your answers! Redirecting to Courses page...</div>';
echo '<script>';
echo ' setTimeout(function() {';
echo ' var userType = "'. $_SESSION['user_type'] . '";';
echo ' if (userType === "Admin") {';
echo ' window.location.href = "Admin.php";';
echo ' } else {';
echo ' window.location.href = "Courses.php";';
echo ' }';
echo ' }, 2000);';
echo '</script>';
} else {
echo '<div class="alert alert-danger" role="alert">Error: ' . mysqli_error($con) . '</div>';
}
}
mysqli_close($con);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Security Questions</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary" style="padding-left:180px;padding-right:150px;margin:auto;">
<div class="container-fluid">
<a class="navbar-brand" href="#"> <img src="logo.png" style="width:30px;height:30px;" alt="LRR Logo"> LRR </a>
</nav>
<br/><br/><br/>
<div class="container">
<div class="col-md-5"></div>
<form action="SecurityQuestions.php" method="POST">
<label> Set Password Recovery (Make sure you remember your answers) </label>
<div class="mb-3">
<br/>
<label for="security_question1" class="form-label">Select Security Question 1</label>
<select class="form-select" id="security_question1" name="security_question1" required>
<option value="">-- Select a question --</option>
<option value="What is the name of your first pet?">What is the name of your first pet?</option>
<option value="What is your mother's maiden name?">What is your mother's maiden name?</option>
<option value="What is the name of the town where you were born?">What is the name of the town where you were born?</option>
<option value="What was the name of your first best friend?">What was the name of your first best friend?</option>
<option value="What is your favorite book?">What is your favorite book?</option>
<option value="What was the make and model of your first car?">What was the make and model of your first car?</option>
<!-- Add more options if needed -->
</select>
</div>
<div class="mb-3">
<label for="security_answer1" class="form-label">Answer 1</label>
<input type="text" class="form-control" id="security_answer1" name="security_answer1" required>
</div>
<br/>
<div class="mb-3">
<label for="security_question2" class="form-label">Select Security Question 2</label>
<select class="form-select" id="security_question2" name="security_question2" required>
<option value="">-- Select a question --</option>
<option value="What was the name of your first school?">What was the name of your first school?</option>
<option value="What is your favorite movie?">What is your favorite movie?</option>
<option value="What was your childhood nickname?">What was your childhood nickname?</option>
<option value="What is the name of your favorite teacher?">What is the name of your favorite teacher?</option>
<option value="What street did you grow up on?">What street did you grow up on?</option>
<option value="What is your favorite food?">What is your favorite food?</option>
<!-- Add more options if needed -->
</select>
</div>
<div class="mb-3">
<label for="security_answer2" class="form-label">Answer 2</label>
<input type="text" class="form-control" id="security_answer2" name="security_answer2" required>
</div>
<br/>
<button id="submit_recovery" type="submit" class="btn btn-primary">Save Answers</button>
</form>
</div>
</body>
</html>

View File

@ -41,7 +41,7 @@ if (isset($_SESSION["user_fullname"])) {
<label class="form-text">Don't have an account yet?</label> <a href="signup.php" id="signup_link">Sign up</a>
<br>
<label class="form-text">Forget your password?</label> <a href="recover_password.php">Recover</a>
<label class="form-text">Forget your password?</label> <a id="goRecover" href="RecoverPassword.php">Recover</a>
<?php

View File

@ -259,7 +259,10 @@ INSERT INTO `students_data` (`ID`, `Student_ID`, `Passport_Number`) VALUES
(1, '201825800054', 'LJ7951632'),
(2, '201825800050', 'P00581929'),
(3, '201632120150', 'FN524516'),
(4, '202400000001', 'NA');
(4, '202400000001', 'NA'),
(5,'201932130101',''),
(6,'201920781742','');
-- --------------------------------------------------------
@ -269,7 +272,7 @@ INSERT INTO `students_data` (`ID`, `Student_ID`, `Passport_Number`) VALUES
--
CREATE TABLE `users_table` (
`User_ID` int(11) NOT NULL,
`User_ID` int(11) NOT NULL AUTO_INCREMENT,
`Email` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,
`Password` varchar(250) CHARACTER SET utf8 DEFAULT NULL,
`HashPassword` varchar(250) COLLATE utf8mb4_bin NOT NULL,
@ -277,7 +280,8 @@ CREATE TABLE `users_table` (
`UserType` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,
`Student_ID` varchar(500) COLLATE utf8mb4_bin DEFAULT NULL,
`Passport_Number` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,
`Status` varchar(30) COLLATE utf8mb4_bin NOT NULL DEFAULT 'Active'
`Status` varchar(30) COLLATE utf8mb4_bin NOT NULL DEFAULT 'Active',
PRIMARY KEY (`User_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
--
@ -294,8 +298,28 @@ INSERT INTO `users_table` (`User_ID`, `Email`, `Password`, `HashPassword`, `Full
(12, 'mehdi@qq.com', '123', '', 'El-mehdi Houzi', 'Student', '201825800054', 'LJ7951632', 'Active'),
(17, 'teecloudy@qq.com', '$2y$10$8WqSK7QI.3YCb2yoclqutOxyGxojncUvzhqLcE8zjlSvjBdcIQ18O', '', 'Ashly Tafadzwa Dhani', 'Student', '201632120150', NULL, 'Active'),
(18, 'ashly@qq.com', 'Testing2', '', 'Ashly 2 Testing', 'Student', '2016321201502', NULL, 'Active'),
(19, '11@11.11', 'dfdf', '760a8f4f392f1f6bc3ecb118365c6cd039b59fdce96122897d5157970d9c9c129bd73b3c402dbeedd8fe94d319df7bd7de0025c22839fec06631a025ec1e0e69', '11', 'Student', '11', '', 'Active');
(19, '11@11.11', 'dfdf', '760a8f4f392f1f6bc3ecb118365c6cd039b59fdce96122897d5157970d9c9c129bd73b3c402dbeedd8fe94d319df7bd7de0025c22839fec06631a025ec1e0e69', '11', 'Student', '11', '', 'Active'),
(20,'goodstd@qq.com','$2y$10$RXIjONOK.mw74pSxPrsnGuccQsFq4O4.e71vaxfGHHhtzHREtfqkG','','Good Std','Student','201932130101',NULL,'Active'),(21,'goodstd2@qq.com','$2y$10$kmqrGuZd7hCiiaHFDQr2vObpD7BgEnCKlgQ/EcLHYnsQenMbNKcHy','','Good Std2','Student','201920781742',NULL,'Active');
CREATE TABLE `password_recovery_security_questions` (
`user_id` int NOT NULL,
`user_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`student_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
`email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
`question1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`answer1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`question2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`answer2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`user_id`),
CONSTRAINT `password_recovery_security_questions_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users_table` (`User_ID`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
INSERT INTO `password_recovery_security_questions` VALUES
(3,'Admin',NULL,'admin@qq.com','What is the name of your first pet?','mimi','What was the name of your first school?','zjnu'),
(7,'Lecturer',NULL,'peter@qq.com','What was the name of your first best friend?','chen','What is your favorite food?','hotpot'),
(8,'Lecturer',NULL,'lanhui@qq.com','What is the name of the town where you were born?','jinhua','What is your favorite movie?','titanic'),
(9,'Student','201825800050','mohamed@qq.com','What was the make and model of your first car?','audi','What is the name of your favorite teacher?','chen'),
(21,'Student','201920781742','goodstd2@qq.com','What is the name of the town where you were born?','wenzhou','What is your favorite food?','hotpot');
--
-- Indexes for dumped tables
--
@ -349,12 +373,6 @@ ALTER TABLE `lab_report_submissions`
ALTER TABLE `students_data`
ADD PRIMARY KEY (`ID`);
--
-- Indexes for table `users_table`
--
ALTER TABLE `users_table`
ADD PRIMARY KEY (`User_ID`);
--
-- AUTO_INCREMENT for dumped tables
--
@ -412,12 +430,7 @@ ALTER TABLE `students_data`
--
ALTER TABLE courses_table
MODIFY Course_Name varchar(500);
--
-- AUTO_INCREMENT for table `users_table`
--
ALTER TABLE `users_table`
MODIFY `User_ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=20;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;

View File

@ -0,0 +1,37 @@
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException, UnexpectedAlertPresentException
def login(driver, url, username, password):
try:
driver.get(url)
# Fill in the login form
user_input = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "user_name"))
)
user_input.send_keys(username)
password_input = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "user_password"))
)
password_input.send_keys(password)
# Click the login button
login_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "login_btn"))
)
login_button.click()
except (NoSuchElementException, UnexpectedAlertPresentException) as e:
return f"Error: {str(e)}"
def logout(driver):
logout_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable(
(By.XPATH, "//a[contains(@class, 'nav-link') and contains(@href, 'logout.php')]")
)
)
logout_button.click()

View File

@ -0,0 +1,156 @@
from helper import login, logout
import time
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
def test_attempt_recovery_with_unanswered_security_questions(driver, url, restore_database):
# Student goodstd@qq.com with no answered questions
driver.get(url)
driver.maximize_window()
elem = driver.find_element(By.ID, 'goRecover')
elem.click()
elem = driver.find_element(By.NAME, 'email')
elem.send_keys("goodstd@qq.com")
elem = driver.find_element(By.ID, 'rec')
elem.click()
wait = WebDriverWait(driver, 10)
alert_elem = wait.until(EC.presence_of_element_located((By.CLASS_NAME, "alert-warning")))
assert "no security questions found for this user." in alert_elem.text.lower()
driver.quit()
def test_set_security_questions(driver, url, restore_database):
# Student goodstd@qq.com logs in
driver.get(url)
driver.maximize_window()
login(driver, url, 'goodstd@qq.com', '[123Abc]')
question1 = driver.find_element(By.ID, 'security_question1')
question2 = driver.find_element(By.ID, 'security_question2')
select_question1 = Select(question1)
select_question1.select_by_index(1)
select_question2 = Select(question2)
select_question2.select_by_index(2)
answer1 = driver.find_element(By.ID, 'security_answer1')
answer1.send_keys("mImI")
answer2 = driver.find_element(By.ID, 'security_answer2')
answer2.send_keys("TitaNic")
submit_button = driver.find_element(By.ID, 'submit_recovery')
submit_button.click()
# Assertion: Check if password recovery confirmation or success message appears
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, 'alertgood')))
recovery_success = driver.find_element(By.ID, 'alertgood')
assert recovery_success.is_displayed(), "Password recovery failed or confirmation message not displayed."
logout(driver)
#Log in Student account
login(driver, url, 'goodstd@qq.com', '[123Abc]')
elems = driver.find_elements(By.CLASS_NAME, 'nav-link')
assert 'Student ID' in elems[0].text
assert 'Good Std' in elems[0].text
driver.quit()
def test_password_recover_wrong_answers(driver, url, restore_database):
# Student goodstd2@qq.com recover password --> wrong answers
driver.get(url)
driver.maximize_window()
elem = driver.find_element(By.ID, 'goRecover')
elem.click()
elem = driver.find_element(By.NAME, 'email')
elem.send_keys("goodstd2@qq.com")
elem = driver.find_element(By.ID, 'rec')
elem.click()
elem = driver.find_element(By.NAME, 'answer1')
elem.send_keys("wrong")
elem = driver.find_element(By.NAME, 'answer2')
elem.send_keys("wrong")
elem = driver.find_element(By.ID, 'sub')
elem.click()
driver.quit()
def test_recover_password_with_weak_password(driver, url, restore_database):
driver.get(url)
driver.maximize_window()
elem = driver.find_element(By.ID, 'goRecover')
elem.click()
elem = driver.find_element(By.NAME, 'email')
elem.send_keys("goodstd2@qq.com")
elem = driver.find_element(By.ID, 'rec')
elem.click()
elem = driver.find_element(By.NAME, 'answer1')
elem.send_keys("Wenzhou")
elem = driver.find_element(By.NAME, 'answer2')
elem.send_keys("HotPot")
elem = driver.find_element(By.ID, 'sub')
elem.click()
elem = driver.find_element(By.NAME, 'new_password')
elem.send_keys("123")
elem = driver.find_element(By.NAME, 'confirm_password')
elem.send_keys("123")
elem = driver.find_element(By.ID, "butt")
elem.click()
wait = WebDriverWait(driver, 10)
alert_elem = wait.until(EC.presence_of_element_located((By.CLASS_NAME, "alert-danger")))
assert "password must be at least 8 characters long and include uppercase and lowercase letters, numbers, and special characters." in alert_elem.text.lower()
driver.quit()
def test_recover_password_successfully(driver, url, restore_database):
# Student goodstd2@qq.com recover password ---> correct answers
driver.get(url)
driver.maximize_window()
elem = driver.find_element(By.ID, 'goRecover')
elem.click()
elem = driver.find_element(By.NAME, 'email')
elem.send_keys("goodstd2@qq.com")
elem = driver.find_element(By.ID, 'rec')
elem.click()
elem = driver.find_element(By.NAME, 'answer1')
elem.send_keys("wenzhou")
elem = driver.find_element(By.NAME, 'answer2')
elem.send_keys("hotpot")
elem = driver.find_element(By.ID, 'sub')
elem.click()
elem = driver.find_element(By.NAME, 'new_password')
elem.send_keys("123Abc!!")
elem = driver.find_element(By.NAME, 'confirm_password')
elem.send_keys("123Abc!!")
elem = driver.find_element(By.ID, "butt")
elem.click()
#Log in Student account
login(driver, url, 'goodstd2@qq.com', '123Abc!!')
elems = driver.find_elements(By.CLASS_NAME, 'nav-link')
assert 'Student ID' in elems[0].text
assert 'Good Std2' in elems[0].text
driver.quit()
def test_recovery_invalid_user_cannot_recover(driver, url, restore_database):
# Unrecognizable user cannot recover
driver.get(url)
driver.maximize_window()
elem = driver.find_element(By.ID, 'goRecover')
elem.click()
elem = driver.find_element(By.NAME, 'email')
elem.send_keys("goodstd3@qq.com")
elem = driver.find_element(By.ID, 'rec')
elem.click()
wait = WebDriverWait(driver, 10)
alert_elem = wait.until(EC.presence_of_element_located((By.CLASS_NAME, "alert-danger")))
assert "email address is not recognized." in alert_elem.text.lower()
driver.quit()

View File

@ -30,9 +30,12 @@ def test_admin_can_create_lecturer_account(driver, url, admin_username, admin_pa
# Log in Lecturer account
login(driver, url, 'mrlan@qq.com', '123Abc!!')
elems = driver.find_elements(By.CLASS_NAME, 'nav-link')
assert '(Lecturer)' in elems[0].text
assert 'Mr Lan' in elems[0].text
#elems = driver.find_elements(By.CLASS_NAME, 'nav-link')
#assert '(Lecturer)' in elems[0].text
#assert 'Mr Lan' in elems[0].text
wait = WebDriverWait(driver, 10)
wait.until(EC.url_contains('SecurityQuestions.php'))
driver.quit()
@ -73,9 +76,9 @@ def test_lecturer_can_post_assignment(driver, url, restore_database):
)
elem.click()
elem = driver.find_element(By.NAME, 'deadlinedate')
elem.send_keys('002024/12/30')
elem.send_keys('05/30/2025')
elem = driver.find_element(By.NAME, 'deadlinetime')
elem.send_keys('23:59')
elem.send_keys('11:53PM')
elem = driver.find_element(By.NAME, 'title')
elem.send_keys('Take-home quiz 1')
elem = driver.find_element(By.NAME, 'instructions')
@ -91,7 +94,7 @@ def test_lecturer_can_post_assignment(driver, url, restore_database):
elem = driver.find_element(By.CLASS_NAME, 'card-title')
assert 'Take-home quiz 1 (10 Marks, Individual)' in elem.text
elem = driver.find_element(By.CLASS_NAME, 'text-muted')
assert 'Deadline: 2024-12-30' in elem.text
assert 'Deadline: 2025-05-30' in elem.text
driver.quit()
@ -157,13 +160,15 @@ def test_student_with_valid_student_number_can_sign_up(driver, url, restore_data
elem.send_keys('[123Abc]')
elem = driver.find_element(By.ID, 'signup_btn')
elem.click()
logout(driver)
driver.get(url + 'logout.php')
# Log in Student account
login(driver, url, '202400000001', '[123Abc]')
elems = driver.find_elements(By.CLASS_NAME, 'nav-link')
assert 'Student ID' in elems[0].text
assert 'Good Student' in elems[0].text
#elems = driver.find_elements(By.CLASS_NAME, 'nav-link')
#assert 'Student ID' in elems[0].text
#assert 'Good Student' in elems[0].text
wait = WebDriverWait(driver, 10)
wait.until(EC.url_contains('SecurityQuestions.php'))
driver.quit()
@ -245,6 +250,7 @@ def test_student_can_join_course(driver, url, restore_database):
assert 'CSC1111' in elems[0].text
assert 'Project Management' in elems[0].text
assert 'Joined' in elems[0].text
driver.quit()
def test_student_can_submit_assignment(driver, url, restore_database):
@ -264,7 +270,7 @@ def test_student_can_submit_assignment(driver, url, restore_database):
elem = driver.find_element(By.NAME, 'title')
elem.send_keys('Assignment submission from Mohamed')
elem = driver.find_element(By.NAME, 'attachment1')
elem.send_keys('/home/mrlan/Downloads/test/SeleniumHui/helper.py') # attach a file
elem.send_keys('/var/www/html/LRR/test/SeleniumHui/helper.py') # attach a file
elem = driver.find_element(By.XPATH, '//form/button')
elem.click()
@ -277,6 +283,8 @@ def test_student_can_submit_assignment(driver, url, restore_database):
assert 'Reading 2 (6 Marks)' in elem.text
assert 'SUBMITTED' in elem.text
assert 'helper.py' in elem.text
driver.quit()
def test_student_can_request_remarking(driver, url, restore_database):
@ -302,6 +310,8 @@ def test_student_can_request_remarking(driver, url, restore_database):
elem = driver.find_element(By.XPATH, '//div[@id="menu4"]/div/div/p/span')
assert 'Remarking request sent' == elem.text
driver.quit()
def test_lecturer_can_mark_assignment(driver, url, restore_database):
@ -333,6 +343,8 @@ def test_lecturer_can_mark_assignment(driver, url, restore_database):
elems[1].click()
elem = driver.find_element(By.XPATH, "//div[@id='menu2']/div/b")
assert 'Reading 1 submission' in elem.text
driver.quit()
def test_lecturer_cannot_see_tas_not_from_his_course(driver, url, restore_database):

View File

@ -11,7 +11,7 @@ def restore_database():
Benefit: we can reproduce the same test result.
'''
PASSWORD = 'p-@va9' # root password
PASSWORD = 'root' # root password
DB_NAME = 'lrr' # database name used for LRR
# commands used to import data to DB_NAME