diff --git a/.gitignore b/.gitignore index 4bb1c62..d1138a3 100644 --- a/.gitignore +++ b/.gitignore @@ -103,3 +103,6 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk +certs/ +db_config.php +config.php \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/TVPNBackend.iml b/.idea/TVPNBackend.iml new file mode 100644 index 0000000..c956989 --- /dev/null +++ b/.idea/TVPNBackend.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..b5554f8 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + mariadb + true + org.mariadb.jdbc.Driver + jdbc:mariadb://mariadb.traceyclan.us:3306 + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..876c99f --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/php.xml b/.idea/php.xml new file mode 100644 index 0000000..7d11e4f --- /dev/null +++ b/.idea/php.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 0000000..9a220bf --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/api/auth.php b/api/auth.php new file mode 100644 index 0000000..64bfa5c --- /dev/null +++ b/api/auth.php @@ -0,0 +1,89 @@ +real_escape_string($token); + $stmt = $mysqli->prepare("SELECT * FROM users WHERE token = ?"); + $stmt->bind_param("s", $token); + + $stmt->execute(); + $result = $stmt->get_result(); + $response = array(); + if ($result->num_rows > 0) { + $row = $result->fetch_assoc(); + $response['success'] = "true"; + $response['message'] = 'Login successful!'; + $response['token'] = $row['token']; + $response['expires'] = $row['expires']; + } else { + $response['success'] = "false"; + $response['message'] = 'Invalid token.'; + $response['token'] = ""; + $response['expires'] = 0; + } + // Close connections + $stmt->close(); + $mysqli->close(); + header('Content-Type: application/json'); + echo '{"success":"' . $response['success'] . '", "isAuthenticated":' . $response['success'] . ', "token":"'. $response['token'] .'", "expires":' . $response['expires'] . ', "message":"' . $response['message'] . '"' . '}'; + return; +} + +if (is_null($data)) { + header('Content-Type: application/json'); + http_response_code(412); + echo '{"success":"false","message":"No body sent.","token":"","expires": 0,"isAuthenticated":false}'; + return; +} + +$user = $data['username']; +$pass = $data['password']; + +// Input validation and sanitization +$user = $mysqli->real_escape_string($user); + +// Prepare and bind +$stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ?"); +$stmt->bind_param("s", $user); + +// Execute statement +$stmt->execute(); + +// Get result +$result = $stmt->get_result(); + +$response = array(); + +if ($result->num_rows > 0) { + $row = $result->fetch_assoc(); + $hashed_password = $row['passwordHash']; + if (password_verify($pass, $hashed_password)) { + $response['success'] = "true"; + $response['message'] = 'Login successful!'; + $response['token'] = $row['token']; + $response['expires'] = $row['expires']; + } else { + $response['success'] = "false"; + $response['message'] = 'Invalid username or password.'; + $response['token'] = ""; + $response['expires'] = 0; + } +} else { + $response['success'] = "false"; + $response['message'] = 'Invalid username or password.'; + $response['token'] = ""; + $response['expires'] = 0; +} + +// Close connections +$stmt->close(); +$mysqli->close(); + +// Return JSON response +header('Content-Type: application/json'); +echo '{"success":"' . $response['success'] . '", "isAuthenticated":' . $response['success'] . ', "token":"'. $response['token'] .'", "expires":' . $response['expires'] . ', "message":"' . $response['message'] . '"' . '}'; + diff --git a/api/user-info.php b/api/user-info.php new file mode 100644 index 0000000..85f2b0b --- /dev/null +++ b/api/user-info.php @@ -0,0 +1,49 @@ +real_escape_string($token); + +// Prepare and bind +$stmt = $mysqli->prepare("SELECT * FROM users WHERE token = ?"); +$stmt->bind_param("s", $token); + +// Execute statement +$stmt->execute(); + +// Get result +$result = $stmt->get_result(); + +$response = array(); + +if ($result->num_rows > 0) { + $row = $result->fetch_assoc(); + + $response['success'] = "true"; + $response['message'] = "Success"; + $response['username'] = $row['username']; + $response['email'] = $row['email']; +} else { + $response['success'] = "false"; + $response['message'] = 'Invalid token.'; + $response['username'] = ""; + $response['email'] = ""; +} + +// Close connections +$stmt->close(); +$mysqli->close(); + +// Return JSON response +header('Content-Type: application/json'); +echo '{"success":' . $response['success'] . ', "message":"' . $response['message'] . '", "username":"' . $response['username'] . '", "email":"' . $response['email'] . '"}'; diff --git a/assets/css/style.css b/assets/css/style.css new file mode 100644 index 0000000..22dba22 --- /dev/null +++ b/assets/css/style.css @@ -0,0 +1,116 @@ +/* Global container to center the buttons and position tabs at the top */ +body { + font-family: Arial, sans-serif; + margin: 0; + background-color: #f4f4f9; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; /* Aligns content to the top */ + min-height: 100vh; +} + +/* Tab section at the top */ +.tab { + width: 100%; + display: flex; + justify-content: center; + background-color: #f1f1f1; + padding: 10px 0; + border-bottom: 1px solid #ccc; +} + +.tab a { + background-color: inherit; + border: none; + outline: none; + cursor: pointer; + padding: 14px 16px; + transition: 0.3s; + text-decoration: none; + color: black; +} + +.tab a:hover { + background-color: #ddd; +} + +.tab a.active { + background-color: #ccc; +} + +/* Container for centering the buttons in the middle of the page */ +.container { + text-align: center; + width: 300px; + padding: 20px; + border-radius: 8px; + background-color: white; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + margin-top: 20vh; /* Pushes the container down */ +} + +h1 { + margin-bottom: 20px; + color: #333; +} + +/* Input Group */ +.input-group { + margin-bottom: 15px; + text-align: left; +} + +.input-group label { + display: block; + margin-bottom: 5px; + color: #333; +} + +.input-group input { + width: 100%; + padding: 10px; + font-size: 16px; + border: 1px solid #ccc; + border-radius: 4px; +} + +/* Button Styling */ +button { + background-color: #4CAF50; + color: white; + border: none; + padding: 15px 32px; + margin-top: 10px; + font-size: 16px; + cursor: pointer; + transition: background-color 0.3s; + width: 100%; +} + +button:hover { + background-color: #45a049; +} + +/* Error Message */ +.error-message { + color: red; + font-size: 14px; + margin-top: 15px; +} + +/* Style for link buttons (can be used globally) */ +.buttons button { + background-color: #4CAF50; + color: white; + border: none; + padding: 15px 32px; + margin: 10px; + font-size: 16px; + cursor: pointer; + transition: background-color 0.3s; +} + +.buttons button:hover { + background-color: #45a049; +} diff --git a/authenticate.php b/authenticate.php new file mode 100644 index 0000000..820f257 --- /dev/null +++ b/authenticate.php @@ -0,0 +1,15 @@ +prepare("CREATE TABLE IF NOT EXISTS users( + id INTEGER PRIMARY KEY, + username TEXT NOT NULL, + passwordHash TEXT NOT NULL, + email TEXT NOT NULL + );"); + +echo $stmt->execute(); + + +$mysqli->close(); \ No newline at end of file diff --git a/config.php.example b/config.php.example new file mode 100644 index 0000000..9bf0cda --- /dev/null +++ b/config.php.example @@ -0,0 +1,2 @@ +options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, true); +$mysqli->ssl_set($_SERVER['DOCUMENT_ROOT'] . "/path/to/client-key.pem", $_SERVER['DOCUMENT_ROOT'] . "/path/to/client-cert.pem", $_SERVER['DOCUMENT_ROOT'] . "/path/to/ca-cert.pem", NULL, NULL); +$mysqli->real_connect($dbHost, $dbUser, $dbPass, $dbName); \ No newline at end of file diff --git a/includes/authcheck.php b/includes/authcheck.php new file mode 100644 index 0000000..a2992be --- /dev/null +++ b/includes/authcheck.php @@ -0,0 +1,22 @@ + +
+ Home + Panel + + Logout'; + } else { + echo 'Login'; + } + ?> +
diff --git a/includes/utils.php b/includes/utils.php new file mode 100644 index 0000000..f421725 --- /dev/null +++ b/includes/utils.php @@ -0,0 +1,36 @@ + + + + + + + + Link Buttons Page + + + + +
+

