Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Skip to content
ecloud_account_creator.php 7.37 KiB
Newer Older
<?php
require 'vendor/autoload.php';
require_once('language.php');
require_once('account_creator.php');
Akhil's avatar
Akhil committed
require_once('helpers.php');

use phpseclib3\Net\SSH2;

class ECloudAccountCreator implements AccountCreator
{
    private string $ecloudUrl;
    private string $ecloudAccountsApiUrl;
    private int $quotaInMB = 1024;

    public function __construct(string $ecloudUrl)
        $this->ecloudUrl = endsWith($ecloudUrl, "/") ? $ecloudUrl : $ecloudUrl . "/";
        $this->ecloudAccountsApiUrl = $this->ecloudUrl . 'apps/ecloud-accounts/api/';
        $quota = getenv('CLOUD_QUOTA_IN_MB');
        if ($quota !== false) {
            $this->quotaInMB = intval($quota);
        }
    public function validateData(object $userData): ValidatedData
    {
        $id = "e_cloud_account_data";
        try {
            // We use $userData->email as uid as it is set to username@domain
            if ($this->isUsernameTaken($userData->email)) {
                return new \ValidatedData($id, "error_account_taken");
Akhil's avatar
Akhil committed
            }
Akhil's avatar
Akhil committed
        } catch (\Error $_) {
            return new \ValidatedData($id, "error_server_side");
        }
        return new \ValidatedData($id, null);
    }

    private function isUsernameTaken(string $uid): bool
        $token = getenv('ECLOUD_ACCOUNTS_SECRET');

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");

        $data = array(
            "uid" => $uid,
            "token" => $token,
        );
        curl_setopt($ch, CURLOPT_URL, $this->ecloudAccountsApiUrl . 'user_exists');
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));

        $output = curl_exec($ch);
        $output = json_decode($output);
        $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if ($statusCode !== 200) {
            $err = curl_error($ch);
            throw new Error($err);
        }

        return $output;
Akhil's avatar
Akhil committed

Akhil's avatar
Akhil committed
    private function createHMEAlias(string $resultmail) : string
    {
        $token = getenv('COMMON_SERVICES_TOKEN');
        $url = getenv('COMMON_SERVICES_URL');
        $domain = getenv('DOMAIN');
        
        $endpoint = '/aliases/hide-my-email/';
        $url .= $endpoint . $resultmail;
        $data = array(
            "token" => $token,
            "domain" => $domain
        );

        $result = curlPostJSON($url, $data);
        $output = $result->output;
        if ($result->statusCode != 200) {
            $err = $output->message;
            throw new Error($err);
        }
        $alias = isset($output->emailAlias) ? $output->emailAlias : '';
        return $alias;
    }

    private function createNewDomainAlias(string $username, string $resultmail)
    {
        $token = getenv('COMMON_SERVICES_TOKEN');
        $url = getenv('COMMON_SERVICES_URL');
        $domain = getenv('ALIAS_DOMAIN');

        $endpoint = '/aliases/';
        $url .= $endpoint . $resultmail;

        $data = array(
            "token" => $token,
            "alias" => $username,
            "domain" => $domain
        );
        $result = curlPostJSON($url, $data);
        $output = $result->output;
        if ($result->statusCode != 200) {
            $err = $output->message;
            throw new Error($err);
        }
    }

    private function setAccountDataAtNextcloud(string $email, string $quota, string $recoveryEmail, string $hmeAlias)
