Skip to content

Fixes #9: Hash Passwords #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
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
63 changes: 55 additions & 8 deletions ComplaintBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,22 @@
#include <fstream>
#include <sstream>
#include <bits/stdc++.h>
#include <openssl/sha.h>

using namespace std;

string hashPassword(const string& password) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256((const unsigned char*)password.c_str(), password.size(), hash);

stringstream ss;
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
ss << hex << setw(2) << setfill('0') << (int)hash[i];

return ss.str();
}


ComplaintBox::ComplaintBox() {
sqlite3_open("complaints.db", &db);
createTables();
Expand Down Expand Up @@ -51,7 +64,8 @@ void ComplaintBox::registerUser(bool isAdmin) {
cin >> pass;

string table = isAdmin ? "adminusers" : "users";
string sql = "INSERT INTO " + table + " (username, password) VALUES ('" + uname + "', '" + pass + "');";
string hashedPass = hashPassword(pass);
string sql = "INSERT INTO " + table + " (username, password) VALUES ('" + uname + "', '" + hashedPass + "');";

if (sqlite3_exec(db, sql.c_str(), 0, 0, &errMsg) != SQLITE_OK) {
cout << RED << "Error: " << errMsg << RESET << endl;
Expand All @@ -69,7 +83,9 @@ bool ComplaintBox::loginUser(bool isAdmin) {
cin >> pass;

string table = isAdmin ? "adminusers" : "users";
string sql = "SELECT * FROM " + table + " WHERE username = '" + uname + "' AND password = '" + pass + "';";
string hashedPass = hashPassword(pass);
string sql = "SELECT * FROM " + table + " WHERE username = '" + uname + "' AND password = '" + hashedPass + "';";

bool success = false;

sqlite3_exec(db, sql.c_str(), [](void *successPtr, int, char **, char **) -> int {
Expand All @@ -79,13 +95,15 @@ bool ComplaintBox::loginUser(bool isAdmin) {

if (success) {
cout << GREEN << "Login successful!\n" << RESET;
admin_logged_in = isAdmin;
return true;
} else {
cout << RED << "Invalid credentials!\n" << RESET;
return false;
}
}


void ComplaintBox::fileComplaint() {
string category, subCategory, message;
cout << YELLOW << "Enter category: " << RESET;
Expand All @@ -96,12 +114,14 @@ void ComplaintBox::fileComplaint() {
cout << YELLOW << "Enter complaint message: " << RESET;
getline(cin, message);

string sql = "INSERT INTO complaints (category, subCategory, message) VALUES ('" + category + "', '" + subCategory + "', '" + message + "');";
string sql = "INSERT INTO complaints (category, subCategory, message, status) VALUES ('"
+ category + "', '" + subCategory + "', '" + message + "', 'Pending');";

if (sqlite3_exec(db, sql.c_str(), 0, 0, &errMsg) != SQLITE_OK) {
cout << RED << "Error: " << errMsg << RESET << endl;
sqlite3_free(errMsg);
} else {
cout << BOLDGREEN << "Complaint filed successfully!\n" << RESET;
cout << BOLDGREEN << "Complaint filed successfully with status 'Pending'!\n" << RESET;
}
}

Expand All @@ -112,8 +132,8 @@ void ComplaintBox::exportComplaintsToCSV() {
return;
}

file << "complaint_id,category,subCategory,message\n";
string sql = "SELECT complaint_id, category, subCategory, message FROM complaints;";
file << "complaint_id,category,subCategory,message,status\n";
string sql = "SELECT complaint_id, category, subCategory, message, status FROM complaints;";
auto callback = [](void *data, int argc, char **argv, char **colName) -> int {
ofstream *f = static_cast<ofstream *>(data);
for (int i = 0; i < argc; i++) {
Expand All @@ -138,10 +158,11 @@ void ComplaintBox::searchComplaints() {
cin.ignore();
getline(cin, keyword);

string sql = "SELECT complaint_id, category, subCategory, message FROM complaints "
string sql = "SELECT complaint_id, category, subCategory, message, status FROM complaints "
"WHERE category LIKE '%" + keyword + "%' OR "
"subCategory LIKE '%" + keyword + "%' OR "
"message LIKE '%" + keyword + "%';";
"message LIKE '%" + keyword + "%' OR "
"status LIKE '%" + keyword + "%';";

cout << CYAN << "\nSearch Results:\n" << RESET;
auto callback = [](void *data, int argc, char **argv, char **colName) -> int {
Expand All @@ -157,3 +178,29 @@ void ComplaintBox::searchComplaints() {
sqlite3_free(errMsg);
}
}


void ComplaintBox::updateComplaintStatus(int complaint_id, const std::string& new_status) {
if (!admin_logged_in) {
cout << RED << "Only admins can update complaint status.\n" << RESET;
return;
}

sqlite3_stmt* stmt;
string sql = "UPDATE complaints SET status = ? WHERE complaint_id = ?";

if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, new_status.c_str(), -1, SQLITE_STATIC);
sqlite3_bind_int(stmt, 2, complaint_id);

if (sqlite3_step(stmt) == SQLITE_DONE) {
cout << GREEN << "Status updated successfully.\n" << RESET;
} else {
cerr << RED << "Failed to update status.\n" << RESET;
}
} else {
cerr << RED << "SQL Prepare Failed: " << sqlite3_errmsg(db) << "\n" << RESET;
}

sqlite3_finalize(stmt);
}
3 changes: 3 additions & 0 deletions ComplaintBox.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ class ComplaintBox {
void fileComplaint();
void exportComplaintsToCSV();
void searchComplaints();
void updateComplaintStatus(int complaint_id, const string& new_status);
bool isAdminLoggedIn() const { return admin_logged_in; }

private:
sqlite3 *db;
char *errMsg;
bool admin_logged_in = false;
void createTables();
};

Expand Down
9 changes: 5 additions & 4 deletions complaints_export.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
complaint_id,category,subCategory,message
1,Infrastructural,Hostel,Washrooms are not being regularly cleaned.
2,Management,College Events,Admin paisa kha gaya bc
3,Infrastructure,Hostel,MMC change karo mc
complaint_id,category,subCategory,message,status
1,Infrastructural,Hostel,Washrooms are not being regularly cleaned.,Pending
2,Management,College Events,Admin paisa kha gaya bc,Resolved
3,Infrastructure,Hostel,MMC change karo mc,Pending
4,College,Clasroom,ACs need to be installed,Pending
119 changes: 53 additions & 66 deletions main.cpp
Original file line number Diff line number Diff line change
@@ -1,87 +1,74 @@
// g++ main.cpp ComplaintBox.cpp -lssl -lcrypto -lsqlite3 -o complaintbox

#include <bits/stdc++.h>
#include "ComplaintBox.h"
using namespace std;

int main() {
ComplaintBox cb;
string choice;
int choiceNum = 0;
int choice = 0;

do {
cout << BOLDVIOLET << "\n==== Complaint Box Menu ====\n" << RESET;
cout << CYAN << "1. Register User\n"
cout << CYAN
<< "1. Register User\n"
<< "2. Register Admin\n"
<< "3. User Login\n"
<< "4. Admin Login\n"
<< "5. File Complaint\n"
<< "6. Export Complaints to CSV\n"
<< "7. Search Complaints\n"
<< "8. Exit\n" << RESET;

<< "8. Update Complaint Status (Admin Only)\n"
<< "9. Exit\n"
<< RESET;

cout << WHITE << "Choice: " << RESET;
cin >> choice;

// <<<<<<< Fix/crash-main-menu
try {
choiceNum = stoi(choice);
switch (choiceNum)
{
case 1:
cb.registerUser();
break;
case 2:
cb.registerUser(true);
break;
case 3:
cb.loginUser();
break;
case 4:
cb.loginUser(true);
break;
case 5:
cb.fileComplaint();
break;
case 6:
cout << "Exiting..." << endl;
break;
default:
cout << "Invalid choice!\n";
switch (choice) {
case 1:
cb.registerUser();
break;
case 2:
cb.registerUser(true);
break;
case 3:
cb.loginUser();
break;
case 4:
cb.loginUser(true);
break;
case 5:
cb.fileComplaint();
break;
case 6:
cb.exportComplaintsToCSV();
break;
case 7:
cb.searchComplaints();
break;
case 8:
if (!cb.isAdminLoggedIn()) {
cout << RED << "Only admins can update complaint status. Please login as admin first.\n" << RESET;
break;
} else {
int id;
string status;
cout << YELLOW << "Enter Complaint ID to update: " << RESET;
cin >> id;
cin.ignore();
cout << YELLOW << "Enter new status (Pending/In Progress/Resolved): " << RESET;
getline(cin, status);
cb.updateComplaintStatus(id, status);
break;
}
case 9:
cout << BOLDGREEN << "Exiting..." << RESET << endl;
break;
default:
cout << BOLDRED << "Invalid choice!\n" << RESET;
}
} catch (exception& e) { // stoi throw an exception when input is non-numeric string
cout << "Invalid input! Please enter a number."<<endl;
}
}while (choiceNum != 6);
// =======
// switch (choice) {
// case 1:
// cb.registerUser();
// break;
// case 2:
// cb.registerUser(true);
// break;
// case 3:
// cb.loginUser();
// break;
// case 4:
// cb.loginUser(true);
// break;
// case 5:
// cb.fileComplaint();
// break;
// case 6:
// cb.exportComplaintsToCSV();
// break;
// case 7:
// cb.searchComplaints();
// break;
// case 8:
// cout << BOLDGREEN << "Exiting..." << RESET << endl;
// break;
// default:
// cout << BOLDRED << "Invalid choice!\n" << RESET;
// }
// } while (choice != 8);
// >>>>>>> main
} while (choice != 9);

return 0;
}
}