I know it's a little bit complicated but there's a lot of benefits for me using this scenario,
I'm working on a WordPress project and need to verify the user's license so I made an AJAX form has the required fields from user, Unfortunately the verification API needs a Secret Key (Belongs to me and cannot include in the client's project) so I made an external WordPress website (Subfolder on my website) and develop two small [Plugin & Theme].
- In the client side
I prepare the user sensitive data to send to my website using WordPress function (wp_safe_remote_get) like this...
$request_url = 'HTTPS://MY_WEBSITE/verify?api=XXX&some=XXX&some=XXX';
$response = wp_safe_remote_get(
$request_url,
array(
'timeout' => 300
)
);
- On my Website
The theme has an [3 files: style.css, functions.php and verify.php] and the verify.php has this line [ do_action( 'xxx' ) ].
The plugin has [ add_action( 'xxx' ) ] in the constructor to do the verification process and of course I included the My SECRET KEY here ..
Collect $_GET params and verify then return an array with the result using [print_r] so the final result exactly like this from browser Inspect Element
body_tag>
Array (
[API_RESULT] => Array ( 'verified' => true );
)
/body>
The Issue
In the client side I received the previous array BUT besides a lot of included scripts and css paths belongs to my WordPress website, So...
I need to receive only the response body without the other included files.
Is that secure enough?
Is there a solution for this scenario something like create a PHP file rather than a WordPress site but will be more secure??
Thanks for your help.
1. Server Side
If you need to send an array to the client side, Do your processes you need then print serialized array.
index.php
do_action( 'YOUR_ACTION_NAME', 'VAR_1', 'VAR_2' );
class_processes.php
function __construct() {
add_action( 'YOUR_ACTION_NAME', array( &$this, '__Trigger_User_Action' ), 10, 2 );
}
public function __Trigger_User_Action( $seller_name = '', $token_type ) {
$user_final_data = array();
// Do Some
die( serialize( $user_final_data ) );
}
2. Client Side
$request_url = 'https://DOMAIN.XXX/user_processes?user_name=XXX&code=XXX';
$response = wp_safe_remote_get(
$request_url,
array(
'timeout' => 300
)
);
if( ! is_wp_error( $response ) ) {
$body_data = wp_remote_retrieve_body( $response );
if( ! is_wp_error( $body_data ) ) {
$user_server_data = #unserialize( $body_data );
}
}
Now $user_server_data contains the the array you passed in [print] function through your server.
Related
I want to get post from a site with BasicAuth protection.
To get the post from the site I'm using the following code (from here):
// Disable direct file access.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Get posts via REST API.
*/
function get_posts_via_rest() {
// Initialize variable.
$allposts = '';
// Enter the name of your blog here followed by /wp-json/wp/v2/posts and add filters like this one that limits the result to 2 posts.
$response = wp_remote_get( 'https://www.sumydesigns.com/wp-json/wp/v2/posts?per_page=2' );
// Exit if error.
if ( is_wp_error( $response ) ) {
return;
}
// Get the body.
$posts = json_decode( wp_remote_retrieve_body( $response ) );
// Exit if nothing is returned.
if ( empty( $posts ) ) {
return;
}
// If there are posts.
if ( ! empty( $posts ) ) {
// For each post.
foreach ( $posts as $post ) {
// Use print_r($post); to get the details of the post and all available fields
// Format the date.
$fordate = date( 'n/j/Y', strtotime( $post->modified ) );
// Show a linked title and post date.
$allposts .= '' . esc_html( $post->title->rendered ) . ' ' . esc_html( $fordate ) . '<br />';
}
return $allposts;
}
}
It works.
But the site I want to get the post from uses a BasicAuth protection.
So there is no result.
I read that the Rest API couldn't handle BasicAuth.
And I have to use a plugin like the Basic Authentication handler
But I'm not sure how to use it.
Is there a way to integrate it in the code?
Within WordPress WP_Http are made through the wp_remote_get() function.
Performs an HTTP request using the GET method and returns its response.
In short wp_remote_get() act as a wrapper for WP_Http.
Performs an HTTP request using the GET method and returns its response.
As per BasicAuth documentation:
<?php
$args = array(
'headers' => array(
//here the credentials are referring to a wordpress account on the targeted website
'Authorization' => 'Basic ' . base64_encode( $username . ':' . $password ),
),
);
wp_remote_get('https://...com/wp-json/wp/v2/posts', $args);
//...
You can definitely prevent api access (but that's not natively the case).
Keep in mind that, using BasicAuth will probably not be useful. When people go for the hassle that is securing the api, usually it requires an admin access level to access the api.
An alternative would be to use a scraper like puppeteer to re-create a api from scratch and host it on a separate server. (sounds complicated but it's pretty easy)
I have 2 WordPress sites in 2 different domains. One is my server & another one is my client site. In my server WordPress, I have a custom WordPress REST API endpoint that accepts POST requests. The client will send some custom data to the server. Then the server processes the data & returns an output.
The issue is that I can't use any authentication method here. The API must be public & any WordPress site can send some data to the server. In the server's REST API callback function, I have added some custom sanitization & validation. Also, nothing to be saved in the DATABASE.
I have added the below code snippet to make a public API endpoint in my server.
add_action( 'rest_api_init', 'register_rest_route_abcd' );
function register_rest_route_abcd() {
register_rest_route(
'mycustomapi', 'v1/abcd',
array(
'methods' => 'POST',
'callback' => array( 'my_callback_function'),
'permission_callback' => '__return_true',
)
);
}
Then in the client file, I have used wp_safe_remote_post to post my custom data.
wp_safe_remote_post( $target_url, array('body' => $request_data) )
The requested data is custom data & there are no authentication parameters there. I got the error given below.
{"code":"rest_not_logged_in","message":"You are not currently logged in.","data":{"status":401}}
I need a public API endpoint where anyone can submit some data.
NOTE: I have a custom string like a key in the submitted data & can I use that string to authenticate API response?
Update: The issue was automatically resolved. I haven't done any changes in the code or file.
I have attached the code snippet that will be useful for someone else. Public API that accepts POST requests is always vulnerable. So be careful. I believe that later we can get some suggestions regarding it.
In server-side
add_action( 'rest_api_init', 'register_rest_route_abcd');
function register_rest_route_abcd() {
register_rest_route(
'myapi', 'v1/myroute',
array(
'methods' => 'POST,GET',
'callback' => 'my_callback_function',
'permission_callback' => '__return_true',
)
);
}
function my_callback_function($request){
//Do logic here
// Prepare response
$response = array();
$response['status'] = true;
$response['message'] = 'done';
return $response;
}
In clint side
add_action( 'template_redirect', 'ed45r_my_action', 5 );
function ed45r_my_action(){
$target_url = 'http://localhost/server-sys/wp-json/myapi/v1/myroute';
$data = array(
'key_1' => 'value_1',
'key_2' => 'value_2',
);
$request = wp_safe_remote_get( $target_url, array('body' => $data) );
if(is_wp_error($request) || wp_remote_retrieve_response_code($request) != 200){
// Know the errror
} else {
$response = wp_remote_retrieve_body( $request );
$response = json_decode($response, true);
// Process the response
}
}
In my case, the action is not a template_redirect. It is a form submission.
I built a custom Wordpress plugin. The plugin frontend is a Facebook React JS application that is embedded into a Wordpress page via a shortcode. It uses the Wordpress REST API exclusively to send and retrieve JSON between the client browser and Wordpress. Wordpress is acting as the middleman in this scenario. The REST routes handling the client requests just call a backend REST API and return the responses to the client from the other server.
I've just added a new feature to the app that allows the user to download a PDF file that's dynamically generated by a different backend server (not Wordpress). My plan was to just add another route on the Wordpress REST API that would call the backend server and return the PDF file generated by that other server. Wordpress would basically just proxy the request to the backend server and return the response back to the client browser.
However, when I try to do that the response body is a string instead of the raw byte array returned from the backend server. I can make the request to the backend server directly and it properly returns the PDF file (e.g. http://default-internal-backend-server.example.com/api/v1/quote/asdf123/pdf).
What's the proper way to have a Wordpress Plugin handle a REST request (e.g. https://example.com/wp-json/my-plugin/v1/quote/asdf123/pdf) and return the raw, untouched, response from an upstream server?
For example, I was doing this:
On the UI of the app I have a simple anchor tag like this:
<a href="http://example.com/wp-json/my-plugin/quote/asdf123/pdf" download="quote.pdf">
<span>Download PDF</span>
</a>
The above URL is registered in the REST Routes of the plugin as so:
class My_Plugin_REST_Controller extends WP_REST_Controller {
// ****
register_rest_route( 'my-plugin', '/quote/(?P<id>\w+)/pdf',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_quote_pdf' ),
'args' => array()
)
)
);
public function get_quote_pdf( $request ) {
$api_service = API_Service::get_instance();
$response = $api_service->getQuotePdf( $request );
$http_response = new WP_REST_Response( $response, 200 );
$http_response->header('Content-Type', 'application/pdf');
return $http_response;
}
// ****
}
class API_Service {
public function getQuotePdf( $request ) {
$curl = curl_init();
$default_options = array(
'url' => 'http://default-internal-backend-server.example.com'
);
$api_options = get_option( 'my_plugin_api', $default_options );
$api_url = $api_options['url'] . '/api/v1/quote/' . $request['id'] . '/pdf'
curl_setopt_array($curl, array(
CURLOPT_URL => $api_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"Accept: application/pdf",
"Cache-Control: no-cache"
)
));
$response = curl_exec( $curl );
$err = curl_error( $curl );
curl_close( $curl );
if ( $err ) {
return null;
} else {
return $response;
}
}
}
Wordpress is properly handling the request from the client JavaScript application, the backend server is being called properly, the backend server is returning the PDF file.
However, with the above example, Wordpress is returning a string representation of the PDF instead of the raw bytes returned by the external server. I had to fight with the WP_Rest_Response to get it to set the Content-Type to appplication/pdf as well. If I set the Content-Length header it would change the Content-Type to application/json for no apparent reason.
How can I return the raw bytes instead of a string version of the response?
My next step is to just remove having Wordpress involved with this at all and link to a different URL in the browser (e.g. https://my.example.com/quote/asdf123/pdf) that uses a reverse proxy to get to the internal server directly.
I did read that PHP doesn't have a native data type of byte[] which could be the limiting factor.
i have a question concerning wp rest api custom endpoints
The idea is i am trying to update database on my local server with data from database on remote site.the data is for a settings page
I have succeeded in developing custom end points with GET methods successfully and i have also succeeded in getting data from database to the get end point.
My question is with the post request. How do i develop the callback function to receive data from remote site and update local database.
Below is my code
function register_custom_route(){
register_rest_route( 'silentblast-dashboard/v1', '/getsetting/(?P<id>\d+)', array(
array(
'methods' => 'GET',
'callback' => 'retrieve_settings_data',
),
array(
'methods' => 'POST',
'callback' => 'update_settings_data',
)
));
}
function retrieve_settings_data($data){
$out = get_option( 'buddysettings');
return $out;
}
function update_settings_data( $posts ){
}
Now secondly, i tried to add this to the retrieve_settings_data() function.
$url(remote url) = 'http://websiteproject.ca/blastbuilder/demo/wp-json/silentblast-dashboard/v1/getsetting/';
$response = wp_remote_get( $url );
$posts = wp_remote_retrieve_body( $response );
$posts = json_decode($posts);
$posts = (array) $posts;
$out = update_option( 'buddy_settings', $posts );
$outi = get_option( 'buddy_settings' );
return $outi ;
and it worked to update the local database with data from remote database but it updates only after i refresh the link localhost/wordpress/wp-json/silentblast-dashboard/v1/getsetting/ on the browser which is quite funny to me. This means if i change settings on spage. the remote database gets updated and posts its data to its endpoint remotesite.com/wp-json/silentblast-dashboard/v1/getsetting/ now the code actually gets the setting data from the remote custom route and updates the local database but i can only see the updates in the browser after reloading the custom route for my local site.
I am using artdarek-oauth-4-laravel for the Login to my website via Facebook, twitter and google.
Login part is working fine. But I want to get some more data from these api, like if user is registering through the google then I am looking for their general info as well as google contact list, or if the user is registering from Facebook then I am trying to get the /me and /friend-list etc.
Here, I am just taking the case of google.
I have set the config like this
'Google' => array(
'client_id' => '***********************************',
'client_secret' => '***********************************',
'scope' => array('userinfo_email', 'userinfo_profile', 'https://www.google.com/m8/feeds/'),
),
My Controller Function is this:-
public function loginWithGoogle()
{
$code = Input::get( 'code' );
$googleService = OAuth::consumer( 'Google' );
if ( !empty( $code ) )
{
$token = $googleService->requestAccessToken( $code );
// $result = json_decode( $googleService->request( 'https://www.googleapis.com/oauth2/v1/userinfo' ), true );
$result = json_decode( $googleService->request( 'https://www.google.com/m8/feeds/contacts/default/full' ), true );
echo json_encode($result);
}
else {
// get googleService authorization
$url = $googleService->getAuthorizationUri();
// return to google login url
return Redirect::to( (string)$url );
}
}
This code leads me to the google api and asks for all the permission that I have set in the scope of the service. Here once I got the access token after exchanging the code parameter with the api, I am calling the url to return me the contact list but it fails. And I am getting this message from the laravel :-Failed to request resource.
If I call the commented $result request, it returns me the result.
So, I wanted to know how can we use this library for the data other than login and register. In case of retrieving facebook friendlist the same thing happens but the login works. (My Facebook App has the permission to get friendlist).
Any help is appreciated.
Check this response, https://stackoverflow.com/a/26488136/434790.
It worked for me. The culprit: alt=json to be added to https://www.google.com/m8/feeds/contacts/default/full