emailproxy-ui.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. <?php
  2. session_start();
  3. ini_set('session.cookie_lifetime', 0); // till browser closes
  4. ini_set('session.gc_maxlifetime', 600); // 10 minutes
  5. ini_set('display_errors', 1);
  6. ini_set('display_startup_errors', 1);
  7. error_reporting(E_ALL);
  8. if (!isset($_SESSION['form_token'])) {
  9. $_SESSION['form_token'] = bin2hex(random_bytes(32));
  10. }
  11. if (isset($_SESSION['form_success']) && $_SESSION['form_success']) {
  12. $_SESSION['form_success'] = false;
  13. }
  14. // dont ask why i have this here
  15. if (isset($_SESSION['success_message'])) {
  16. $success = $_SESSION['success_message'];
  17. unset($_SESSION['success_message']);
  18. }
  19. // load the config (edit this to your needs)
  20. $config = parse_ini_file('/home/crt/helper-emailproxy/config/config.env');
  21. $configPath = $config['EMAILPROXY_CONFIG_FILE'];
  22. $authBaseConfigPath = $config['EMAILPROXY_AUTH_CONFIG'] ?? '/home/crt/helper-emailproxy/config/emailproxy-auth.config'; // base config path plus fallback to my default service user
  23. $logPath = $config['EMAILPROXY_LOG_FILE'];
  24. $allowedDomains = array_map('trim', explode(',', $config['ALLOWED_DOMAINS']));
  25. $debugWeb = isset($config['DEBUG_WEB']) && in_array(strtolower($config['DEBUG_WEB']), ['1', 'true', 'yes'], true);
  26. $debugLogFile = $config['DEBUG_WEB_LOG_FILE'] ?? '/tmp/web-debug.log';
  27. $authTimeout = 600; // if le auth session is not done in le 10 minutes welp too bad
  28. $publicMode = isset($config['PUBLIC']) && in_array(strtolower($config['PUBLIC']), ['1', 'true', 'yes'], true);
  29. $emailproxyExec = $config['EMAILPROXY_EXECUTABLE'];
  30. $commandPort = 8765; // little port to talk back to the auth-injector, should probably secure this more
  31. $mailServerName = $config['MAIL_SERVER_NAME'] ?? 'localhost';
  32. $mailImapPort = $config['MAIL_IMAP_PORT'] ?? '993';
  33. $mailSmtpPort = $config['MAIL_SMTP_PORT'] ?? '587';
  34. $mailImapSsl = isset($config['MAIL_IMAP_SSL']) && in_array(strtolower($config['MAIL_IMAP_SSL']), ['1', 'true', 'yes'], true); // is this a shit way to handle this ? yes very much so, does it make it more foolproof ? also yes
  35. $mailSmtpSsl = isset($config['MAIL_SMTP_SSL']) && in_array(strtolower($config['MAIL_SMTP_SSL']), ['1', 'true', 'yes'], true);
  36. $mailImapProtocol = $config['MAIL_IMAP_PROTOCOL'] ?? 'IMAP';
  37. $mailSmtpProtocol = $config['MAIL_SMTP_PROTOCOL'] ?? 'SMTP';
  38. // our super duper shit captcha that can be bypassed in seconds
  39. if (!isset($_SESSION['captcha']) || empty($_SESSION['captcha'])) {
  40. $_SESSION['captcha'] = rand(1000, 9999);
  41. }
  42. // i dont know if my code breaks without debuging enabled yet :harold:.exe
  43. function debugLog($text, $debug, $file) {
  44. if (!$debug) return;
  45. $entry = "[" . date("Y-m-d H:i:s") . "] " . $text . "\n";
  46. file_put_contents($file, $entry, FILE_APPEND);
  47. }
  48. function isEmailAllowed($email, $allowedDomains) {
  49. $parts = explode('@', $email);
  50. if (count($parts) !== 2) return false;
  51. return in_array($parts[1], $allowedDomains);
  52. }
  53. function sendCommandToAuthInjector($command, $debug, $file) {
  54. global $commandPort;
  55. debugLog("Sending command to auth-injector: " . json_encode($command), $debug, $file);
  56. $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  57. if ($socket === false) {
  58. debugLog("socket_create() failed: " . socket_strerror(socket_last_error()), $debug, $file);
  59. return ['success' => false, 'error' => "Failed to create socket"];
  60. }
  61. $result = socket_connect($socket, 'localhost', $commandPort);
  62. if ($result === false) {
  63. debugLog("socket_connect() failed: " . socket_strerror(socket_last_error($socket)), $debug, $file);
  64. socket_close($socket);
  65. return ['success' => false, 'error' => "Failed to connect to auth-injector"];
  66. }
  67. $data = json_encode($command);
  68. socket_write($socket, $data, strlen($data));
  69. $response = socket_read($socket, 4096);
  70. socket_close($socket);
  71. $response = json_decode($response, true);
  72. debugLog("Received response from auth-injector: " . json_encode($response), $debug, $file);
  73. return $response;
  74. }
  75. function getAuthURL($logFile, $email) {
  76. global $debugWeb, $debugLogFile;
  77. if (!file_exists($logFile)) {
  78. debugLog("Log file not found: $logFile", $debugWeb, $debugLogFile);
  79. return null;
  80. }
  81. debugLog("Searching for auth URL in $logFile for email $email", $debugWeb, $debugLogFile);
  82. $lines = array_reverse(file($logFile));
  83. foreach ($lines as $line) {
  84. if (strpos($line, "Please visit the following URL") !== false) {
  85. debugLog("Found 'Please visit' line: $line", $debugWeb, $debugLogFile);
  86. if (strpos($line, $email) !== false) {
  87. preg_match('/https:\/\/login\\.microsoftonline\\.com\\/[^ ]+/', $line, $matches);
  88. $url = $matches[0] ?? null;
  89. debugLog("Extracted URL: $url", $debugWeb, $debugLogFile);
  90. return $url;
  91. }
  92. }
  93. }
  94. debugLog("No auth URL found for $email after checking " . count($lines) . " lines", $debugWeb, $debugLogFile);
  95. return null;
  96. }
  97. // add "temporary" debug function for session ...
  98. function debugSession($message) {
  99. file_put_contents('/tmp/session_debug.log',
  100. date('Y-m-d H:i:s') . " - " . $message . ": " .
  101. json_encode($_SESSION) . "\n",
  102. FILE_APPEND);
  103. }
  104. // more debug functions for IMAP
  105. function debugImap($message, $debug = true, $debugFile = null) {
  106. if (!$debug) return;
  107. $timestamp = date('Y-m-d H:i:s');
  108. $logMessage = "[$timestamp] [IMAP] $message\n";
  109. file_put_contents($debugFile ?? '/tmp/imap-debug.log', $logMessage, FILE_APPEND);
  110. error_log($logMessage); // Also log to PHP error log
  111. }
  112. // part of the user checking yk
  113. function userExistsInConfig($configPath, $email) {
  114. if (!file_exists($configPath)) return false;
  115. $content = file_get_contents($configPath);
  116. return strpos($content, "[$email]") !== false;
  117. }
  118. function verifyUserPassword($email, $password) {
  119. global $debugWeb, $debugLogFile;
  120. // imagine using the correct port
  121. $imapPort = getMainImapPort();
  122. if (!$imapPort) {
  123. debugLog("Could not determine IMAP port", $debugWeb, $debugLogFile);
  124. return false;
  125. }
  126. debugLog("Attempting to verify password for $email using IMAP port $imapPort", $debugWeb, $debugLogFile);
  127. // try and connect, if it fails, it fails lol
  128. $fp = @fsockopen('127.0.0.1', $imapPort, $errno, $errstr, 5);
  129. if (!$fp) {
  130. debugLog("Could not connect to IMAP server: $errstr ($errno)", $debugWeb, $debugLogFile);
  131. return false;
  132. }
  133. // we need timeout, python isnt that fast
  134. stream_set_timeout($fp, 10);
  135. // get le hello from das server
  136. $greeting = fgets($fp, 1024);
  137. debugLog("IMAP greeting: $greeting", $debugWeb, $debugLogFile);
  138. // check if its a valid greeting and not an insulting one lol
  139. if (!$greeting || strpos($greeting, '* OK') === false) {
  140. debugLog("Invalid IMAP greeting, closing connection", $debugWeb, $debugLogFile);
  141. fclose($fp);
  142. return false;
  143. }
  144. // totally untested function to escape the email and password custom characters
  145. $safeEmail = str_replace(array('\\', '"'), array('\\\\', '\\"'), $email);
  146. $safePassword = str_replace(array('\\', '"'), array('\\\\', '\\"'), $password);
  147. // send the login command obviously
  148. $loginCommand = "a001 LOGIN \"$safeEmail\" \"$safePassword\"\r\n";
  149. debugLog("Sending login command...", $debugWeb, $debugLogFile);
  150. fwrite($fp, $loginCommand);
  151. // wait for python to piss its pants and respond
  152. $response = '';
  153. $timeout = time() + 10; // 10 seconds for pissing time
  154. while (!feof($fp) && time() < $timeout) {
  155. $line = fgets($fp, 1024);
  156. if (!$line) break;
  157. $response .= $line;
  158. debugLog("IMAP response line: " . trim($line), $debugWeb, $debugLogFile);
  159. // is ok? then good
  160. if (strpos($line, 'a001 OK') === 0) {
  161. fwrite($fp, "a002 LOGOUT\r\n");
  162. fclose($fp);
  163. debugLog("Authentication succeeded", $debugWeb, $debugLogFile);
  164. return true;
  165. }
  166. // is no? then bad
  167. if (strpos($line, 'a001 NO') === 0 || strpos($line, 'a001 BAD') === 0) {
  168. fclose($fp);
  169. debugLog("Authentication failed: " . trim($line), $debugWeb, $debugLogFile);
  170. return false;
  171. }
  172. }
  173. // if we here then we failed and we should go and cry
  174. fclose($fp);
  175. debugLog("Authentication timed out or had other issue", $debugWeb, $debugLogFile);
  176. return false;
  177. }
  178. function getMainImapPort() {
  179. global $configPath;
  180. if (!file_exists($configPath)) {
  181. return null;
  182. }
  183. $content = file_get_contents($configPath);
  184. if (preg_match('/\[IMAP-(\d+)\]/', $content, $matches)) {
  185. return (int)$matches[1];
  186. }
  187. return null;
  188. }
  189. function removeUserFromConfig($configPath, $email) {
  190. if (!file_exists($configPath)) return false;
  191. $content = file_get_contents($configPath);
  192. // danger zone ahead we are using regex to remove the user from the config in a terrible way
  193. $pattern = '/\[' . preg_quote($email, '/') . '\].*?(?=\n\[|\Z)/s';
  194. $contentAfterRemoval = preg_replace($pattern, '', $content);
  195. // i have ocd
  196. $contentAfterRemoval = preg_replace("/\n\n\n+/", "\n\n", $contentAfterRemoval);
  197. // update prem file
  198. return file_put_contents($configPath, $contentAfterRemoval) !== false;
  199. }
  200. // state ? AMERICA !!! RAHHHHHH
  201. $step = $_SESSION['step'] ?? 1;
  202. $authUrl = '';
  203. $email = $_SESSION['email'] ?? '';
  204. $success = '';
  205. $error = '';
  206. // mmmm posting
  207. if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  208. // check if the token is valid if is not it has no rights
  209. $valid_token = false;
  210. if (isset($_POST['form_token']) && isset($_SESSION['form_token']) &&
  211. $_POST['form_token'] === $_SESSION['form_token']) {
  212. $valid_token = true;
  213. }
  214. // i wont even pretend i know what this does
  215. elseif (isset($_POST['form_token']) && isset($_SESSION['previous_form_token']) &&
  216. $_POST['form_token'] === $_SESSION['previous_form_token']) {
  217. $valid_token = true;
  218. // stolen code yay !!!
  219. unset($_SESSION['previous_form_token']);
  220. }
  221. if (!$valid_token) {
  222. // le user has pressed refresh and submiteed the form again most likely so uhm nuh uh
  223. $error = "Form submission error. Please try again.";
  224. } else {
  225. // MORE STOLEN CODE !!! YIPPIE
  226. $_SESSION['form_token'] = bin2hex(random_bytes(32));
  227. if ($step === 1 && isset($_POST['captcha'])) {
  228. debugSession("Before CAPTCHA validation");
  229. // Step nummero eins: nutzloses gschiss catptcha
  230. $captcha = trim($_POST['captcha']);
  231. if ($captcha !== (string)$_SESSION['captcha']) {
  232. $error = "Invalid CAPTCHA. Please try again.";
  233. // kei ahnig wiso mer ned üsih function benützed aber okay hets problem gfixxed
  234. $_SESSION['captcha'] = rand(1000, 9999);
  235. } else {
  236. // isch guet denn bye bye kaptcha damit "sicherheit und so"
  237. unset($_SESSION['captcha']);
  238. // ich verlühre mini hoffnig das das jemals sicher wird sih aber mer chans ja probiere (ich han depressioneh)
  239. $imapPort = 2993 + rand(1, 100);
  240. $smtpPort = 2465 + rand(1, 100);
  241. // session ID, isch so fürs authentifizierig dingens
  242. $sessionId = time() . '_' . rand(1000, 9999);
  243. // merken sonst wiso haben wir es gemacht ???
  244. $_SESSION['imapPort'] = $imapPort;
  245. $_SESSION['smtpPort'] = $smtpPort;
  246. $_SESSION['sessionId'] = $sessionId;
  247. // yk vlt bruchid mer zersch emol d'email adresse deswege mal zu steppo 2 gah
  248. $_SESSION['step'] = 2;
  249. $_SESSION['form_success'] = true;
  250. // save session and redirect to the same page ... to update the content kinda terribly
  251. session_write_close();
  252. header('Location: ' . $_SERVER['PHP_SELF']);
  253. exit;
  254. }
  255. debugSession("After CAPTCHA validation");
  256. } elseif ($step === 2 && isset($_POST['email']) && isset($_POST['password'])) {
  257. debugSession("Before email/password processing");
  258. // Schritt numbero due ... email und passwort ihtöggele
  259. $email = trim($_POST['email']);
  260. $password = trim($_POST['password']);
  261. if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
  262. $error = "Invalid email address.";
  263. } elseif (!isEmailAllowed($email, $allowedDomains)) {
  264. $error = "Email domain not allowed.";
  265. } else {
  266. // mmm mal güxle ob de user scho existiert im config
  267. if (userExistsInConfig($configPath, $email)) {
  268. // sehr guet denn chömer mal gugge ob das passwort au stimmt
  269. if (verifyUserPassword($email, $password)) {
  270. // das isch save ned sicher aber yoa lets fucking go oder so
  271. $_SESSION['added_email'] = $email;
  272. $_SESSION['verified_password'] = $password; // mmm yes very secure password storage right here so you can steal it from the session :harold:
  273. $_SESSION['step'] = 4; // go to SEX panel ... to show the user config page
  274. // redirect to the same page to update the content
  275. session_write_close();
  276. header('Location: ' . $_SERVER['PHP_SELF']);
  277. exit;
  278. } else {
  279. // GOOD BYE MY NI... back to the lobby !!!
  280. $error = "Incorrect password for existing account. If you're having trouble, contact " .
  281. htmlspecialchars($config['SYSADMIN_EMAIL'] ?? 'your system administrator');
  282. }
  283. } else {
  284. // user existiert ned also lets go und mache das authentifizierig dingens zum ms nerve
  285. $_SESSION['email'] = $email;
  286. $imapPort = $_SESSION['imapPort'];
  287. $smtpPort = $_SESSION['smtpPort'];
  288. $sessionId = $_SESSION['sessionId'];
  289. // now launch emailproxy temp session (look at me so sekurity)
  290. $command = [
  291. 'type' => 'new_user',
  292. 'email' => $email,
  293. 'imap_port' => $imapPort,
  294. 'smtp_port' => $smtpPort,
  295. 'session_id' => $sessionId
  296. ];
  297. // 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)
  298. $response = sendCommandToAuthInjector($command, $debugWeb, $debugLogFile);
  299. if (!$response['success']) {
  300. $error = "Failed to start authentication process. Please try again.";
  301. } else {
  302. sleep(3); // more spaghetti timeouts to ensure my slow server can handle it
  303. // connect to the IMAP server and send creds (this fails sometimes but we ignore it)
  304. $fp = fsockopen("127.0.0.1", $imapPort, $errno, $errstr, 5);
  305. if (!$fp) {
  306. $error = "Failed to connect to the temporary emailproxy (IMAP port $imapPort).";
  307. } else {
  308. // Send login command to IMAP
  309. fwrite($fp, "a001 LOGIN $email $password\r\n");
  310. sleep(5); // demonstration of ignoring it
  311. fclose($fp);
  312. $maxAttempts = 10; // how many times we try to get the url before deciding le server is le fucked
  313. $authUrl = null;
  314. for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
  315. $authUrl = getAuthURL($logPath, $email);
  316. if ($authUrl) {
  317. break;
  318. }
  319. sleep(3); // more demonstration of ignoring the problem
  320. }
  321. if ($authUrl) {
  322. $_SESSION['authUrl'] = $authUrl;
  323. $_SESSION['step'] = 3; // move to step numbero tres ... tres bien oder so wenn mer das url hend
  324. $_SESSION['form_success'] = true;
  325. // Save session and redirect
  326. session_write_close();
  327. header('Location: ' . $_SERVER['PHP_SELF']);
  328. exit;
  329. } else {
  330. $error = "Failed to retrieve the authentication URL. Please try again.";
  331. debugLog("Authentication URL not found after $maxAttempts attempts", $debugWeb, $debugLogFile);
  332. }
  333. }
  334. }
  335. }
  336. }
  337. } elseif ($step === 3 && isset($_POST['auth_redirect'])) {
  338. debugSession("Processing redirect URL");
  339. // number tres ... redirect url processing
  340. $authRedirect = trim($_POST['auth_redirect']);
  341. $email = $_SESSION['email'];
  342. $sessionId = $_SESSION['sessionId'];
  343. // send the redirect URL to the auth-injector (or by this point known as emailproxy-ui.py backend)
  344. $command = [
  345. 'type' => 'redirect_url',
  346. 'session_id' => $sessionId,
  347. 'email' => $email,
  348. 'redirect_url' => $authRedirect
  349. ];
  350. $response = sendCommandToAuthInjector($command, $debugWeb, $debugLogFile);
  351. if ($response['success']) {
  352. $command = [
  353. 'type' => 'merge_config',
  354. 'session_id' => $sessionId
  355. ];
  356. $mergeResponse = sendCommandToAuthInjector($command, $debugWeb, $debugLogFile);
  357. if ($mergeResponse['success']) {
  358. // checking if the user exists in the config ... again ... because stupid
  359. $is_existing = userExistsInConfig($configPath, $email);
  360. $_SESSION['added_email'] = $email;
  361. $_SESSION['auth_success'] = true;
  362. $_SESSION['form_success'] = true;
  363. $_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
  364. $_SESSION['step'] = 4; // numbero quatro oder so
  365. // save sessino and redirect to the same page ... yk updates yap yap
  366. session_write_close();
  367. header('Location: ' . $_SERVER['PHP_SELF']);
  368. exit;
  369. } else {
  370. $error = "Failed to merge configuration. Please try again.";
  371. }
  372. } else {
  373. $error = "Authentication failed. The URL you provided may be invalid or the authentication timed out.";
  374. $command = [
  375. 'type' => 'cleanup',
  376. 'session_id' => $sessionId
  377. ];
  378. sendCommandToAuthInjector($command, $debugWeb, $debugLogFile);
  379. }
  380. }
  381. // Idk what the following mystery is but its AI's spin on fixing and securing my user delete process
  382. // Add this after your existing POST handlers, before the closing } of the if ($_SERVER['REQUEST_METHOD'] === 'POST') block
  383. elseif (isset($_POST['remove_email']) && isset($_POST['confirm_password'])) {
  384. $email = trim($_POST['remove_email']);
  385. // uhm we uhm please actually want to delete an email and not accidentally match all config entries
  386. if (empty($email) && isset($_SESSION['email_for_removal'])) {
  387. $email = $_SESSION['email_for_removal'];
  388. unset($_SESSION['email_for_removal']);
  389. }
  390. $password = trim($_POST['confirm_password']);
  391. if (empty($email)) {
  392. $_SESSION['success_message'] = "Error: No email address specified for removal.";
  393. } else {
  394. // you very very sure the password is le correcto amigo ?
  395. if (verifyUserPassword($email, $password)) {
  396. // tell the auth-injector to brutally cut out the user from running config
  397. $command = [
  398. 'type' => 'remove_user',
  399. 'email' => $email
  400. ];
  401. $response = sendCommandToAuthInjector($command, $debugWeb, $debugLogFile);
  402. if ($response['success']) {
  403. $_SESSION['success_message'] = "Account $email has been successfully removed from the email proxy.";
  404. } else {
  405. $_SESSION['success_message'] = "Failed to remove account. Error: " . ($response['error'] ?? 'Unknown error');
  406. }
  407. } else {
  408. $_SESSION['success_message'] = "Password verification failed. If you need assistance, please contact " .
  409. ($config['SYSADMIN_EMAIL'] ?? 'your system administrator');
  410. }
  411. }
  412. // redir to first page (maybe clear session ? idk yet)
  413. header('Location: ' . $_SERVER['PHP_SELF']);
  414. exit;
  415. }
  416. }
  417. }
  418. ?>
  419. <!DOCTYPE html>
  420. <html lang="en">
  421. <head>
  422. <meta charset="UTF-8">
  423. <title>Emailproxy Auth Panel</title>
  424. <style>
  425. body {
  426. font-family: Arial, sans-serif;
  427. max-width: 800px;
  428. margin: 0 auto;
  429. padding: 20px;
  430. }
  431. .error {
  432. color: red;
  433. font-weight: bold;
  434. }
  435. .success {
  436. color: green;
  437. font-weight: bold;
  438. }
  439. .form-group {
  440. margin-bottom: 15px;
  441. }
  442. label {
  443. display: block;
  444. margin-bottom: 5px;
  445. }
  446. input[type="text"],
  447. input[type="email"],
  448. input[type="password"] {
  449. width: 100%;
  450. padding: 8px;
  451. box-sizing: border-box;
  452. }
  453. button {
  454. padding: 10px 15px;
  455. background-color: #4CAF50;
  456. color: white;
  457. border: none;
  458. cursor: pointer;
  459. }
  460. button:hover {
  461. background-color: #45a049;
  462. }
  463. .auth-url {
  464. word-break: break-all;
  465. background-color: #f5f5f5;
  466. padding: 10px;
  467. border: 1px solid #ddd;
  468. }
  469. .success-container {
  470. max-width: 700px;
  471. margin: 0 auto;
  472. }
  473. .mail-settings {
  474. background-color: #f9f9f9;
  475. border: 1px solid #ddd;
  476. border-radius: 5px;
  477. padding: 20px;
  478. margin: 20px 0;
  479. }
  480. .settings-container {
  481. display: flex;
  482. justify-content: space-between;
  483. flex-wrap: wrap;
  484. }
  485. .settings-box {
  486. flex: 1;
  487. min-width: 250px;
  488. padding: 10px;
  489. margin: 5px;
  490. background: white;
  491. border: 1px solid #eee;
  492. border-radius: 5px;
  493. }
  494. .settings-box h5 {
  495. margin-top: 0;
  496. color: #333;
  497. border-bottom: 1px solid #eee;
  498. padding-bottom: 10px;
  499. }
  500. .settings-box ul {
  501. list-style: none;
  502. padding-left: 0;
  503. }
  504. .settings-box li {
  505. margin-bottom: 8px;
  506. }
  507. .note {
  508. font-style: italic;
  509. color: #666;
  510. margin-top: 20px;
  511. }
  512. .button {
  513. display: inline-block;
  514. padding: 10px 15px;
  515. background-color: #4CAF50;
  516. color: white;
  517. text-decoration: none;
  518. border-radius: 4px;
  519. margin-top: 10px;
  520. }
  521. .button:hover {
  522. background-color: #45a049;
  523. }
  524. // Add this to your existing <style> section
  525. .actions-container {
  526. margin-top: 30px;
  527. border-top: 1px solid #eee;
  528. padding-top: 20px;
  529. }
  530. .remove-account {
  531. margin-top: 30px;
  532. padding: 15px;
  533. background-color: #fff4f4;
  534. border: 1px solid #ffdddd;
  535. border-radius: 5px;
  536. }
  537. .remove-account h4 {
  538. color: #cc0000;
  539. margin-top: 0;
  540. }
  541. .button.danger {
  542. background-color: #d9534f;
  543. }
  544. .button.danger:hover {
  545. background-color: #c9302c;
  546. }
  547. </style>
  548. </head>
  549. <body>
  550. <h2>OAutsch Sucks Authorization Panel</h2>
  551. <p>for people who hate 2FA, Microsoft and overcomplicated E-Mail.</p>
  552. <p>Made with love for PHP <br> and PURE RAGE AND HATRED FOR AZURE, TEAMS, EXCHANGE AND MICRO$SOFT <br> by UMTS at <a href="https://teleco.ch">teleco</a></p>
  553. <hr>
  554. <?php if ($error): ?>
  555. <p class="error"><?= htmlspecialchars($error) ?></p>
  556. <?php endif; ?>
  557. <?php if ($success): ?>
  558. <p class="success"><?= htmlspecialchars($success) ?></p>
  559. <?php endif; ?>
  560. <?php if ($step === 1): ?>
  561. <form method="POST">
  562. <div class="form-group">
  563. <label>CAPTCHA: <?= isset($_SESSION['captcha']) ? $_SESSION['captcha'] : rand(1000, 9999) ?></label>
  564. <input type="text" name="captcha" required placeholder="Enter the CAPTCHA code">
  565. </div>
  566. <input type="hidden" name="form_token" value="<?= $_SESSION['form_token'] ?>">
  567. <button type="submit">Start Authentication</button>
  568. </form>
  569. <?php elseif ($step === 2): ?>
  570. <form method="POST">
  571. <div class="form-group">
  572. <label>Email Address:</label>
  573. <input type="email" name="email" required placeholder="Enter your email address">
  574. </div>
  575. <div class="form-group">
  576. <label>Password:</label>
  577. <input type="password" name="password" required placeholder="Enter your password">
  578. </div>
  579. <input type="hidden" name="form_token" value="<?= $_SESSION['form_token'] ?>">
  580. <button type="submit">Submit</button>
  581. </form>
  582. <?php elseif ($step === 3): ?>
  583. <p><strong>Please visit the following URL to complete authentication:</strong></p>
  584. <div class="auth-url">
  585. <a href="<?= htmlspecialchars($_SESSION['authUrl']) ?>" target="_blank"><?= htmlspecialchars($_SESSION['authUrl']) ?></a>
  586. </div>
  587. <p>After completing the authentication process, you will be redirected to a page with a final URL. Copy that URL and paste it below:</p>
  588. <form method="POST">
  589. <div class="form-group">
  590. <label>Paste the redirected URL here:</label>
  591. <input type="text" name="auth_redirect" required placeholder="Paste the final URL here">
  592. </div>
  593. <input type="hidden" name="form_token" value="<?= $_SESSION['form_token'] ?>">
  594. <button type="submit">Complete Authentication</button>
  595. </form>
  596. <?php elseif ($step === 4): ?>
  597. <div class="success-container">
  598. <h3>Success!</h3>
  599. <p class="success">Your account <strong><?= htmlspecialchars($_SESSION['added_email'] ?? '') ?></strong> exists on the email proxy.</p>
  600. <div class="mail-settings">
  601. <h4>Mail Client Configuration</h4>
  602. <div class="settings-container">
  603. <div class="settings-box">
  604. <h5>Incoming Mail Server (<?= htmlspecialchars($mailImapProtocol) ?>)</h5>
  605. <ul>
  606. <li><strong>Server:</strong> <?= htmlspecialchars($mailServerName) ?></li>
  607. <li><strong>Port:</strong> <?= htmlspecialchars($mailImapPort) ?></li>
  608. <li><strong>Security:</strong> <?= $mailImapSsl ? 'SSL/TLS' : 'None' ?></li>
  609. <li><strong>Username:</strong> <?= htmlspecialchars($_SESSION['added_email'] ?? 'Your full email address') ?></li>
  610. <li><strong>Authentication:</strong> Normal Password</li>
  611. </ul>
  612. </div>
  613. <div class="settings-box">
  614. <h5>Outgoing Mail Server (<?= htmlspecialchars($mailSmtpProtocol) ?>)</h5>
  615. <ul>
  616. <li><strong>Server:</strong> <?= htmlspecialchars($mailServerName) ?></li>
  617. <li><strong>Port:</strong> <?= htmlspecialchars($mailSmtpPort) ?></li>
  618. <li><strong>Security:</strong> <?= $mailSmtpSsl ? 'SSL/TLS' : 'None' ?></li>
  619. <li><strong>Username:</strong> <?= htmlspecialchars($_SESSION['added_email'] ?? 'Your full email address') ?></li>
  620. <li><strong>Authentication:</strong> Normal Password</li>
  621. </ul>
  622. </div>
  623. </div>
  624. <p class="note">Use your defined password to sign into the proxy server (can differ from OAuth Providers account password).</p>
  625. </div>
  626. <div class="actions-container">
  627. <p><a href="<?= $_SERVER['PHP_SELF'] ?>" class="button">Add Another Account</a></p>
  628. <div class="remove-account">
  629. <h4>Remove Account</h4>
  630. <p>If you wish to remove this account from the email proxy, please confirm your password below.</p>
  631. <form method="POST" onsubmit="return confirm('Are you sure?')">
  632. <div class="form-group">
  633. <label>Confirm Password:</label>
  634. <input type="password" name="confirm_password" required placeholder="Enter your password">
  635. </div>
  636. <input type="hidden" name="remove_email" value="<?= htmlspecialchars($_SESSION['added_email'] ?? '') ?>">
  637. <?php $form_token = $_SESSION['form_token']; ?>
  638. <input type="hidden" name="form_token" value="<?= $form_token ?>">
  639. <button type="submit" class="button danger">Remove Account from Proxy</button>
  640. </form>
  641. </div>
  642. </div>
  643. </div>
  644. <?php
  645. $email_for_removal = $_SESSION['added_email'] ?? '';
  646. // Make new token before bye bye old one
  647. $new_token = bin2hex(random_bytes(32));
  648. // clean up le session after super premio success in hating ms
  649. $_SESSION = [];
  650. $_SESSION['captcha'] = rand(1000, 9999);
  651. $_SESSION['form_token'] = $new_token;
  652. // keep token for the next form just in case doe
  653. $_SESSION['previous_form_token'] = $form_token;
  654. $_SESSION['email_for_removal'] = $email_for_removal;
  655. $step = 1;
  656. ?>
  657. <?php endif; ?>
  658. </body>
  659. </html>