diff --git a/Dockerfile b/Dockerfile index 3f723128de5ead65d9619696cac3d7ebffd9cec9..fe248b55181f040c4d6c8ebab1b9900bb1feaeed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ COPY --from=composer:1.8 /usr/bin/composer /usr/bin/composer RUN apt-get update && apt-get install -y --no-install-recommends git unzip \ # these params are recommended for installing untrusted extensions # https://getcomposer.org/doc/faqs/how-to-install-untrusted-packages-safely.md - && composer require --no-plugins --no-scripts pear/mail pear/net_smtp pear/auth_sasl pear/mail_mime \ + && composer require --no-plugins --no-scripts pear/mail pear/net_smtp pear/auth_sasl pear/mail_mime phpseclib/phpseclib curl/curl \ && apt-get remove -y git unzip \ && rm -rf /var/lib/apt/lists/* \ # composer shouldnt be present in production setups diff --git a/htdocs/postDelete.php b/htdocs/postDelete.php new file mode 100644 index 0000000000000000000000000000000000000000..053489e3769aaa956ad2035dee74e7efe85de674 --- /dev/null +++ b/htdocs/postDelete.php @@ -0,0 +1,196 @@ + $line) { + if (preg_match($regex, $line) == 1) { + // temporarely save the line for later use on the file below + $tmpLine = $line; + + unset($lines[$key]); + } + } + if ($tmpLine) { + //Unique line was found, save $AUTH_FILE_DONE with exclusive lock on the file + $lines[] = ""; + $data = implode(PHP_EOL, $lines); + ftruncate($lockedFileDone, 0); + fwrite($lockedFileDone, $data); + fclose($lockedFileDone); + + /** + * for $AUTH_FILE, line pattern is : + * MAIL_USED_FOR_REGISTRATION:SECRET + * + * remove ALL lines on this file based on MAIL_USED_FOR_REGISTRATION + * + * get MAIL_USED_FOR_REGISTRATION from $tmpLine stored earlier + * create regex pattern to prevent false positives :only lines STARTING with $mail + */ + $mail = strtok($tmpLine, ":"); + $regex = "/^" . preg_quote($mail) . ":/"; + + $lockedFile = fopen($AUTH_FILE, "c", LOCK_EX); + // c mode to open the file in write mode WITH EXCLUSIVE LOCK, but DO NOT truncate it + + // find and delete all the line containing this MAIL_USED_FOR_REGISTRATION + $lines = file($AUTH_FILE, FILE_IGNORE_NEW_LINES); + foreach ($lines as $key => $line) { + if (preg_match($regex, $line) == 1) unset($lines[$key]); + } + $lines[] = ""; + $data = implode(PHP_EOL, $lines); + //save $AUTH_FILE with exclusive lock on the file + ftruncate($lockedFile, 0); + fwrite($lockedFile, $data); + fclose($lockedFile); + + // return MAIL_USED_FOR_REGISTRATION, 2BE used by purgeWebsiteFiles function + return $mail; + } else return null; //NO line was found for this user + +} + +/** + * function to : + * - connect to postfixadmin container to delete user account, using postfixadmin-cli + * - delete account's maildir as mail volume is now bind mounted to PFA container too + * + */ +function deleteMailAccount() +{ + + $PF_HOSTNAME = "postfixadmin"; + $PF_USER = "pfexec"; + $PF_PWD = getenv("POSTFIXADMIN_SSH_PASSWORD"); + + // Dir where /mnt/repo-base/volumes/mail/ is bind mounted on postfixadmin container + $baseDir = "/var/mail/vhosts/"; + + global $user2delete, $userOnly, $domain; + + if (($domain != "") || ($userOnly != "")) { + $ssh = new SSH2($PF_HOSTNAME); + if (!$ssh->login($PF_USER, $PF_PWD)) { + exit('Login Failed'); + } + + $ssh->exec('/postfixadmin/scripts/postfixadmin-cli mailbox delete "' . $user2delete . '"'); + + $ssh->exec('sudo /usr/local/bin/postfixadmin-mailbox-postdeletion.sh ' . $userOnly . " " . $domain); + + // verify it's done + $delDbConfirm = $ssh->exec('/postfixadmin/scripts/postfixadmin-cli mailbox view "' . $user2delete . '" 2>&1 |grep "not valid"'); + + // build path to check deletion + $fullPath = $baseDir . $domain . "/" . $userOnly; + $delDirConfirm = $ssh->exec('[ ! -d "' . $fullPath . '" ] && echo "DELETED"'); + + if (($delDbConfirm == "Error: The EMAIL is not valid!") && ($delDirConfirm == "DELETED")) { + return true; + } else return false; // one of the deletion did not go well! + } else return null; // $domain OR $userOnly empty, do nothing!! + +} + +/** + * !!! specific to ecloud production config !!! + * !!! not to be implemented in self_hosting !!! + * + * function to purge remaining files on e.foundation website + * preventing users to re register on /e/ website registration form + * find&delete lines with email used for registration, I.E. external email + * grab external mail from $AUTH_FILE + * + */ +function purgeWebsiteFiles($externalMailAddress) +{ + + $E_WEBSITE = "https://e.foundation"; + $E_DELETE_SCRIPT = "/delete_email_invite.php"; + $E_SECRET = getenv("WEBSITE_SECRET"); + + + $E_url = $E_WEBSITE . $E_DELETE_SCRIPT; + $curl = new Curl\Curl(); + $curl->post($E_url, array( + 'mail' => $externalMailAddress, + 'auth' => $E_SECRET, + )); + if ($curl->error) { + return $curl->error_code; + } else { + return $curl->response; + } +} + +if (sha1($_POST['sec']) !== getenv("WELCOME_SECRET_SHA")) { + http_response_code(403); + exit(); +} else { + $user2delete = $_POST['uid']; + $exploded = explode("@", $user2delete); + $userOnly = $exploded[0]; + $domain = $exploded[1]; + + // STEP 1 : remove $user2delete from postfix database AND remove its mail folder + $mailDeletionReturn = deleteMailAccount(); + if ($mailDeletionReturn == true) { + /** + * mail DB account AND mailbox dir successfully deleted + * NO user data remaining on the server + * TODO : + * - fire mail for user to confirm deletion of his account is complete + * - handle onlyoffice part + * + */ + + } + // STEP 2 : Purge system files AUTH_FILE & AUTH_FILE_DONE + $registrationMail = purgeAccountFiles(); + + // !!! /e/ specific !!! + if (getenv("WEBSITE_SECRET") != "not_defined") { + // STEP 3 : Purge files on website's form + if ($registrationMail !== null) { + //only if we have a mail to delete + + purgeWebsiteFiles($registrationMail); + return true; + } else return false; // STEP 2 not done, not doing STEP 3 either + } +} \ No newline at end of file