1
0

BxOAuthAPI.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup OAuth2 OAuth2 server
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. use OAuth2\Response;
  12. class BxOAuthAPI extends BxDol
  13. {
  14. protected $_oModule;
  15. protected $_oDb;
  16. public $aAction2Scope = array (
  17. 'me' => 'basic,market,service,api',
  18. 'user' => 'basic,market,service,api',
  19. 'friends' => 'basic,market,service,api',
  20. 'service' => 'service',
  21. 'market' => 'market',
  22. 'api' => 'api',
  23. );
  24. public $aExceptionsAPI = array ('output', 'errorOutput', 'isPublicAPI');
  25. function __construct($oModule)
  26. {
  27. $this->_oModule = $oModule;
  28. $this->_oDb = $oModule->_oDb;
  29. }
  30. /**
  31. * @page private_api API Private
  32. * @section private_api_me /m/oauth2/api/me
  33. *
  34. * Provides information about current profile.
  35. *
  36. * **Scopes:**
  37. * `basic`, `service`, `market`
  38. *
  39. * **HTTP Method:**
  40. * `GET`
  41. *
  42. * **Request header:**
  43. * @code
  44. * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
  45. * @endcode
  46. *
  47. * **Response (success):**
  48. * @code
  49. * {
  50. * "id":"123",
  51. * "type":"bx_organizations",
  52. * "email":"test@example.com",
  53. * "role":"1",
  54. * "name":"Test",
  55. * "profile_display_name":"Test",
  56. * "profile_link":"http:\/\/example.com\/path-to-una\/page\/view-organization-profile?id=12",
  57. * "picture":"http:\/\/example.com\/path-to-una\/image_transcoder.php?o=bx_organizations_picture&h=36&dpx=1&t=1496247306"
  58. * }
  59. * @endcode
  60. *
  61. * **Response (error):**
  62. * @code
  63. * {
  64. * "error":"short error description here",
  65. * "error_description":"long error description here"
  66. * }
  67. * @endcode
  68. *
  69. */
  70. function me($aToken)
  71. {
  72. if (!($oProfile = BxDolProfile::getInstance($aToken['user_id']))) {
  73. $this->errorOutput('404', 'not_found', 'Profile was not found');
  74. return;
  75. }
  76. // get current account's profile (it maybe different if user switched to another profile)
  77. $oAccount = $oProfile->getAccountObject();
  78. if (!($oProfile = BxDolProfile::getInstanceByAccount($oAccount->id()))) {
  79. $this->errorOutput('404', 'not_found', 'Profile was not found');
  80. return;
  81. }
  82. $aClient = $this->_oDb->getClientsBy(array('type' => 'client_id', 'client_id' => $aToken['client_id']));
  83. $aProfile = $this->_prepareProfileArray($oProfile, false);
  84. $aProfile['owner'] = (int)$aProfile['id'] == (int)$aClient['user_id'];
  85. $this->output($aProfile);
  86. }
  87. /**
  88. * @page private_api API Private
  89. * @section private_api_user /m/oauth2/api/user
  90. *
  91. * Provides information about particular profile profile.
  92. *
  93. * **Parameters:**
  94. * - `id` - profile ID
  95. *
  96. * Everything else is equivalent to @ref private_api_me
  97. */
  98. function user($aToken)
  99. {
  100. $iProfileId = (int)bx_get('id');
  101. if ($iProfileId == $aToken['user_id']) {
  102. $this->me($aToken);
  103. return;
  104. }
  105. if (!($oProfile = $this->_getProfileWithAccessChecking($iProfileId)))
  106. return;
  107. if (!(BxDolProfile::getInstance($aToken['user_id'])))
  108. return;
  109. $this->output($this->_prepareProfileArray($oProfile, !isAdmin()));
  110. }
  111. /**
  112. * @page private_api API Private
  113. * @section private_api_friends /m/oauth2/api/friends
  114. *
  115. * Get list of friends.
  116. *
  117. * **Scopes:**
  118. * `basic`, `service`, `market`
  119. *
  120. * **HTTP Method:**
  121. * `GET`
  122. *
  123. * **Parameters:**
  124. * - `id` - profile ID
  125. *
  126. * **Request header:**
  127. * @code
  128. * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
  129. * @endcode
  130. *
  131. * **Response (success):**
  132. * @code
  133. * {
  134. * "user_id":30,
  135. * "friends":[
  136. * "24",
  137. * "29",
  138. * "51"
  139. * ]
  140. * }
  141. * @endcode
  142. *
  143. * **Response (error):**
  144. * @code
  145. * {
  146. * "error":"short error description here",
  147. * "error_description":"long error description here"
  148. * }
  149. * @endcode
  150. *
  151. */
  152. function friends($aToken)
  153. {
  154. $iProfileId = (int)bx_get('id');
  155. if (!($oProfile = $this->_getProfileWithAccessChecking($iProfileId)))
  156. return;
  157. if (!($oConn = BxDolConnection::getObjectInstance('sys_profiles_friends'))) {
  158. $this->errorOutput(405, 'not_supported', 'Friends lists aren\'t supported');
  159. return false;
  160. }
  161. $this->output(array(
  162. 'user_id' => $iProfileId,
  163. 'friends' => $oConn->getConnectedContent($iProfileId, true),
  164. ));
  165. }
  166. /**
  167. * @page private_api API Private
  168. * @section private_api_market /m/oauth2/api/market
  169. *
  170. * Market service call.
  171. *
  172. * **Scopes:**
  173. * `market`, `service`
  174. *
  175. * Everything is equivalent to @ref private_api_service, only module name parameter can be ommited
  176. */
  177. function market($aToken)
  178. {
  179. $_GET['key'] = $_POST['key'] = $aToken['client_id'];
  180. $_GET['module'] = $_POST['module'] = 'bx_market_api';
  181. $this->service($aToken);
  182. }
  183. /**
  184. * @page public_api API Public
  185. * @section public_api_com /m/oauth2/api/com
  186. *
  187. * API service call (com is for command).
  188. * The call should be look this:
  189. * `/m/oauth2/api/com/[metod-name-here]`
  190. *
  191. * **Scopes:**
  192. * `api`
  193. *
  194. * Everything is equivalent to @ref private_api_service,
  195. * only module name parameter can be ommited and
  196. * method is passed as method parameter instead of GET/POST variable
  197. */
  198. function com($sMethod, $aToken, $bPublic)
  199. {
  200. $_GET['key'] = $_POST['key'] = (isset($aToken['client_id']) ? $aToken['client_id'] : '');
  201. if (!isset($_GET['module']) && !isset($_POST['module']))
  202. $_GET['module'] = $_POST['module'] = 'bx_api';
  203. $_GET['method'] = $_POST['method'] = $sMethod;
  204. $this->service($aToken, $bPublic, true);
  205. }
  206. function isPublicAPI($sModule, $sMethod, $sClass = false)
  207. {
  208. return $this->_isAPI($sModule, $sMethod, $sClass, 'is_public_service');
  209. }
  210. function isSafeAPI($sModule, $sMethod, $sClass = false)
  211. {
  212. return $this->_isAPI($sModule, $sMethod, $sClass, 'is_safe_service');
  213. }
  214. protected function _isAPI($sModule, $sMethod, $sClass = false, $sCheckMethod = 'is_safe_service')
  215. {
  216. if (!$sClass)
  217. $sClass = 'Module';
  218. if (!BxDolRequest::serviceExists($sModule, $sMethod, $sClass))
  219. return false;
  220. if (!BxDolRequest::serviceExists($sModule, $sCheckMethod, 'system' == $sModule ? 'TemplServices' : $sClass))
  221. return false;
  222. return BxDolService::call($sModule, $sCheckMethod, array($sMethod), 'system' == $sModule ? 'TemplServices' : $sClass);
  223. }
  224. /**
  225. * @page private_api API Private
  226. * @section private_api_service /m/oauth2/api/service
  227. *
  228. * Perform system call.
  229. * For a list of avalibale service calls and their parameters refer to @ref service page.
  230. *
  231. * URL should look like this in case of service API call:
  232. * @code
  233. * http://example.com/m/oauth2/api/service?module=bx_market&method=test&params[]=1&params[]=abc&class=custom_class_name_or_remove_it_if_main_module_class
  234. * http://example.com/m/oauth2/api/service?module=bx_market&method=test&params=serialized_string_of_params
  235. * http://example.com/m/oauth2/api/service?module=bx_market&method=test&params=json_string_of_params
  236. * @endcode
  237. *
  238. * **Scopes:**
  239. * `service`
  240. *
  241. * **HTTP Method:**
  242. * `GET`, `POST`
  243. *
  244. * **Parameters:**
  245. * - `module` - module name to perform service call in
  246. * - `method` - service call method
  247. * - `params` - parameters array
  248. * - `class` - custom module name if different from main module class
  249. *
  250. * **Request header:**
  251. * @code
  252. * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
  253. * @endcode
  254. *
  255. * **Response (success):**
  256. * Depends on particular service call
  257. *
  258. * **Response (error):**
  259. * Error responce is described in particular service method.
  260. * In case of general error (for example when service call isn't found, or error with token), the format is following:
  261. * @code
  262. * {
  263. * "error":"short error description here",
  264. * "error_description":"long error description here"
  265. * }
  266. * @endcode
  267. *
  268. */
  269. function service($aToken, $bPublic = false, $bOutputResultOnly = false)
  270. {
  271. if (!$bPublic && !($oProfile = BxDolProfile::getInstance($aToken['user_id']))) {
  272. $this->errorOutput('404', 'not_found', 'Profile was not found');
  273. return;
  274. }
  275. if (!$bPublic) {
  276. bx_login($oProfile->getAccountId(), false);
  277. check_logged();
  278. }
  279. $sModule = bx_get('module');
  280. $sMethod = bx_get('method');
  281. if (!($aParams = bx_get('params')))
  282. $aParams = array();
  283. elseif (is_string($aParams) && preg_match('/^\[.*\]$/', $aParams))
  284. $aParams = @json_decode($aParams);
  285. if (!is_array($aParams))
  286. $aParams = array($aParams);
  287. if (!($sClass = bx_get('class')))
  288. $sClass = 'Module';
  289. if (!preg_match('/^[A-Za-z0-9_]+$/', $sModule) || !preg_match('/^[A-Za-z0-9_]+$/', $sMethod) || !preg_match('/^[A-Za-z0-9_]+$/', $sClass)) {
  290. $this->errorOutput(500, 'error', 'Malformed request');
  291. return false;
  292. }
  293. if (!BxDolRequest::serviceExists($sModule, $sMethod, $sClass)) {
  294. $this->errorOutput(404, 'not_found', 'Service was not found');
  295. return false;
  296. }
  297. $mixedRet = BxDolService::call($sModule, $sMethod, $aParams, $sClass);
  298. if (is_array($mixedRet) && isset($mixedRet['error']) && isset($mixedRet['code'])) {
  299. $this->errorOutput($mixedRet['code'], $mixedRet['error'], isset($mixedRet['desc']) ? $mixedRet['desc'] : $mixedRet['error']);
  300. return false;
  301. }
  302. $this->output($bOutputResultOnly ? $mixedRet : array(
  303. 'module' => $sModule,
  304. 'method' => $sMethod,
  305. 'data' => $mixedRet,
  306. ));
  307. }
  308. function errorOutput($iHttpCode, $sError, $sErrorDesc)
  309. {
  310. $oReponse = new Response();
  311. $oReponse->setError($iHttpCode, $sError, $sErrorDesc);
  312. $oReponse->send();
  313. }
  314. function output($a)
  315. {
  316. $oReponse = new Response();
  317. $oReponse->setParameters($a);
  318. $oReponse->send();
  319. }
  320. protected function _getProfileWithAccessChecking ($iProfileId)
  321. {
  322. if (!$oProfile = BxDolProfile::getInstance($iProfileId)) {
  323. $this->errorOutput('404', 'not_found', 'Profile was not found');
  324. return false;
  325. }
  326. /*
  327. // TODO: check visibility
  328. if (!bx_check_profile_visibility($iProfileId, $aToken['user_id'], true)) {
  329. $this->errorOutput(403, 'access_denied', 'You have no rights to view this user info');
  330. return false;
  331. }
  332. */
  333. return $oProfile;
  334. }
  335. protected function _prepareProfileArray ($oProfile, $bPublicFieldsOnly = true)
  336. {
  337. $oAccount = $oProfile->getAccountObject();
  338. $aProfileInfo = $oProfile->getInfo();
  339. $aAccountInfo = $oAccount->getInfo();
  340. if ($bPublicFieldsOnly) {
  341. $aProfileInfo = array(
  342. 'id' => $aProfileInfo['id'],
  343. );
  344. }
  345. else {
  346. unset($aProfileInfo['account_id']);
  347. unset($aProfileInfo['content_id']);
  348. unset($aProfileInfo['status']);
  349. // --- account's profiles info
  350. $aProfileInfo['email'] = $oAccount->getEmail();
  351. // ---- returns all accounts profiles React Jot
  352. $aProfiles = $oAccount->getProfiles();
  353. foreach($aProfiles as &$aProfile) {
  354. $oSubProfile = BxDolProfile::getInstance($aProfile['id']);
  355. $aProfileInfo['profiles'][$aProfile['id']] = array(
  356. 'name' => $oSubProfile->getDisplayName(),
  357. 'profile_link' => $oSubProfile->getUrl(),
  358. 'picture' => $oSubProfile->getThumb(),
  359. 'id' => $aProfile['id']
  360. );
  361. }
  362. // TODO: fetch extended info from profile module
  363. }
  364. $aProfileInfo['role'] = $aAccountInfo['role'];
  365. $aProfileInfo['name'] = $oAccount->getDisplayName();
  366. $aProfileInfo['profile_display_name'] = $oProfile->getDisplayName();
  367. $aProfileInfo['profile_link'] = $oProfile->getUrl();
  368. $aProfileInfo['picture'] = $oProfile->getPicture();
  369. $aProfileInfo['avatar'] = $oProfile->getAvatar();
  370. // ---- additional profile's fields for React Jot
  371. $aProfileInfo['cover'] = $oProfile->getCover();
  372. $aProfileInfo['followers'] = (int)BxDolConnection::getObjectInstance('sys_profiles_subscriptions')->getConnectedInitiatorsCount($aProfileInfo['id']);
  373. $aProfileInfo['following'] = (int)BxDolConnection::getObjectInstance('sys_profiles_subscriptions')->getConnectedContentCount($aProfileInfo['id']);
  374. $aProfileInfo['friends'] = (int)BxDolConnection::getObjectInstance('sys_profiles_friends')->getConnectedContentCount($aProfileInfo['id'], true);
  375. return $aProfileInfo;
  376. }
  377. }
  378. /** @} */