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 @@
+
+
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
+
+
+
+
+
+
+
+
+
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');
+}