Page MenuHomePhabricator

SecureShieldsUpAction.php
No OneTemporary

SecureShieldsUpAction.php

<?php
final class SecureShieldsUpAction
extends HeraldAction {
const ACTIONCONST = 'secure.shields-up';
const DO_SHIELD = 'do.secure.shields';
public function getHeraldActionName() {
return pht('Activate Advanced Cyber Defenses');
}
public function getActionGroupKey() {
return HeraldUtilityActionGroup::ACTIONGROUPKEY;
}
public function supportsObject($object) {
return ($object instanceof ManiphestTask);
}
public function supportsRuleType($rule_type) {
return ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL);
}
public function applyEffect($object, HeraldEffect $effect) {
// This is super janky but we don't currently get a reliable acting user.
$last_actor_row = queryfx_one(
$object->establishConnection('r'),
'SELECT authorPHID FROM %T WHERE objectPHID = %s ORDER BY id DESC
LIMIT 1',
id(new ManiphestTransaction())->getTableName(),
$object->getPHID());
if (!$last_actor_row) {
return;
}
$actor = id(new PhabricatorPeopleQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs(array($last_actor_row['authorPHID']))
->executeOne();
if (!$actor) {
return;
}
if ($this->isFriendlyUser($actor)) {
return;
}
if (!$this->isHostileObject($object)) {
return;
}
$this->quarantineUser($actor);
$this->quarantineObject($object);
$this->logEffect(self::DO_SHIELD);
}
public function getHeraldActionStandardType() {
return self::STANDARD_NONE;
}
public function renderActionDescription($value) {
return pht('Shields up.');
}
protected function getActionEffectMap() {
return array(
self::DO_SHIELD => array(
'icon' => 'fa-umbrella',
'color' => 'indigo',
'name' => pht('Shields Up'),
),
);
}
protected function renderActionEffectDescription($type, $data) {
switch ($type) {
case self::DO_SHIELD:
return pht('Shields up.');
}
}
private function isFriendlyUser(PhabricatorUser $user) {
if ($user->getIsAdmin()) {
return true;
}
return false;
}
private function isHostileObject($object) {
$content = array();
if ($object instanceof ManiphestTask) {
$content[] = $object->getTitle();
$content[] = $object->getDescription();
}
$content = implode("\n\n", $content);
$patterns = array();
// Phone numbers that we'll reject.
$numbers = array(
'8443133901',
'8007909186',
'800059007',
'8008101018',
'8002044122',
'8007992667',
'8557092847',
'8007789936',
'8000903859',
'8000314244',
'8008057863',
);
if (self::matchPhoneNumbers($numbers, $content)) {
return true;
}
return false;
}
public static function matchPhoneNumbers(array $numbers, $content) {
$swap = array(
'o' => '0',
'O' => '0',
'@' => '0',
'()' => '0',
'i' => '1',
'I' => '1',
'|' => '1',
'l' => '1',
);
$content = str_replace(
array_keys($swap),
array_values($swap),
$content);
foreach ($numbers as $number) {
$regex = array();
for ($ii = 0; $ii < strlen($number); $ii++) {
$regex[] = $number[$ii];
}
// Reject all variants of the number with other random punctuation or
// spaces between the digits.
$regex = implode('[^\\d]{0,6}', $regex);
$patterns[] = '/'.$regex.'/';
}
foreach ($patterns as $pattern) {
if (preg_match($pattern, $content)) {
return true;
}
}
return false;
}
private function quarantineUser(PhabricatorUser $user) {
// For now, just log the user out of all their sessions so it's not a big
// deal if we hit a friendly user by accident. We could make this more
// extreme in the future.
$sessions = id(new PhabricatorAuthSessionQuery())
->setViewer($user)
->withIdentityPHIDs(array($user->getPHID()))
->execute();
foreach ($sessions as $session) {
$session->delete();
}
}
private function quarantineObject($object) {
$title = $object->getTitle();
$new_title = '<QUARANTINED> '.$title;
$object
->setTitle($new_title)
->setViewPolicy(PhabricatorPolicies::POLICY_ADMIN)
->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN)
->save();
}
}

File Metadata

Mime Type
text/x-php
Expires
Sat, Jun 12, 7:32 AM (1 d, 23 h)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
3395416
Default Alt Text
SecureShieldsUpAction.php (4 KB)

Event Timeline