Page MenuHomec4science

PhabricatorUserEmail.php
No OneTemporary

File Metadata

Created
Sun, Aug 25, 15:54

PhabricatorUserEmail.php

<?php
/**
* @task restrictions Domain Restrictions
* @task email Email About Email
*/
final class PhabricatorUserEmail extends PhabricatorUserDAO {
protected $userPHID;
protected $address;
protected $isVerified;
protected $isPrimary;
protected $verificationCode;
const MAX_ADDRESS_LENGTH = 128;
protected function getConfiguration() {
return array(
self::CONFIG_COLUMN_SCHEMA => array(
'address' => 'sort128',
'isVerified' => 'bool',
'isPrimary' => 'bool',
'verificationCode' => 'text64?',
),
self::CONFIG_KEY_SCHEMA => array(
'address' => array(
'columns' => array('address'),
'unique' => true,
),
'userPHID' => array(
'columns' => array('userPHID', 'isPrimary'),
),
),
) + parent::getConfiguration();
}
public function getVerificationURI() {
return '/emailverify/'.$this->getVerificationCode().'/';
}
public function save() {
if (!$this->verificationCode) {
$this->setVerificationCode(Filesystem::readRandomCharacters(24));
}
return parent::save();
}
/* -( Domain Restrictions )------------------------------------------------ */
/**
* @task restrictions
*/
public static function isValidAddress($address) {
if (strlen($address) > self::MAX_ADDRESS_LENGTH) {
return false;
}
// Very roughly validate that this address isn't so mangled that a
// reasonable piece of code might completely misparse it. In particular,
// the major risks are:
//
// - `PhutilEmailAddress` needs to be able to extract the domain portion
// from it.
// - Reasonable mail adapters should be hard-pressed to interpret one
// address as several addresses.
//
// To this end, we're roughly verifying that there's some normal text, an
// "@" symbol, and then some more normal text.
$email_regex = '(^[a-z0-9_+.!-]+@[a-z0-9_+:.-]+\z)i';
if (!preg_match($email_regex, $address)) {
return false;
}
return true;
}
/**
* @task restrictions
*/
public static function describeValidAddresses() {
return pht(
"Email addresses should be in the form 'user@domain.com'. The maximum ".
"length of an email address is %d character(s).",
new PhutilNumber(self::MAX_ADDRESS_LENGTH));
}
/**
* @task restrictions
*/
public static function isAllowedAddress($address) {
if (!self::isValidAddress($address)) {
return false;
}
$allowed_domains = PhabricatorEnv::getEnvConfig('auth.email-domains');
if (!$allowed_domains) {
return true;
}
$addr_obj = new PhutilEmailAddress($address);
$domain = $addr_obj->getDomainName();
if (!$domain) {
return false;
}
$lower_domain = phutil_utf8_strtolower($domain);
foreach ($allowed_domains as $allowed_domain) {
$lower_allowed = phutil_utf8_strtolower($allowed_domain);
if ($lower_allowed === $lower_domain) {
return true;
}
}
return false;
}
/**
* @task restrictions
*/
public static function describeAllowedAddresses() {
$domains = PhabricatorEnv::getEnvConfig('auth.email-domains');
if (!$domains) {
return null;
}
if (count($domains) == 1) {
return 'Email address must be @'.head($domains);
} else {
return 'Email address must be at one of: '.
implode(', ', $domains);
}
}
/**
* Check if this install requires email verification.
*
* @return bool True if email addresses must be verified.
*
* @task restrictions
*/
public static function isEmailVerificationRequired() {
// NOTE: Configuring required email domains implies required verification.
return PhabricatorEnv::getEnvConfig('auth.require-email-verification') ||
PhabricatorEnv::getEnvConfig('auth.email-domains');
}
/* -( Email About Email )-------------------------------------------------- */
/**
* Send a verification email from $user to this address.
*
* @param PhabricatorUser The user sending the verification.
* @return this
* @task email
*/
public function sendVerificationEmail(PhabricatorUser $user) {
$username = $user->getUsername();
$address = $this->getAddress();
$link = PhabricatorEnv::getProductionURI($this->getVerificationURI());
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
$signature = null;
if (!$is_serious) {
$signature = <<<EOSIGNATURE
Get Well Soon,
Phabricator
EOSIGNATURE;
}
$body = <<<EOBODY
Hi {$username},
Please verify that you own this email address ({$address}) by clicking this
link:
{$link}
{$signature}
EOBODY;
id(new PhabricatorMetaMTAMail())
->addRawTos(array($address))
->setForceDelivery(true)
->setSubject('[Phabricator] Email Verification')
->setBody($body)
->setRelatedPHID($user->getPHID())
->saveAndSend();
return $this;
}
/**
* Send a notification email from $user to this address, informing the
* recipient that this is no longer their account's primary address.
*
* @param PhabricatorUser The user sending the notification.
* @param PhabricatorUserEmail New primary email address.
* @return this
* @task email
*/
public function sendOldPrimaryEmail(
PhabricatorUser $user,
PhabricatorUserEmail $new) {
$username = $user->getUsername();
$old_address = $this->getAddress();
$new_address = $new->getAddress();
$body = <<<EOBODY
Hi {$username},
This email address ({$old_address}) is no longer your primary email address.
Going forward, Phabricator will send all email to your new primary email
address ({$new_address}).
EOBODY;
id(new PhabricatorMetaMTAMail())
->addRawTos(array($old_address))
->setForceDelivery(true)
->setSubject('[Phabricator] Primary Address Changed')
->setBody($body)
->setFrom($user->getPHID())
->setRelatedPHID($user->getPHID())
->saveAndSend();
}
/**
* Send a notification email from $user to this address, informing the
* recipient that this is now their account's new primary email address.
*
* @param PhabricatorUser The user sending the verification.
* @return this
* @task email
*/
public function sendNewPrimaryEmail(PhabricatorUser $user) {
$username = $user->getUsername();
$new_address = $this->getAddress();
$body = <<<EOBODY
Hi {$username},
This is now your primary email address ({$new_address}). Going forward,
Phabricator will send all email here.
EOBODY;
id(new PhabricatorMetaMTAMail())
->addRawTos(array($new_address))
->setForceDelivery(true)
->setSubject('[Phabricator] Primary Address Changed')
->setBody($body)
->setFrom($user->getPHID())
->setRelatedPHID($user->getPHID())
->saveAndSend();
return $this;
}
}

Event Timeline