3 final class PhabricatorConduitToken
4 extends PhabricatorConduitDAO
5 implements PhabricatorPolicyInterface
{
12 private $object = self
::ATTACHABLE
;
14 const TYPE_STANDARD
= 'api';
15 const TYPE_COMMANDLINE
= 'cli';
16 const TYPE_CLUSTER
= 'clr';
18 protected function getConfiguration() {
20 self
::CONFIG_COLUMN_SCHEMA
=> array(
21 'tokenType' => 'text32',
23 'expires' => 'epoch?',
25 self
::CONFIG_KEY_SCHEMA
=> array(
26 'key_object' => array(
27 'columns' => array('objectPHID', 'tokenType'),
30 'columns' => array('token'),
33 'key_expires' => array(
34 'columns' => array('expires'),
37 ) + parent
::getConfiguration();
40 public static function loadClusterTokenForUser(PhabricatorUser
$user) {
41 if (!$user->isLoggedIn()) {
45 if ($user->hasConduitClusterToken()) {
46 return $user->getConduitClusterToken();
49 $tokens = id(new PhabricatorConduitTokenQuery())
51 ->withObjectPHIDs(array($user->getPHID()))
52 ->withTokenTypes(array(self
::TYPE_CLUSTER
))
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');
63 foreach ($tokens as $token) {
64 if ($token->getExpires() > $must_expire_after) {
65 $valid_token = $token;
70 // We didn't find any existing tokens (or the existing tokens are all about
71 // to expire) so generate a new token.
73 $unguarded = AphrontWriteGuard
::beginScopedUnguardedWrites();
74 $valid_token = self
::initializeNewToken(
81 $user->attachConduitClusterToken($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;
99 public static function getTokenTypeName($type) {
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() {
112 self
::TYPE_COMMANDLINE
,
117 private function getTokenExpires($token_type) {
118 $now = PhabricatorTime
::getNow();
119 switch ($token_type) {
120 case self
::TYPE_STANDARD
:
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');
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');
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;
151 /* -( PhabricatorPolicyInterface )----------------------------------------- */
154 public function getCapabilities() {
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) {
171 'Conduit tokens inherit the policies of the user they authenticate.');