Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / applications / conduit / storage / PhabricatorConduitToken.php
blobaa836cf623b580874712938508778d4e52621af8
1 <?php
3 final class PhabricatorConduitToken
4 extends PhabricatorConduitDAO
5 implements PhabricatorPolicyInterface {
7 protected $objectPHID;
8 protected $tokenType;
9 protected $token;
10 protected $expires;
12 private $object = self::ATTACHABLE;
14 const TYPE_STANDARD = 'api';
15 const TYPE_COMMANDLINE = 'cli';
16 const TYPE_CLUSTER = 'clr';
18 protected function getConfiguration() {
19 return array(
20 self::CONFIG_COLUMN_SCHEMA => array(
21 'tokenType' => 'text32',
22 'token' => 'text32',
23 'expires' => 'epoch?',
25 self::CONFIG_KEY_SCHEMA => array(
26 'key_object' => array(
27 'columns' => array('objectPHID', 'tokenType'),
29 'key_token' => array(
30 'columns' => array('token'),
31 'unique' => true,
33 'key_expires' => array(
34 'columns' => array('expires'),
37 ) + parent::getConfiguration();
40 public static function loadClusterTokenForUser(PhabricatorUser $user) {
41 if (!$user->isLoggedIn()) {
42 return null;
45 if ($user->hasConduitClusterToken()) {
46 return $user->getConduitClusterToken();
49 $tokens = id(new PhabricatorConduitTokenQuery())
50 ->setViewer($user)
51 ->withObjectPHIDs(array($user->getPHID()))
52 ->withTokenTypes(array(self::TYPE_CLUSTER))
53 ->withExpired(false)
54 ->execute();
56 // Only return a token if it has at least 5 minutes left before
57 // expiration. Cluster tokens cycle regularly, so we don't want to use
58 // one that's going to expire momentarily.
59 $now = PhabricatorTime::getNow();
60 $must_expire_after = $now + phutil_units('5 minutes in seconds');
62 $valid_token = null;
63 foreach ($tokens as $token) {
64 if ($token->getExpires() > $must_expire_after) {
65 $valid_token = $token;
66 break;
70 // We didn't find any existing tokens (or the existing tokens are all about
71 // to expire) so generate a new token.
72 if (!$valid_token) {
73 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
74 $valid_token = self::initializeNewToken(
75 $user->getPHID(),
76 self::TYPE_CLUSTER);
77 $valid_token->save();
78 unset($unguarded);
81 $user->attachConduitClusterToken($valid_token);
83 return $valid_token;
86 public static function initializeNewToken($object_phid, $token_type) {
87 $token = new PhabricatorConduitToken();
88 $token->objectPHID = $object_phid;
89 $token->tokenType = $token_type;
90 $token->expires = $token->getTokenExpires($token_type);
92 $secret = $token_type.'-'.Filesystem::readRandomCharacters(32);
93 $secret = substr($secret, 0, 32);
94 $token->token = $secret;
96 return $token;
99 public static function getTokenTypeName($type) {
100 $map = array(
101 self::TYPE_STANDARD => pht('Standard API Token'),
102 self::TYPE_COMMANDLINE => pht('Command Line API Token'),
103 self::TYPE_CLUSTER => pht('Cluster API Token'),
106 return idx($map, $type, $type);
109 public static function getAllTokenTypes() {
110 return array(
111 self::TYPE_STANDARD,
112 self::TYPE_COMMANDLINE,
113 self::TYPE_CLUSTER,
117 private function getTokenExpires($token_type) {
118 $now = PhabricatorTime::getNow();
119 switch ($token_type) {
120 case self::TYPE_STANDARD:
121 return null;
122 case self::TYPE_COMMANDLINE:
123 return $now + phutil_units('1 hour in seconds');
124 case self::TYPE_CLUSTER:
125 return $now + phutil_units('30 minutes in seconds');
126 default:
127 throw new Exception(
128 pht('Unknown Conduit token type "%s"!', $token_type));
132 public function getPublicTokenName() {
133 switch ($this->getTokenType()) {
134 case self::TYPE_CLUSTER:
135 return pht('Cluster API Token');
136 default:
137 return substr($this->getToken(), 0, 8).'...';
141 public function getObject() {
142 return $this->assertAttached($this->object);
145 public function attachObject(PhabricatorUser $object) {
146 $this->object = $object;
147 return $this;
151 /* -( PhabricatorPolicyInterface )----------------------------------------- */
154 public function getCapabilities() {
155 return array(
156 PhabricatorPolicyCapability::CAN_VIEW,
157 PhabricatorPolicyCapability::CAN_EDIT,
161 public function getPolicy($capability) {
162 return $this->getObject()->getPolicy($capability);
165 public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
166 return $this->getObject()->hasAutomaticCapability($capability, $viewer);
169 public function describeAutomaticCapability($capability) {
170 return pht(
171 'Conduit tokens inherit the policies of the user they authenticate.');