Akhil's avatar
Akhil committed
    {
Akhil's avatar
Akhil committed
        $token = getenv('ECLOUD_ACCOUNTS_SECRET');

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");

        $data = array(
            "uid" => $email,
Akhil's avatar
Akhil committed
            "token" => $token,
Akhil's avatar
Akhil committed
            "email" => $email,
            "quota" => $quota,
Akhil's avatar
Akhil committed
            "recoveryEmail" => $recoveryEmail,
            "hmeAlias" => $hmeAlias
        curl_setopt($ch, CURLOPT_URL, $this->ecloudAccountsApiUrl . 'set_account_data');
Akhil's avatar
Akhil committed
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        $output = curl_exec($ch);
        $output = json_decode($output, false);
Akhil's avatar
Akhil committed
        $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        $answer = new \stdClass;
        $answer->success = true;

Akhil's avatar
Akhil committed
        $errorNotEmpty = !empty($output->error);
        $isRecoveryEmailError = $errorNotEmpty && $output->error === 'error_setting_recovery';
        $isHmeError = $errorNotEmpty && $output->error === 'error_adding_hme_alias';

        if ($isRecoveryEmailError) {
            $message = 'Setting recovery email of user ' . $email . ' failed with status code: ' . $statusCode . '(recovery email: ' . $recoveryEmail . ')' . PHP_EOL;
            error_log($message, 0);
        }
        if ($isHmeError) {
            $message = 'Setting HME alias of user ' . $email . ' failed with status code: ' . $statusCode . '(HME alias: ' . $hmeAlias . ')' . PHP_EOL;
            error_log($message, 0);
        }

Akhil's avatar
Akhil committed
        if ($statusCode !== 200) {
Akhil's avatar
Akhil committed
            // Don't fail if recovery email or hide-my-email alias not set correctly
            $answer->success = $isRecoveryEmailError || $isHmeError;
Akhil's avatar
Akhil committed
            $answer->type = $errorNotEmpty ? $output->error : 'error_creating_account';
        }

        return $answer;
    }

Akhil's avatar
Akhil committed
    private function createMailAccount($resultmail, $username, $pw, $pw2, $name, $quota, $authmail, ?string $referrerCode = null)
    {
        global $strings;
        $PF_HOSTNAME = "postfixadmin";
        $PF_USER = "pfexec";
        $PF_PWD = getenv("POSTFIXADMIN_SSH_PASSWORD");

        $ssh = new SSH2($PF_HOSTNAME);
        if (!$ssh->login($PF_USER, $PF_PWD)) {
            $error_string = $strings["error_server_side"];
            sendAPIResponse(500, createAPIResponse("general", $error_string));
        }


        // 1 - create the account
Akhil's avatar
Akhil committed
        $creationFeedBack = explode("\n", $ssh->exec('/postfixadmin/scripts/postfixadmin-cli mailbox add ' . escapeshellarg($resultmail) . ' --password ' . escapeshellarg($pw) . ' --password2 ' . escapeshellarg($pw2) . ' --name ' . escapeshellarg($name) . ' --email_other ' . escapeshellarg($authmail) . ' --quota ' . $quota . ' --active 1 --welcome-mail 0 2>&1'));
        $isCreated = preg_grep('/added/', $creationFeedBack);
        $answer = new \stdClass();
        if (empty($isCreated)) {
            // There was an error during account creation on PFA side, return it
            $answer->success = false;
            $answer->type = "error_creating_account";
            return $answer;
        } else {
            // 2 - the account was created, set some settings
Akhil's avatar
Akhil committed
            $hmeAlias = '';
            try {
                $hmeAlias = $this->createHMEAlias($resultmail);
                $this->createNewDomainAlias($username, $resultmail);
            } catch (Error $e) {
                error_log('Error during alias creation for user: ' . $resultmail . ' : ' . $e->getMessage());
            }
            $answer = $this->setAccountDataAtNextcloud($resultmail, $quota . ' MB', $authmail, $hmeAlias);
Akhil's avatar
Akhil committed
            return $answer;
        }
    }

    public function tryToCreate(object $userData)
    {
        global $strings;
        $pw = $userData->password;
Akhil's avatar
Akhil committed
        $answer = $this->createMailAccount($userData->email, $userData->username, $pw, $pw, $userData->name, $this->quotaInMB, $userData->authmail, $userData->referrerCode);
        if ($answer->success === false) {
            sendAPIResponse(400, createAPIResponse("general", $strings[$answer->type]));
        }
    }
Akhil's avatar
Akhil committed
}