class-wp-rest-application-passwords-controller.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. <?php
  2. /**
  3. * REST API: WP_REST_Application_Passwords_Controller class
  4. *
  5. * @package WordPress
  6. * @subpackage REST_API
  7. * @since 5.6.0
  8. */
  9. /**
  10. * Core class to access a user's application passwords via the REST API.
  11. *
  12. * @since 5.6.0
  13. *
  14. * @see WP_REST_Controller
  15. */
  16. class WP_REST_Application_Passwords_Controller extends WP_REST_Controller {
  17. /**
  18. * Application Passwords controller constructor.
  19. *
  20. * @since 5.6.0
  21. */
  22. public function __construct() {
  23. $this->namespace = 'wp/v2';
  24. $this->rest_base = 'users/(?P<user_id>(?:[\d]+|me))/application-passwords';
  25. }
  26. /**
  27. * Registers the REST API routes for the application passwords controller.
  28. *
  29. * @since 5.6.0
  30. */
  31. public function register_routes() {
  32. register_rest_route(
  33. $this->namespace,
  34. '/' . $this->rest_base,
  35. array(
  36. array(
  37. 'methods' => WP_REST_Server::READABLE,
  38. 'callback' => array( $this, 'get_items' ),
  39. 'permission_callback' => array( $this, 'get_items_permissions_check' ),
  40. 'args' => $this->get_collection_params(),
  41. ),
  42. array(
  43. 'methods' => WP_REST_Server::CREATABLE,
  44. 'callback' => array( $this, 'create_item' ),
  45. 'permission_callback' => array( $this, 'create_item_permissions_check' ),
  46. 'args' => $this->get_endpoint_args_for_item_schema(),
  47. ),
  48. array(
  49. 'methods' => WP_REST_Server::DELETABLE,
  50. 'callback' => array( $this, 'delete_items' ),
  51. 'permission_callback' => array( $this, 'delete_items_permissions_check' ),
  52. ),
  53. 'schema' => array( $this, 'get_public_item_schema' ),
  54. )
  55. );
  56. register_rest_route(
  57. $this->namespace,
  58. '/' . $this->rest_base . '/introspect',
  59. array(
  60. array(
  61. 'methods' => WP_REST_Server::READABLE,
  62. 'callback' => array( $this, 'get_current_item' ),
  63. 'permission_callback' => array( $this, 'get_current_item_permissions_check' ),
  64. 'args' => array(
  65. 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
  66. ),
  67. ),
  68. 'schema' => array( $this, 'get_public_item_schema' ),
  69. )
  70. );
  71. register_rest_route(
  72. $this->namespace,
  73. '/' . $this->rest_base . '/(?P<uuid>[\w\-]+)',
  74. array(
  75. array(
  76. 'methods' => WP_REST_Server::READABLE,
  77. 'callback' => array( $this, 'get_item' ),
  78. 'permission_callback' => array( $this, 'get_item_permissions_check' ),
  79. 'args' => array(
  80. 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
  81. ),
  82. ),
  83. array(
  84. 'methods' => WP_REST_Server::EDITABLE,
  85. 'callback' => array( $this, 'update_item' ),
  86. 'permission_callback' => array( $this, 'update_item_permissions_check' ),
  87. 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
  88. ),
  89. array(
  90. 'methods' => WP_REST_Server::DELETABLE,
  91. 'callback' => array( $this, 'delete_item' ),
  92. 'permission_callback' => array( $this, 'delete_item_permissions_check' ),
  93. ),
  94. 'schema' => array( $this, 'get_public_item_schema' ),
  95. )
  96. );
  97. }
  98. /**
  99. * Checks if a given request has access to get application passwords.
  100. *
  101. * @since 5.6.0
  102. *
  103. * @param WP_REST_Request $request Full details about the request.
  104. * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
  105. */
  106. public function get_items_permissions_check( $request ) {
  107. $user = $this->get_user( $request );
  108. if ( is_wp_error( $user ) ) {
  109. return $user;
  110. }
  111. if ( ! current_user_can( 'list_app_passwords', $user->ID ) ) {
  112. return new WP_Error(
  113. 'rest_cannot_list_application_passwords',
  114. __( 'Sorry, you are not allowed to list application passwords for this user.' ),
  115. array( 'status' => rest_authorization_required_code() )
  116. );
  117. }
  118. return true;
  119. }
  120. /**
  121. * Retrieves a collection of application passwords.
  122. *
  123. * @since 5.6.0
  124. *
  125. * @param WP_REST_Request $request Full details about the request.
  126. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
  127. */
  128. public function get_items( $request ) {
  129. $user = $this->get_user( $request );
  130. if ( is_wp_error( $user ) ) {
  131. return $user;
  132. }
  133. $passwords = WP_Application_Passwords::get_user_application_passwords( $user->ID );
  134. $response = array();
  135. foreach ( $passwords as $password ) {
  136. $response[] = $this->prepare_response_for_collection(
  137. $this->prepare_item_for_response( $password, $request )
  138. );
  139. }
  140. return new WP_REST_Response( $response );
  141. }
  142. /**
  143. * Checks if a given request has access to get a specific application password.
  144. *
  145. * @since 5.6.0
  146. *
  147. * @param WP_REST_Request $request Full details about the request.
  148. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
  149. */
  150. public function get_item_permissions_check( $request ) {
  151. $user = $this->get_user( $request );
  152. if ( is_wp_error( $user ) ) {
  153. return $user;
  154. }
  155. if ( ! current_user_can( 'read_app_password', $user->ID, $request['uuid'] ) ) {
  156. return new WP_Error(
  157. 'rest_cannot_read_application_password',
  158. __( 'Sorry, you are not allowed to read this application password.' ),
  159. array( 'status' => rest_authorization_required_code() )
  160. );
  161. }
  162. return true;
  163. }
  164. /**
  165. * Retrieves one application password from the collection.
  166. *
  167. * @since 5.6.0
  168. *
  169. * @param WP_REST_Request $request Full details about the request.
  170. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
  171. */
  172. public function get_item( $request ) {
  173. $password = $this->get_application_password( $request );
  174. if ( is_wp_error( $password ) ) {
  175. return $password;
  176. }
  177. return $this->prepare_item_for_response( $password, $request );
  178. }
  179. /**
  180. * Checks if a given request has access to create application passwords.
  181. *
  182. * @since 5.6.0
  183. *
  184. * @param WP_REST_Request $request Full details about the request.
  185. * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise.
  186. */
  187. public function create_item_permissions_check( $request ) {
  188. $user = $this->get_user( $request );
  189. if ( is_wp_error( $user ) ) {
  190. return $user;
  191. }
  192. if ( ! current_user_can( 'create_app_password', $user->ID ) ) {
  193. return new WP_Error(
  194. 'rest_cannot_create_application_passwords',
  195. __( 'Sorry, you are not allowed to create application passwords for this user.' ),
  196. array( 'status' => rest_authorization_required_code() )
  197. );
  198. }
  199. return true;
  200. }
  201. /**
  202. * Creates an application password.
  203. *
  204. * @since 5.6.0
  205. *
  206. * @param WP_REST_Request $request Full details about the request.
  207. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
  208. */
  209. public function create_item( $request ) {
  210. $user = $this->get_user( $request );
  211. if ( is_wp_error( $user ) ) {
  212. return $user;
  213. }
  214. $prepared = $this->prepare_item_for_database( $request );
  215. if ( is_wp_error( $prepared ) ) {
  216. return $prepared;
  217. }
  218. $created = WP_Application_Passwords::create_new_application_password( $user->ID, wp_slash( (array) $prepared ) );
  219. if ( is_wp_error( $created ) ) {
  220. return $created;
  221. }
  222. $password = $created[0];
  223. $item = WP_Application_Passwords::get_user_application_password( $user->ID, $created[1]['uuid'] );
  224. $item['new_password'] = WP_Application_Passwords::chunk_password( $password );
  225. $fields_update = $this->update_additional_fields_for_object( $item, $request );
  226. if ( is_wp_error( $fields_update ) ) {
  227. return $fields_update;
  228. }
  229. /**
  230. * Fires after a single application password is completely created or updated via the REST API.
  231. *
  232. * @since 5.6.0
  233. *
  234. * @param array $item Inserted or updated password item.
  235. * @param WP_REST_Request $request Request object.
  236. * @param bool $creating True when creating an application password, false when updating.
  237. */
  238. do_action( 'rest_after_insert_application_password', $item, $request, true );
  239. $request->set_param( 'context', 'edit' );
  240. $response = $this->prepare_item_for_response( $item, $request );
  241. $response->set_status( 201 );
  242. $response->header( 'Location', $response->get_links()['self'][0]['href'] );
  243. return $response;
  244. }
  245. /**
  246. * Checks if a given request has access to update application passwords.
  247. *
  248. * @since 5.6.0
  249. *
  250. * @param WP_REST_Request $request Full details about the request.
  251. * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise.
  252. */
  253. public function update_item_permissions_check( $request ) {
  254. $user = $this->get_user( $request );
  255. if ( is_wp_error( $user ) ) {
  256. return $user;
  257. }
  258. if ( ! current_user_can( 'edit_app_password', $user->ID, $request['uuid'] ) ) {
  259. return new WP_Error(
  260. 'rest_cannot_edit_application_password',
  261. __( 'Sorry, you are not allowed to edit this application password.' ),
  262. array( 'status' => rest_authorization_required_code() )
  263. );
  264. }
  265. return true;
  266. }
  267. /**
  268. * Updates an application password.
  269. *
  270. * @since 5.6.0
  271. *
  272. * @param WP_REST_Request $request Full details about the request.
  273. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
  274. */
  275. public function update_item( $request ) {
  276. $user = $this->get_user( $request );
  277. if ( is_wp_error( $user ) ) {
  278. return $user;
  279. }
  280. $item = $this->get_application_password( $request );
  281. if ( is_wp_error( $item ) ) {
  282. return $item;
  283. }
  284. $prepared = $this->prepare_item_for_database( $request );
  285. if ( is_wp_error( $prepared ) ) {
  286. return $prepared;
  287. }
  288. $saved = WP_Application_Passwords::update_application_password( $user->ID, $item['uuid'], wp_slash( (array) $prepared ) );
  289. if ( is_wp_error( $saved ) ) {
  290. return $saved;
  291. }
  292. $fields_update = $this->update_additional_fields_for_object( $item, $request );
  293. if ( is_wp_error( $fields_update ) ) {
  294. return $fields_update;
  295. }
  296. $item = WP_Application_Passwords::get_user_application_password( $user->ID, $item['uuid'] );
  297. /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php */
  298. do_action( 'rest_after_insert_application_password', $item, $request, false );
  299. $request->set_param( 'context', 'edit' );
  300. return $this->prepare_item_for_response( $item, $request );
  301. }
  302. /**
  303. * Checks if a given request has access to delete all application passwords for a user.
  304. *
  305. * @since 5.6.0
  306. *
  307. * @param WP_REST_Request $request Full details about the request.
  308. * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise.
  309. */
  310. public function delete_items_permissions_check( $request ) {
  311. $user = $this->get_user( $request );
  312. if ( is_wp_error( $user ) ) {
  313. return $user;
  314. }
  315. if ( ! current_user_can( 'delete_app_passwords', $user->ID ) ) {
  316. return new WP_Error(
  317. 'rest_cannot_delete_application_passwords',
  318. __( 'Sorry, you are not allowed to delete application passwords for this user.' ),
  319. array( 'status' => rest_authorization_required_code() )
  320. );
  321. }
  322. return true;
  323. }
  324. /**
  325. * Deletes all application passwords for a user.
  326. *
  327. * @since 5.6.0
  328. *
  329. * @param WP_REST_Request $request Full details about the request.
  330. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
  331. */
  332. public function delete_items( $request ) {
  333. $user = $this->get_user( $request );
  334. if ( is_wp_error( $user ) ) {
  335. return $user;
  336. }
  337. $deleted = WP_Application_Passwords::delete_all_application_passwords( $user->ID );
  338. if ( is_wp_error( $deleted ) ) {
  339. return $deleted;
  340. }
  341. return new WP_REST_Response(
  342. array(
  343. 'deleted' => true,
  344. 'count' => $deleted,
  345. )
  346. );
  347. }
  348. /**
  349. * Checks if a given request has access to delete a specific application password for a user.
  350. *
  351. * @since 5.6.0
  352. *
  353. * @param WP_REST_Request $request Full details about the request.
  354. * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise.
  355. */
  356. public function delete_item_permissions_check( $request ) {
  357. $user = $this->get_user( $request );
  358. if ( is_wp_error( $user ) ) {
  359. return $user;
  360. }
  361. if ( ! current_user_can( 'delete_app_password', $user->ID, $request['uuid'] ) ) {
  362. return new WP_Error(
  363. 'rest_cannot_delete_application_password',
  364. __( 'Sorry, you are not allowed to delete this application password.' ),
  365. array( 'status' => rest_authorization_required_code() )
  366. );
  367. }
  368. return true;
  369. }
  370. /**
  371. * Deletes an application password for a user.
  372. *
  373. * @since 5.6.0
  374. *
  375. * @param WP_REST_Request $request Full details about the request.
  376. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
  377. */
  378. public function delete_item( $request ) {
  379. $user = $this->get_user( $request );
  380. if ( is_wp_error( $user ) ) {
  381. return $user;
  382. }
  383. $password = $this->get_application_password( $request );
  384. if ( is_wp_error( $password ) ) {
  385. return $password;
  386. }
  387. $request->set_param( 'context', 'edit' );
  388. $previous = $this->prepare_item_for_response( $password, $request );
  389. $deleted = WP_Application_Passwords::delete_application_password( $user->ID, $password['uuid'] );
  390. if ( is_wp_error( $deleted ) ) {
  391. return $deleted;
  392. }
  393. return new WP_REST_Response(
  394. array(
  395. 'deleted' => true,
  396. 'previous' => $previous->get_data(),
  397. )
  398. );
  399. }
  400. /**
  401. * Checks if a given request has access to get the currently used application password for a user.
  402. *
  403. * @since 5.7.0
  404. *
  405. * @param WP_REST_Request $request Full details about the request.
  406. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
  407. */
  408. public function get_current_item_permissions_check( $request ) {
  409. $user = $this->get_user( $request );
  410. if ( is_wp_error( $user ) ) {
  411. return $user;
  412. }
  413. if ( get_current_user_id() !== $user->ID ) {
  414. return new WP_Error(
  415. 'rest_cannot_introspect_app_password_for_non_authenticated_user',
  416. __( 'The authenticated application password can only be introspected for the current user.' ),
  417. array( 'status' => rest_authorization_required_code() )
  418. );
  419. }
  420. return true;
  421. }
  422. /**
  423. * Retrieves the application password being currently used for authentication of a user.
  424. *
  425. * @since 5.7.0
  426. *
  427. * @param WP_REST_Request $request Full details about the request.
  428. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
  429. */
  430. public function get_current_item( $request ) {
  431. $user = $this->get_user( $request );
  432. if ( is_wp_error( $user ) ) {
  433. return $user;
  434. }
  435. $uuid = rest_get_authenticated_app_password();
  436. if ( ! $uuid ) {
  437. return new WP_Error(
  438. 'rest_no_authenticated_app_password',
  439. __( 'Cannot introspect application password.' ),
  440. array( 'status' => 404 )
  441. );
  442. }
  443. $password = WP_Application_Passwords::get_user_application_password( $user->ID, $uuid );
  444. if ( ! $password ) {
  445. return new WP_Error(
  446. 'rest_application_password_not_found',
  447. __( 'Application password not found.' ),
  448. array( 'status' => 500 )
  449. );
  450. }
  451. return $this->prepare_item_for_response( $password, $request );
  452. }
  453. /**
  454. * Performs a permissions check for the request.
  455. *
  456. * @since 5.6.0
  457. * @deprecated 5.7.0 Use `edit_user` directly or one of the specific meta capabilities introduced in 5.7.0.
  458. *
  459. * @param WP_REST_Request $request
  460. * @return true|WP_Error
  461. */
  462. protected function do_permissions_check( $request ) {
  463. _deprecated_function( __METHOD__, '5.7.0' );
  464. $user = $this->get_user( $request );
  465. if ( is_wp_error( $user ) ) {
  466. return $user;
  467. }
  468. if ( ! current_user_can( 'edit_user', $user->ID ) ) {
  469. return new WP_Error(
  470. 'rest_cannot_manage_application_passwords',
  471. __( 'Sorry, you are not allowed to manage application passwords for this user.' ),
  472. array( 'status' => rest_authorization_required_code() )
  473. );
  474. }
  475. return true;
  476. }
  477. /**
  478. * Prepares an application password for a create or update operation.
  479. *
  480. * @since 5.6.0
  481. *
  482. * @param WP_REST_Request $request Request object.
  483. * @return object|WP_Error The prepared item, or WP_Error object on failure.
  484. */
  485. protected function prepare_item_for_database( $request ) {
  486. $prepared = (object) array(
  487. 'name' => $request['name'],
  488. );
  489. if ( $request['app_id'] && ! $request['uuid'] ) {
  490. $prepared->app_id = $request['app_id'];
  491. }
  492. /**
  493. * Filters an application password before it is inserted via the REST API.
  494. *
  495. * @since 5.6.0
  496. *
  497. * @param stdClass $prepared An object representing a single application password prepared for inserting or updating the database.
  498. * @param WP_REST_Request $request Request object.
  499. */
  500. return apply_filters( 'rest_pre_insert_application_password', $prepared, $request );
  501. }
  502. /**
  503. * Prepares the application password for the REST response.
  504. *
  505. * @since 5.6.0
  506. *
  507. * @param array $item WordPress representation of the item.
  508. * @param WP_REST_Request $request Request object.
  509. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
  510. */
  511. public function prepare_item_for_response( $item, $request ) {
  512. $user = $this->get_user( $request );
  513. if ( is_wp_error( $user ) ) {
  514. return $user;
  515. }
  516. $fields = $this->get_fields_for_response( $request );
  517. $prepared = array(
  518. 'uuid' => $item['uuid'],
  519. 'app_id' => empty( $item['app_id'] ) ? '' : $item['app_id'],
  520. 'name' => $item['name'],
  521. 'created' => gmdate( 'Y-m-d\TH:i:s', $item['created'] ),
  522. 'last_used' => $item['last_used'] ? gmdate( 'Y-m-d\TH:i:s', $item['last_used'] ) : null,
  523. 'last_ip' => $item['last_ip'] ? $item['last_ip'] : null,
  524. );
  525. if ( isset( $item['new_password'] ) ) {
  526. $prepared['password'] = $item['new_password'];
  527. }
  528. $prepared = $this->add_additional_fields_to_object( $prepared, $request );
  529. $prepared = $this->filter_response_by_context( $prepared, $request['context'] );
  530. $response = new WP_REST_Response( $prepared );
  531. if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
  532. $response->add_links( $this->prepare_links( $user, $item ) );
  533. }
  534. /**
  535. * Filters the REST API response for an application password.
  536. *
  537. * @since 5.6.0
  538. *
  539. * @param WP_REST_Response $response The response object.
  540. * @param array $item The application password array.
  541. * @param WP_REST_Request $request The request object.
  542. */
  543. return apply_filters( 'rest_prepare_application_password', $response, $item, $request );
  544. }
  545. /**
  546. * Prepares links for the request.
  547. *
  548. * @since 5.6.0
  549. *
  550. * @param WP_User $user The requested user.
  551. * @param array $item The application password.
  552. * @return array The list of links.
  553. */
  554. protected function prepare_links( WP_User $user, $item ) {
  555. return array(
  556. 'self' => array(
  557. 'href' => rest_url(
  558. sprintf(
  559. '%s/users/%d/application-passwords/%s',
  560. $this->namespace,
  561. $user->ID,
  562. $item['uuid']
  563. )
  564. ),
  565. ),
  566. );
  567. }
  568. /**
  569. * Gets the requested user.
  570. *
  571. * @since 5.6.0
  572. *
  573. * @param WP_REST_Request $request The request object.
  574. * @return WP_User|WP_Error The WordPress user associated with the request, or a WP_Error if none found.
  575. */
  576. protected function get_user( $request ) {
  577. if ( ! wp_is_application_passwords_available() ) {
  578. return new WP_Error(
  579. 'application_passwords_disabled',
  580. __( 'Application passwords are not available.' ),
  581. array( 'status' => 501 )
  582. );
  583. }
  584. $error = new WP_Error(
  585. 'rest_user_invalid_id',
  586. __( 'Invalid user ID.' ),
  587. array( 'status' => 404 )
  588. );
  589. $id = $request['user_id'];
  590. if ( 'me' === $id ) {
  591. if ( ! is_user_logged_in() ) {
  592. return new WP_Error(
  593. 'rest_not_logged_in',
  594. __( 'You are not currently logged in.' ),
  595. array( 'status' => 401 )
  596. );
  597. }
  598. $user = wp_get_current_user();
  599. } else {
  600. $id = (int) $id;
  601. if ( $id <= 0 ) {
  602. return $error;
  603. }
  604. $user = get_userdata( $id );
  605. }
  606. if ( empty( $user ) || ! $user->exists() ) {
  607. return $error;
  608. }
  609. if ( is_multisite() && ! user_can( $user->ID, 'manage_sites' ) && ! is_user_member_of_blog( $user->ID ) ) {
  610. return $error;
  611. }
  612. if ( ! wp_is_application_passwords_available_for_user( $user ) ) {
  613. return new WP_Error(
  614. 'application_passwords_disabled_for_user',
  615. __( 'Application passwords are not available for your account. Please contact the site administrator for assistance.' ),
  616. array( 'status' => 501 )
  617. );
  618. }
  619. return $user;
  620. }
  621. /**
  622. * Gets the requested application password for a user.
  623. *
  624. * @since 5.6.0
  625. *
  626. * @param WP_REST_Request $request The request object.
  627. * @return array|WP_Error The application password details if found, a WP_Error otherwise.
  628. */
  629. protected function get_application_password( $request ) {
  630. $user = $this->get_user( $request );
  631. if ( is_wp_error( $user ) ) {
  632. return $user;
  633. }
  634. $password = WP_Application_Passwords::get_user_application_password( $user->ID, $request['uuid'] );
  635. if ( ! $password ) {
  636. return new WP_Error(
  637. 'rest_application_password_not_found',
  638. __( 'Application password not found.' ),
  639. array( 'status' => 404 )
  640. );
  641. }
  642. return $password;
  643. }
  644. /**
  645. * Retrieves the query params for the collections.
  646. *
  647. * @since 5.6.0
  648. *
  649. * @return array Query parameters for the collection.
  650. */
  651. public function get_collection_params() {
  652. return array(
  653. 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
  654. );
  655. }
  656. /**
  657. * Retrieves the application password's schema, conforming to JSON Schema.
  658. *
  659. * @since 5.6.0
  660. *
  661. * @return array Item schema data.
  662. */
  663. public function get_item_schema() {
  664. if ( $this->schema ) {
  665. return $this->add_additional_fields_schema( $this->schema );
  666. }
  667. $this->schema = array(
  668. '$schema' => 'http://json-schema.org/draft-04/schema#',
  669. 'title' => 'application-password',
  670. 'type' => 'object',
  671. 'properties' => array(
  672. 'uuid' => array(
  673. 'description' => __( 'The unique identifier for the application password.' ),
  674. 'type' => 'string',
  675. 'format' => 'uuid',
  676. 'context' => array( 'view', 'edit', 'embed' ),
  677. 'readonly' => true,
  678. ),
  679. 'app_id' => array(
  680. 'description' => __( 'A UUID provided by the application to uniquely identify it. It is recommended to use an UUID v5 with the URL or DNS namespace.' ),
  681. 'type' => 'string',
  682. 'format' => 'uuid',
  683. 'context' => array( 'view', 'edit', 'embed' ),
  684. ),
  685. 'name' => array(
  686. 'description' => __( 'The name of the application password.' ),
  687. 'type' => 'string',
  688. 'required' => true,
  689. 'context' => array( 'view', 'edit', 'embed' ),
  690. 'minLength' => 1,
  691. 'pattern' => '.*\S.*',
  692. ),
  693. 'password' => array(
  694. 'description' => __( 'The generated password. Only available after adding an application.' ),
  695. 'type' => 'string',
  696. 'context' => array( 'edit' ),
  697. 'readonly' => true,
  698. ),
  699. 'created' => array(
  700. 'description' => __( 'The GMT date the application password was created.' ),
  701. 'type' => 'string',
  702. 'format' => 'date-time',
  703. 'context' => array( 'view', 'edit' ),
  704. 'readonly' => true,
  705. ),
  706. 'last_used' => array(
  707. 'description' => __( 'The GMT date the application password was last used.' ),
  708. 'type' => array( 'string', 'null' ),
  709. 'format' => 'date-time',
  710. 'context' => array( 'view', 'edit' ),
  711. 'readonly' => true,
  712. ),
  713. 'last_ip' => array(
  714. 'description' => __( 'The IP address the application password was last used by.' ),
  715. 'type' => array( 'string', 'null' ),
  716. 'format' => 'ip',
  717. 'context' => array( 'view', 'edit' ),
  718. 'readonly' => true,
  719. ),
  720. ),
  721. );
  722. return $this->add_additional_fields_schema( $this->schema );
  723. }
  724. }