Correct a parameter order swap in "diffusion.historyquery" for Mercurial
[phabricator.git] / src / applications / conduit / method / ConduitConnectConduitAPIMethod.php
blob8119deb86076f1be1a39c420fb86fec58e7b675e
1 <?php
3 final class ConduitConnectConduitAPIMethod extends ConduitAPIMethod {
5 public function getAPIMethodName() {
6 return 'conduit.connect';
9 public function shouldRequireAuthentication() {
10 return false;
13 public function shouldAllowUnguardedWrites() {
14 return true;
17 public function getMethodDescription() {
18 return pht('Connect a session-based client.');
21 protected function defineParamTypes() {
22 return array(
23 'client' => 'required string',
24 'clientVersion' => 'required int',
25 'clientDescription' => 'optional string',
26 'user' => 'optional string',
27 'authToken' => 'optional int',
28 'authSignature' => 'optional string',
29 'host' => 'deprecated',
33 protected function defineReturnType() {
34 return 'dict<string, any>';
37 protected function defineErrorTypes() {
38 return array(
39 'ERR-BAD-VERSION' => pht(
40 'Client/server version mismatch. Upgrade your server or downgrade '.
41 'your client.'),
42 'NEW-ARC-VERSION' => pht(
43 'Client/server version mismatch. Upgrade your client.'),
44 'ERR-UNKNOWN-CLIENT' => pht('Client is unknown.'),
45 'ERR-INVALID-USER' => pht(
46 'The username you are attempting to authenticate with is not valid.'),
47 'ERR-INVALID-CERTIFICATE' => pht(
48 'Your authentication certificate for this server is invalid.'),
49 'ERR-INVALID-TOKEN' => pht(
50 "The challenge token you are authenticating with is outside of the ".
51 "allowed time range. Either your system clock is out of whack or ".
52 "you're executing a replay attack."),
53 'ERR-NO-CERTIFICATE' => pht('This server requires authentication.'),
57 protected function execute(ConduitAPIRequest $request) {
58 $client = $request->getValue('client');
59 $client_version = (int)$request->getValue('clientVersion');
60 $client_description = (string)$request->getValue('clientDescription');
61 $client_description = id(new PhutilUTF8StringTruncator())
62 ->setMaximumBytes(255)
63 ->truncateString($client_description);
64 $username = (string)$request->getValue('user');
66 switch ($client) {
67 case 'arc':
68 $server_version = 6;
69 $supported_versions = array(
70 $server_version => true,
71 // Client version 5 introduced "user.query" call
72 4 => true,
73 // Client version 6 introduced "diffusion.getlintmessages" call
74 5 => true,
77 if (empty($supported_versions[$client_version])) {
78 if ($server_version < $client_version) {
79 $ex = new ConduitException('ERR-BAD-VERSION');
80 $ex->setErrorDescription(
81 pht(
82 "Your '%s' client version is '%d', which is newer than the ".
83 "server version, '%d'. Upgrade your Phabricator install.",
84 'arc',
85 $client_version,
86 $server_version));
87 } else {
88 $ex = new ConduitException('NEW-ARC-VERSION');
89 $ex->setErrorDescription(
90 pht(
91 'A new version of arc is available! You need to upgrade '.
92 'to connect to this server (you are running version '.
93 '%d, the server is running version %d).',
94 $client_version,
95 $server_version));
97 throw $ex;
99 break;
100 default:
101 // Allow new clients by default.
102 break;
105 $token = $request->getValue('authToken');
106 $signature = $request->getValue('authSignature');
108 $user = id(new PhabricatorUser())->loadOneWhere('username = %s', $username);
109 if (!$user) {
110 throw new ConduitException('ERR-INVALID-USER');
113 $session_key = null;
114 if ($token && $signature) {
115 $threshold = 60 * 15;
116 $now = time();
117 if (abs($token - $now) > $threshold) {
118 throw id(new ConduitException('ERR-INVALID-TOKEN'))
119 ->setErrorDescription(
120 pht(
121 'The request you submitted is signed with a timestamp, but that '.
122 'timestamp is not within %s of the current time. The '.
123 'signed timestamp is %s (%s), and the current server time is '.
124 '%s (%s). This is a difference of %s seconds, but the '.
125 'timestamp must differ from the server time by no more than '.
126 '%s seconds. Your client or server clock may not be set '.
127 'correctly.',
128 phutil_format_relative_time($threshold),
129 $token,
130 date('r', $token),
131 $now,
132 date('r', $now),
133 ($token - $now),
134 $threshold));
136 $valid = sha1($token.$user->getConduitCertificate());
137 if (!phutil_hashes_are_identical($valid, $signature)) {
138 throw new ConduitException('ERR-INVALID-CERTIFICATE');
140 $session_key = id(new PhabricatorAuthSessionEngine())->establishSession(
141 PhabricatorAuthSession::TYPE_CONDUIT,
142 $user->getPHID(),
143 $partial = false);
144 } else {
145 throw new ConduitException('ERR-NO-CERTIFICATE');
148 return array(
149 'connectionID' => mt_rand(),
150 'sessionKey' => $session_key,
151 'userPHID' => $user->getPHID(),