Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / applications / auth / future / PhabricatorDuoFuture.php
blob1e70ec2a578f5c798a65edbcdd76640af655ddfb
1 <?php
3 final class PhabricatorDuoFuture
4 extends FutureProxy {
6 private $future;
8 private $integrationKey;
9 private $secretKey;
10 private $apiHostname;
12 private $httpMethod = 'POST';
13 private $method;
14 private $parameters;
15 private $timeout;
17 public function __construct() {
18 parent::__construct(null);
21 public function setIntegrationKey($integration_key) {
22 $this->integrationKey = $integration_key;
23 return $this;
26 public function setSecretKey(PhutilOpaqueEnvelope $key) {
27 $this->secretKey = $key;
28 return $this;
31 public function setAPIHostname($hostname) {
32 $this->apiHostname = $hostname;
33 return $this;
36 public function setMethod($method, array $parameters) {
37 $this->method = $method;
38 $this->parameters = $parameters;
39 return $this;
42 public function setTimeout($timeout) {
43 $this->timeout = $timeout;
44 return $this;
47 public function getTimeout() {
48 return $this->timeout;
51 public function setHTTPMethod($method) {
52 $this->httpMethod = $method;
53 return $this;
56 public function getHTTPMethod() {
57 return $this->httpMethod;
60 protected function getProxiedFuture() {
61 if (!$this->future) {
62 if ($this->integrationKey === null) {
63 throw new PhutilInvalidStateException('setIntegrationKey');
66 if ($this->secretKey === null) {
67 throw new PhutilInvalidStateException('setSecretKey');
70 if ($this->apiHostname === null) {
71 throw new PhutilInvalidStateException('setAPIHostname');
74 if ($this->method === null || $this->parameters === null) {
75 throw new PhutilInvalidStateException('setMethod');
78 $path = (string)urisprintf('/auth/v2/%s', $this->method);
80 $host = $this->apiHostname;
81 $host = phutil_utf8_strtolower($host);
83 $data = $this->parameters;
84 $date = date('r');
86 $http_method = $this->getHTTPMethod();
88 ksort($data);
89 $data_parts = phutil_build_http_querystring($data);
91 $corpus = array(
92 $date,
93 $http_method,
94 $host,
95 $path,
96 $data_parts,
98 $corpus = implode("\n", $corpus);
100 $signature = hash_hmac(
101 'sha1',
102 $corpus,
103 $this->secretKey->openEnvelope());
104 $signature = new PhutilOpaqueEnvelope($signature);
106 if ($http_method === 'GET') {
107 $uri_data = $data;
108 $body_data = array();
109 } else {
110 $uri_data = array();
111 $body_data = $data;
114 $uri = id(new PhutilURI('', $uri_data))
115 ->setProtocol('https')
116 ->setDomain($host)
117 ->setPath($path);
119 $future = id(new HTTPSFuture($uri, $body_data))
120 ->setHTTPBasicAuthCredentials($this->integrationKey, $signature)
121 ->setMethod($http_method)
122 ->addHeader('Accept', 'application/json')
123 ->addHeader('Date', $date);
125 $timeout = $this->getTimeout();
126 if ($timeout) {
127 $future->setTimeout($timeout);
130 $this->future = $future;
133 return $this->future;
136 protected function didReceiveResult($result) {
137 list($status, $body, $headers) = $result;
139 if ($status->isError()) {
140 throw $status;
143 try {
144 $data = phutil_json_decode($body);
145 } catch (PhutilJSONParserException $ex) {
146 throw new PhutilProxyException(
147 pht('Expected JSON response from Duo.'),
148 $ex);
151 return $data;