From 427ef022bb5bc9a28a707fbb1efe08a72286b7ab Mon Sep 17 00:00:00 2001 From: Kablersalat Date: Wed, 19 Mar 2025 01:10:02 +0100 Subject: less swearing and first public push --- emailproxy-ui.php | 768 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 768 insertions(+) create mode 100644 emailproxy-ui.php (limited to 'emailproxy-ui.php') diff --git a/emailproxy-ui.php b/emailproxy-ui.php new file mode 100644 index 0000000..7258d94 --- /dev/null +++ b/emailproxy-ui.php @@ -0,0 +1,768 @@ + false, 'error' => "Failed to create socket"]; + } + + $result = socket_connect($socket, 'localhost', $commandPort); + if ($result === false) { + debugLog("socket_connect() failed: " . socket_strerror(socket_last_error($socket)), $debug, $file); + socket_close($socket); + return ['success' => false, 'error' => "Failed to connect to auth-injector"]; + } + + $data = json_encode($command); + socket_write($socket, $data, strlen($data)); + + $response = socket_read($socket, 4096); + socket_close($socket); + + $response = json_decode($response, true); + debugLog("Received response from auth-injector: " . json_encode($response), $debug, $file); + + return $response; +} + +function getAuthURL($logFile, $email) { + global $debugWeb, $debugLogFile; + + if (!file_exists($logFile)) { + debugLog("Log file not found: $logFile", $debugWeb, $debugLogFile); + return null; + } + + debugLog("Searching for auth URL in $logFile for email $email", $debugWeb, $debugLogFile); + $lines = array_reverse(file($logFile)); + + foreach ($lines as $line) { + if (strpos($line, "Please visit the following URL") !== false) { + debugLog("Found 'Please visit' line: $line", $debugWeb, $debugLogFile); + + if (strpos($line, $email) !== false) { + preg_match('/https:\/\/login\\.microsoftonline\\.com\\/[^ ]+/', $line, $matches); + $url = $matches[0] ?? null; + debugLog("Extracted URL: $url", $debugWeb, $debugLogFile); + return $url; + } + } + } + + debugLog("No auth URL found for $email after checking " . count($lines) . " lines", $debugWeb, $debugLogFile); + return null; +} + +// add "temporary" debug function for session ... +function debugSession($message) { + file_put_contents('/tmp/session_debug.log', + date('Y-m-d H:i:s') . " - " . $message . ": " . + json_encode($_SESSION) . "\n", + FILE_APPEND); +} + +// more debug functions for IMAP +function debugImap($message, $debug = true, $debugFile = null) { + if (!$debug) return; + $timestamp = date('Y-m-d H:i:s'); + $logMessage = "[$timestamp] [IMAP] $message\n"; + file_put_contents($debugFile ?? '/tmp/imap-debug.log', $logMessage, FILE_APPEND); + error_log($logMessage); // Also log to PHP error log +} + +// part of the user checking yk +function userExistsInConfig($configPath, $email) { + if (!file_exists($configPath)) return false; + $content = file_get_contents($configPath); + return strpos($content, "[$email]") !== false; +} + +function verifyUserPassword($email, $password) { + global $debugWeb, $debugLogFile; + + // imagine using the correct port + $imapPort = getMainImapPort(); + if (!$imapPort) { + debugLog("Could not determine IMAP port", $debugWeb, $debugLogFile); + return false; + } + + debugLog("Attempting to verify password for $email using IMAP port $imapPort", $debugWeb, $debugLogFile); + + // try and connect, if it fails, it fails lol + $fp = @fsockopen('127.0.0.1', $imapPort, $errno, $errstr, 5); + if (!$fp) { + debugLog("Could not connect to IMAP server: $errstr ($errno)", $debugWeb, $debugLogFile); + return false; + } + + // we need timeout, python isnt that fast + stream_set_timeout($fp, 10); + + // get le hello from das server + $greeting = fgets($fp, 1024); + debugLog("IMAP greeting: $greeting", $debugWeb, $debugLogFile); + + // check if its a valid greeting and not an insulting one lol + if (!$greeting || strpos($greeting, '* OK') === false) { + debugLog("Invalid IMAP greeting, closing connection", $debugWeb, $debugLogFile); + fclose($fp); + return false; + } + + // totally untested function to escape the email and password custom characters + $safeEmail = str_replace(array('\\', '"'), array('\\\\', '\\"'), $email); + $safePassword = str_replace(array('\\', '"'), array('\\\\', '\\"'), $password); + + // send the login command obviously + $loginCommand = "a001 LOGIN \"$safeEmail\" \"$safePassword\"\r\n"; + debugLog("Sending login command...", $debugWeb, $debugLogFile); + fwrite($fp, $loginCommand); + + // wait for python to piss its pants and respond + $response = ''; + $timeout = time() + 10; // 10 seconds for pissing time + + while (!feof($fp) && time() < $timeout) { + $line = fgets($fp, 1024); + if (!$line) break; + + $response .= $line; + debugLog("IMAP response line: " . trim($line), $debugWeb, $debugLogFile); + + // is ok? then good + if (strpos($line, 'a001 OK') === 0) { + fwrite($fp, "a002 LOGOUT\r\n"); + fclose($fp); + debugLog("Authentication succeeded", $debugWeb, $debugLogFile); + return true; + } + // is no? then bad + if (strpos($line, 'a001 NO') === 0 || strpos($line, 'a001 BAD') === 0) { + fclose($fp); + debugLog("Authentication failed: " . trim($line), $debugWeb, $debugLogFile); + return false; + } + } + + // if we here then we failed and we should go and cry + fclose($fp); + debugLog("Authentication timed out or had other issue", $debugWeb, $debugLogFile); + return false; +} + +function getMainImapPort() { + global $configPath; + + if (!file_exists($configPath)) { + return null; + } + + $content = file_get_contents($configPath); + if (preg_match('/\[IMAP-(\d+)\]/', $content, $matches)) { + return (int)$matches[1]; + } + + return null; +} + +function removeUserFromConfig($configPath, $email) { + if (!file_exists($configPath)) return false; + + $content = file_get_contents($configPath); + + // danger zone ahead we are using regex to remove the user from the config in a terrible way + $pattern = '/\[' . preg_quote($email, '/') . '\].*?(?=\n\[|\Z)/s'; + $contentAfterRemoval = preg_replace($pattern, '', $content); + + // i have ocd + $contentAfterRemoval = preg_replace("/\n\n\n+/", "\n\n", $contentAfterRemoval); + + // update prem file + return file_put_contents($configPath, $contentAfterRemoval) !== false; +} + +// state ? AMERICA !!! RAHHHHHH +$step = $_SESSION['step'] ?? 1; +$authUrl = ''; +$email = $_SESSION['email'] ?? ''; +$success = ''; +$error = ''; + +// mmmm posting +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + // check if the token is valid if is not it has no rights + $valid_token = false; + + if (isset($_POST['form_token']) && isset($_SESSION['form_token']) && + $_POST['form_token'] === $_SESSION['form_token']) { + $valid_token = true; + } + // i wont even pretend i know what this does + elseif (isset($_POST['form_token']) && isset($_SESSION['previous_form_token']) && + $_POST['form_token'] === $_SESSION['previous_form_token']) { + $valid_token = true; + // stolen code yay !!! + unset($_SESSION['previous_form_token']); + } + + if (!$valid_token) { + // le user has pressed refresh and submiteed the form again most likely so uhm nuh uh + $error = "Form submission error. Please try again."; + } else { + // MORE STOLEN CODE !!! YIPPIE + $_SESSION['form_token'] = bin2hex(random_bytes(32)); + + if ($step === 1 && isset($_POST['captcha'])) { + debugSession("Before CAPTCHA validation"); + // Step nummero eins: nutzloses gschiss catptcha + $captcha = trim($_POST['captcha']); + if ($captcha !== (string)$_SESSION['captcha']) { + $error = "Invalid CAPTCHA. Please try again."; + // kei ahnig wiso mer ned üsih function benützed aber okay hets problem gfixxed + $_SESSION['captcha'] = rand(1000, 9999); + } else { + // isch guet denn bye bye kaptcha damit "sicherheit und so" + unset($_SESSION['captcha']); + + // ich verlühre mini hoffnig das das jemals sicher wird sih aber mer chans ja probiere (ich han depressioneh) + $imapPort = 2993 + rand(1, 100); + $smtpPort = 2465 + rand(1, 100); + + // session ID, isch so fürs authentifizierig dingens + $sessionId = time() . '_' . rand(1000, 9999); + + // merken sonst wiso haben wir es gemacht ??? + $_SESSION['imapPort'] = $imapPort; + $_SESSION['smtpPort'] = $smtpPort; + $_SESSION['sessionId'] = $sessionId; + + // yk vlt bruchid mer zersch emol d'email adresse deswege mal zu steppo 2 gah + $_SESSION['step'] = 2; + $_SESSION['form_success'] = true; + + // save session and redirect to the same page ... to update the content kinda terribly + session_write_close(); + header('Location: ' . $_SERVER['PHP_SELF']); + exit; + } + debugSession("After CAPTCHA validation"); + } elseif ($step === 2 && isset($_POST['email']) && isset($_POST['password'])) { + debugSession("Before email/password processing"); + // Schritt numbero due ... email und passwort ihtöggele + $email = trim($_POST['email']); + $password = trim($_POST['password']); + + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + $error = "Invalid email address."; + } elseif (!isEmailAllowed($email, $allowedDomains)) { + $error = "Email domain not allowed."; + } else { + // mmm mal güxle ob de user scho existiert im config + if (userExistsInConfig($configPath, $email)) { + // sehr guet denn chömer mal gugge ob das passwort au stimmt + if (verifyUserPassword($email, $password)) { + // das isch save ned sicher aber yoa lets fucking go oder so + $_SESSION['added_email'] = $email; + $_SESSION['verified_password'] = $password; // mmm yes very secure password storage right here so you can steal it from the session :harold: + $_SESSION['step'] = 4; // go to SEX panel ... to show the user config page + + // redirect to the same page to update the content + session_write_close(); + header('Location: ' . $_SERVER['PHP_SELF']); + exit; + } else { + // GOOD BYE MY NI... back to the lobby !!! + $error = "Incorrect password for existing account. If you're having trouble, contact " . + htmlspecialchars($config['SYSADMIN_EMAIL'] ?? 'your system administrator'); + } + } else { + // user existiert ned also lets go und mache das authentifizierig dingens zum ms nerve + $_SESSION['email'] = $email; + $imapPort = $_SESSION['imapPort']; + $smtpPort = $_SESSION['smtpPort']; + $sessionId = $_SESSION['sessionId']; + + // now launch emailproxy temp session (look at me so sekurity) + $command = [ + 'type' => 'new_user', + 'email' => $email, + 'imap_port' => $imapPort, + 'smtp_port' => $smtpPort, + 'session_id' => $sessionId + ]; + + // note to self : following line has been fixed by an LLM (because i was lazy and i have no oversight of my code at this point its late and i want to sleep) + $response = sendCommandToAuthInjector($command, $debugWeb, $debugLogFile); + + if (!$response['success']) { + $error = "Failed to start authentication process. Please try again."; + } else { + sleep(3); // more spaghetti timeouts to ensure my slow server can handle it + + // connect to the IMAP server and send creds (this fails sometimes but we ignore it) + $fp = fsockopen("127.0.0.1", $imapPort, $errno, $errstr, 5); + if (!$fp) { + $error = "Failed to connect to the temporary emailproxy (IMAP port $imapPort)."; + } else { + // Send login command to IMAP + fwrite($fp, "a001 LOGIN $email $password\r\n"); + sleep(5); // demonstration of ignoring it + fclose($fp); + + $maxAttempts = 10; // how many times we try to get the url before deciding le server is le fucked + $authUrl = null; + + for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) { + $authUrl = getAuthURL($logPath, $email); + if ($authUrl) { + break; + } + sleep(3); // more demonstration of ignoring the problem + } + + if ($authUrl) { + $_SESSION['authUrl'] = $authUrl; + $_SESSION['step'] = 3; // move to step numbero tres ... tres bien oder so wenn mer das url hend + $_SESSION['form_success'] = true; + + // Save session and redirect + session_write_close(); + header('Location: ' . $_SERVER['PHP_SELF']); + exit; + } else { + $error = "Failed to retrieve the authentication URL. Please try again."; + debugLog("Authentication URL not found after $maxAttempts attempts", $debugWeb, $debugLogFile); + } + } + } + } + } + } elseif ($step === 3 && isset($_POST['auth_redirect'])) { + debugSession("Processing redirect URL"); + // number tres ... redirect url processing + $authRedirect = trim($_POST['auth_redirect']); + $email = $_SESSION['email']; + $sessionId = $_SESSION['sessionId']; + + // send the redirect URL to the auth-injector (or by this point known as emailproxy-ui.py backend) + $command = [ + 'type' => 'redirect_url', + 'session_id' => $sessionId, + 'email' => $email, + 'redirect_url' => $authRedirect + ]; + + $response = sendCommandToAuthInjector($command, $debugWeb, $debugLogFile); + + if ($response['success']) { + $command = [ + 'type' => 'merge_config', + 'session_id' => $sessionId + ]; + $mergeResponse = sendCommandToAuthInjector($command, $debugWeb, $debugLogFile); + if ($mergeResponse['success']) { + // checking if the user exists in the config ... again ... because stupid + $is_existing = userExistsInConfig($configPath, $email); + + $_SESSION['added_email'] = $email; + $_SESSION['auth_success'] = true; + $_SESSION['form_success'] = true; + $_SESSION['is_existing_account'] = $is_existing; // attempt at trying to make it display a different message upon creating or editing an account but didnt work lol + $_SESSION['step'] = 4; // numbero quatro oder so + + // save sessino and redirect to the same page ... yk updates yap yap + session_write_close(); + header('Location: ' . $_SERVER['PHP_SELF']); + exit; + } else { + $error = "Failed to merge configuration. Please try again."; + } + } else { + $error = "Authentication failed. The URL you provided may be invalid or the authentication timed out."; + $command = [ + 'type' => 'cleanup', + 'session_id' => $sessionId + ]; + sendCommandToAuthInjector($command, $debugWeb, $debugLogFile); + } + } + // Idk what the following mystery is but its AI's spin on fixing and securing my user delete process + // Add this after your existing POST handlers, before the closing } of the if ($_SERVER['REQUEST_METHOD'] === 'POST') block + elseif (isset($_POST['remove_email']) && isset($_POST['confirm_password'])) { + $email = trim($_POST['remove_email']); + + // uhm we uhm please actually want to delete an email and not accidentally match all config entries + if (empty($email) && isset($_SESSION['email_for_removal'])) { + $email = $_SESSION['email_for_removal']; + unset($_SESSION['email_for_removal']); + } + + $password = trim($_POST['confirm_password']); + + if (empty($email)) { + $_SESSION['success_message'] = "Error: No email address specified for removal."; + } else { + // you very very sure the password is le correcto amigo ? + if (verifyUserPassword($email, $password)) { + // tell the auth-injector to brutally cut out the user from running config + $command = [ + 'type' => 'remove_user', + 'email' => $email + ]; + + $response = sendCommandToAuthInjector($command, $debugWeb, $debugLogFile); + + if ($response['success']) { + $_SESSION['success_message'] = "Account $email has been successfully removed from the email proxy."; + } else { + $_SESSION['success_message'] = "Failed to remove account. Error: " . ($response['error'] ?? 'Unknown error'); + } + } else { + $_SESSION['success_message'] = "Password verification failed. If you need assistance, please contact " . + ($config['SYSADMIN_EMAIL'] ?? 'your system administrator'); + } + } + + // redir to first page (maybe clear session ? idk yet) + header('Location: ' . $_SERVER['PHP_SELF']); + exit; + } + } +} +?> + + + + + + Emailproxy Auth Panel + + + +

