Api.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. <?php
  2. # Copyright (c) 2013-2016, OVH SAS.
  3. # All rights reserved.
  4. #
  5. # Redistribution and use in source and binary forms, with or without
  6. # modification, are permitted provided that the following conditions are met:
  7. #
  8. # * Redistributions of source code must retain the above copyright
  9. # notice, this list of conditions and the following disclaimer.
  10. # * Redistributions in binary form must reproduce the above copyright
  11. # notice, this list of conditions and the following disclaimer in the
  12. # documentation and/or other materials provided with the distribution.
  13. # * Neither the name of OVH SAS nor the
  14. # names of its contributors may be used to endorse or promote products
  15. # derived from this software without specific prior written permission.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY OVH SAS AND CONTRIBUTORS ``AS IS'' AND ANY
  18. # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. # DISCLAIMED. IN NO EVENT SHALL OVH SAS AND CONTRIBUTORS BE LIABLE FOR ANY
  21. # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24. # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. /**
  28. * This file contains code about \Ovh\Api class
  29. */
  30. namespace MGModule\DNSManager2\mgLibs\custom\dns\submodules\OVH;
  31. use \GuzzleHttp\Client;
  32. use \GuzzleHttp\Stream\Stream;
  33. use \GuzzleHttp\Psr7\Request;
  34. use \GuzzleHttp\Psr7\Response;
  35. use \MGModule\DNSManager2\mgLibs\custom\dns\exceptions;
  36. /**
  37. * Wrapper to manage login and exchanges with simpliest Ovh API
  38. *
  39. * This class manage how works connections to the simple Ovh API with
  40. * login method and call wrapper
  41. * Http connections use guzzle http client api and result of request are
  42. * object from this http wrapper
  43. *
  44. * @package Ovh
  45. * @category Ovh
  46. */
  47. class Api
  48. {
  49. /**
  50. * Url to communicate with Ovh API
  51. *
  52. * @var array
  53. */
  54. private $endpoints = [
  55. 'ovh-eu' => 'https://api.ovh.com/1.0',
  56. 'ovh-ca' => 'https://ca.api.ovh.com/1.0',
  57. 'kimsufi-eu' => 'https://eu.api.kimsufi.com/1.0',
  58. 'kimsufi-ca' => 'https://ca.api.kimsufi.com/1.0',
  59. 'soyoustart-eu' => 'https://eu.api.soyoustart.com/1.0',
  60. 'soyoustart-ca' => 'https://ca.api.soyoustart.com/1.0',
  61. 'runabove-ca' => 'https://api.runabove.com/1.0',
  62. ];
  63. /**
  64. * Contain endpoint selected to choose API
  65. *
  66. * @var string
  67. */
  68. private $endpoint = null;
  69. /**
  70. * Contain key of the current application
  71. *
  72. * @var string
  73. */
  74. private $application_key = null;
  75. /**
  76. * Contain secret of the current application
  77. *
  78. * @var string
  79. */
  80. private $application_secret = null;
  81. /**
  82. * Contain consumer key of the current application
  83. *
  84. * @var string
  85. */
  86. private $consumer_key = null;
  87. /**
  88. * Contain delta between local timestamp and api server timestamp
  89. *
  90. * @var string
  91. */
  92. private $time_delta = null;
  93. /**
  94. * Contain http client connection
  95. *
  96. * @var Client
  97. */
  98. private $http_client = null;
  99. /**
  100. * Construct a new wrapper instance
  101. *
  102. * @param string $application_key key of your application.
  103. * For OVH APIs, you can create a application's credentials on
  104. * https://api.ovh.com/createApp/
  105. * @param string $application_secret secret of your application.
  106. * @param string $api_endpoint name of api selected
  107. * @param string $consumer_key If you have already a consumer key, this parameter prevent to do a
  108. * new authentication
  109. * @param Client $http_client instance of http client
  110. *
  111. * @throws Exceptions\InvalidParameterException if one parameter is missing or with bad value
  112. */
  113. public function __construct(
  114. $application_key,
  115. $application_secret,
  116. $api_endpoint,
  117. $consumer_key = null,
  118. Client $http_client = null
  119. ) {
  120. if (!isset($application_key)) {
  121. throw new Exceptions\InvalidParameterException("Application key parameter is empty");
  122. }
  123. if (!isset($application_secret)) {
  124. throw new Exceptions\InvalidParameterException("Application secret parameter is empty");
  125. }
  126. if (!isset($api_endpoint)) {
  127. throw new exceptions\DNSSubmoduleException("Endpoint parameter is empty");
  128. }
  129. if (!array_key_exists($api_endpoint, $this->endpoints)) {
  130. throw new Exceptions\InvalidParameterException("Unknown provided endpoint");
  131. }
  132. if (!isset($http_client)) {
  133. $http_client = new Client([
  134. 'timeout' => 30,
  135. 'connect_timeout' => 5,
  136. ]);
  137. }
  138. $this->application_key = $application_key;
  139. $this->endpoint = $this->endpoints[$api_endpoint];
  140. $this->application_secret = $application_secret;
  141. $this->http_client = $http_client;
  142. $this->consumer_key = $consumer_key;
  143. $this->time_delta = null;
  144. }
  145. /**
  146. * Calculate time delta between local machine and API's server
  147. *
  148. * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  149. * @return int
  150. */
  151. private function calculateTimeDelta()
  152. {
  153. if (!isset($this->time_delta)) {
  154. $response = $this->http_client->get($this->endpoint . "/auth/time");
  155. $serverTimestamp = (int)(String)$response->getBody();
  156. $this->time_delta = $serverTimestamp - (int)\time();
  157. }
  158. return $this->time_delta;
  159. }
  160. /**
  161. * Request a consumer key from the API and the validation link to
  162. * authorize user to validate this consumer key
  163. *
  164. * @param array $accessRules list of rules your application need.
  165. * @param string $redirection url to redirect on your website after authentication
  166. *
  167. * @return mixed
  168. * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  169. */
  170. public function requestCredentials(
  171. array $accessRules,
  172. $redirection = null
  173. ) {
  174. $parameters = new \StdClass();
  175. $parameters->accessRules = $accessRules;
  176. $parameters->redirection = $redirection;
  177. //bypass authentication for this call
  178. $response = $this->rawCall(
  179. 'POST',
  180. '/auth/credential',
  181. $parameters,
  182. false
  183. );
  184. $this->consumer_key = $response["consumerKey"];
  185. return $response;
  186. }
  187. /**
  188. * This is the main method of this wrapper. It will
  189. * sign a given query and return its result.
  190. *
  191. * @param string $method HTTP method of request (GET,POST,PUT,DELETE)
  192. * @param string $path relative url of API request
  193. * @param \stdClass|array|null $content body of the request
  194. * @param bool $is_authenticated if the request use authentication
  195. *
  196. * @return array
  197. * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  198. */
  199. private function rawCall($method, $path, $content = null, $is_authenticated = true)
  200. {
  201. $url = $this->endpoint . $path;
  202. //$request = new Request($method, $url);
  203. $request = $this->http_client->createRequest($method,$url);
  204. if (isset($content) && $method == 'GET') {
  205. $query_string = $request->getUri()->getQuery();
  206. $query = array();
  207. if (!empty($query_string)) {
  208. $queries = explode('&', $query_string);
  209. foreach($queries as $element) {
  210. $key_value_query = explode('=', $element, 2);
  211. $query[$key_value_query[0]] = $key_value_query[1];
  212. }
  213. }
  214. $query = array_merge($query, (array)$content);
  215. // rewrite query args to properly dump true/false parameters
  216. foreach($query as $key => $value)
  217. {
  218. if ($value === false)
  219. {
  220. $query[$key] = "false";
  221. }
  222. elseif ($value === true)
  223. {
  224. $query[$key] = "true";
  225. }
  226. }
  227. $query = \GuzzleHttp\Psr7\build_query($query);
  228. $url = $request->getUri()->withQuery($query);
  229. $request = $request->withUri($url);
  230. $body = "";
  231. } elseif (isset($content)) {
  232. $body = json_encode($content);
  233. //$request->getBody()->write($body);
  234. $request->setBody(Stream::factory($body));
  235. } else {
  236. $body = "";
  237. }
  238. $headers = [
  239. 'Content-Type' => 'application/json; charset=utf-8',
  240. 'X-Ovh-Application' => $this->application_key,
  241. ];
  242. if ($is_authenticated) {
  243. if (!isset($this->time_delta)) {
  244. $this->calculateTimeDelta();
  245. }
  246. $now = time() + $this->time_delta;
  247. $headers['X-Ovh-Timestamp'] = $now;
  248. if (isset($this->consumer_key)) {
  249. $toSign = $this->application_secret . '+' . $this->consumer_key . '+' . $method
  250. . '+' . $url . '+' . $body . '+' . $now;
  251. $signature = '$1$' . sha1($toSign);
  252. $headers['X-Ovh-Consumer'] = $this->consumer_key;
  253. $headers['X-Ovh-Signature'] = $signature;
  254. }
  255. }
  256. $request->setHeaders($headers);
  257. /** @var Response $response */
  258. $response = $this->http_client->send($request);
  259. return json_decode($response->getBody(), true);
  260. }
  261. /**
  262. * Wrap call to Ovh APIs for GET requests
  263. *
  264. * @param string $path path ask inside api
  265. * @param array $content content to send inside body of request
  266. *
  267. * @return array
  268. * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  269. */
  270. public function get($path, $content = null)
  271. {
  272. return $this->rawCall("GET", $path, $content);
  273. }
  274. /**
  275. * Wrap call to Ovh APIs for POST requests
  276. *
  277. * @param string $path path ask inside api
  278. * @param array $content content to send inside body of request
  279. *
  280. * @return array
  281. * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  282. */
  283. public function post($path, $content = null)
  284. {
  285. return $this->rawCall("POST", $path, $content);
  286. }
  287. /**
  288. * Wrap call to Ovh APIs for PUT requests
  289. *
  290. * @param string $path path ask inside api
  291. * @param array $content content to send inside body of request
  292. *
  293. * @return array
  294. * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  295. */
  296. public function put($path, $content)
  297. {
  298. return $this->rawCall("PUT", $path, $content);
  299. }
  300. /**
  301. * Wrap call to Ovh APIs for DELETE requests
  302. *
  303. * @param string $path path ask inside api
  304. * @param array $content content to send inside body of request
  305. *
  306. * @return array
  307. * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  308. */
  309. public function delete($path, $content = null)
  310. {
  311. return $this->rawCall("DELETE", $path, $content);
  312. }
  313. /**
  314. * Get the current consumer key
  315. */
  316. public function getConsumerKey()
  317. {
  318. return $this->consumer_key;
  319. }
  320. /**
  321. * Return instance of http client
  322. */
  323. public function getHttpClient()
  324. {
  325. return $this->http_client;
  326. }
  327. }