TVPN

+
+ + + + + +
+
+ + + + diff --git a/login/authenticate.php b/login/authenticate.php new file mode 100644 index 0000000..e9046fb --- /dev/null +++ b/login/authenticate.php @@ -0,0 +1,66 @@ +real_escape_string($user); + +// Prepare and bind +$stmt = $mysqli->prepare("SELECT passwordHash FROM users WHERE username = ?"); +$stmt->bind_param("s", $user); + +// Execute statement +$stmt->execute(); + +// Get result +$result = $stmt->get_result(); + +$response = array(); + +if ($result->num_rows > 0) { + $row = $result->fetch_assoc(); + $hashed_password = $row['passwordHash']; + if (password_verify($pass, $hashed_password)) { + // Regenerate session ID to prevent session fixation + session_regenerate_id(true); + + // Create session + $_SESSION['authenticated'] = true; + $_SESSION['username'] = $user; + + $response['success'] = true; + $response['message'] = 'Login successful!'; + } else { + $response['success'] = false; + $response['message'] = 'Invalid username or password.'; + } +} else { + $response['success'] = false; + $response['message'] = 'Invalid username or password.'; +} + +// Close connections +$stmt->close(); +$mysqli->close(); + +// Return JSON response +header('Content-Type: application/json'); +echo '{"success":"' . $response['success'] . '","message":"' . $response['message'] . '"' . '}'; + diff --git a/login/genpass.php b/login/genpass.php new file mode 100644 index 0000000..93be332 --- /dev/null +++ b/login/genpass.php @@ -0,0 +1,2 @@ + + + + + + + + Login + + + + +
+

Login

+
+
+ + +
+
+ + +
+ +
+
+ +
+ + + + diff --git a/login/script.js b/login/script.js new file mode 100644 index 0000000..b07d26a --- /dev/null +++ b/login/script.js @@ -0,0 +1,36 @@ +document.getElementById('loginForm').addEventListener('submit', function(e) { + e.preventDefault(); + + const username = document.getElementById('username').value; + const password = document.getElementById('password').value; + + const data = { + username: username, + password: password + }; + + // Show spinner + document.getElementById('spinner').style.display = 'block'; + + fetch('authenticate.php', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }) + .then(response => response.json()) + .then(data => { + document.getElementById('response').innerText = data.message; + // Hide spinner + document.getElementById('spinner').style.display = 'none'; + if (data.success) { + window.location.href = '../'; // Redirect on successful login + } + }) + .catch((error) => { + document.getElementById('response').innerText = 'Error: ' + error; + // Hide spinner + document.getElementById('spinner').style.display = 'none'; + }); +}); diff --git a/logout/index.php b/logout/index.php new file mode 100644 index 0000000..d680048 --- /dev/null +++ b/logout/index.php @@ -0,0 +1,24 @@ + + + + + + + TVPN Panel + + + +

Hello World!

+ + \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..da72b95 --- /dev/null +++ b/script.js @@ -0,0 +1,3 @@ +function openLink(url) { + window.open(url, '_blank'); +}