OAutsch Sucks Authorization Panel

+

for people who hate 2FA, Microsoft and overcomplicated E-Mail.

+

Made with love for PHP
and PURE RAGE AND HATRED FOR AZURE, TEAMS, EXCHANGE AND MICRO$SOFT
by UMTS at teleco

+
+ + +

+ + + +

+ + + +
+
+ + +
+ + +
+ +
+
+ + +
+
+ + +
+ + +
+ +

Please visit the following URL to complete authentication:

+
+ +
+

After completing the authentication process, you will be redirected to a page with a final URL. Copy that URL and paste it below:

+ +
+
+ + +
+ + +
+ +
+

Success!

+

Your account exists on the email proxy.

+ +
+

Mail Client Configuration

+ +
+
+
Incoming Mail Server ()
+
    +
  • Server:
  • +
  • Port:
  • +
  • Security:
  • +
  • Username:
  • +
  • Authentication: Normal Password
  • +
+
+ +
+
Outgoing Mail Server ()
+
    +
  • Server:
  • +
  • Port:
  • +
  • Security:
  • +
  • Username:
  • +
  • Authentication: Normal Password
  • +
+
+
+ +

Use your defined password to sign into the proxy server (can differ from OAuth Providers account password).

+
+ +
+

Add Another Account

+ + +
+
+ + + + + -- cgit v1.2.3-70-g09d2