I need to fetch a page inside my Wordpress blog admin area. The following script:
function fetchAdminPage() {
var url = "http://www.mydomain.invalid/wp/wp-admin/wp-login.php";
var options = {
"method": "post",
"payload": {
"log": "admin",
"pwd": "password",
"wp-submit": "Login",
"redirect_to":"http://www.mydomain.invalid/wp/wp-admin/edit-comments.php",
"testcookie": 1
}
};
var response = UrlFetchApp.fetch(url, options);
...
}
is executed without errors. Anyway, response.getContentText() returns the login page, and I am not able to access the page http://www.mydomain.invalid/wp/wp-admin/edit-comments.php which is the one I want to fetch.
Any idea on how to do this?
There might be an issue with Google Apps Scripts and post-ing to a URL that gives you back a redirection header.
It seems like it might not be possible to follow the redirect with a post - here's a discussion on the issue -
https://issuetracker.google.com/issues/36754794
Would it be possible, if you modify your code to not follow redirects, capture the cookies and then do a second request to your page? I haven't actually used GAS, but here's my best guess from reading the documentation:
function fetchAdminPage() {
var url = "http://www.mydomain.invalid/wp/wp-admin/wp-login.php";
var options = {
"method": "post",
"payload": {
"log": "admin",
"pwd": "password",
"wp-submit": "Login",
"testcookie": 1
},
"followRedirects": false
};
var response = UrlFetchApp.fetch(url, options);
if ( response.getResponseCode() == 200 ) {
// Incorrect user/pass combo
} else if ( response.getResponseCode() == 302 ) {
// Logged-in
var headers = response.getAllHeaders();
if ( typeof headers['Set-Cookie'] !== 'undefined' ) {
// Make sure that we are working with an array of cookies
var cookies = typeof headers['Set-Cookie'] == 'string' ? [ headers['Set-Cookie'] ] : headers['Set-Cookie'];
for (var i = 0; i < cookies.length; i++) {
// We only need the cookie's value - it might have path, expiry time, etc here
cookies[i] = cookies[i].split( ';' )[0];
};
url = "http://www.mydomain.invalid/wp/wp-admin/edit-comments.php";
options = {
"method": "get",
// Set the cookies so that we appear logged-in
"headers": {
"Cookie": cookies.join(';')
}
};
response = UrlFetchApp.fetch(url, options);
};
};
...
}
You would obviously need to add some debugging and error handling, but it should get you through.
What happens here is that we first post to the log-in form. Assuming that everything goes correctly, that should give us back a response code of 302(Found). If that's the case, we will then process the headers and look specifically for the "Set-Cookie" header. If it's set, we'll get rid of the un-needed stuff and store the cookies values.
Finally we make a new get request to the desired page on the admin( in this case /wp/wp-admin/edit-comments.php ), but this time we attach the "Cookie" header which contains all of the cookies acquired in the previous step.
If everything works as expected, you should get your admin page :)
I would advise on storing the cookies information(in case you're going to make multiple requests to your page) in order to save time, resources and requests.
Again - I haven't actually tested the code, but in theory it should work. Please test it and come back to me with any findings you make.
Related
I'm trying to send images to a whatsapp user via Twilio, but I'm always getting 400 error
(400) Bad Request. -> {"code": 21620, "message": "Media urls: https://image-charts.com/chart?cht=pd&chd=a:10238,10200&chs=400x300&chdls=9e9e9e,10&chco=FFC00C,03A9F4&chtt=Ocupaci%C3%B3n%20en%20almac%C3%A9n&chdl=Contratado%7COcupado&chli=100.37%25&chl=10238%7C10200&chdlp=b&chof=.png are invalid. Please use only valid http and https urls", "more_info": "https://www.twilio.com/docs/errors/21620", "status": 400}
The image works fine in browser or when is send directly to the user directly in whatsapp
I'm encoding the image like this (js):
img_url = encodeURI(img_url);
Any ideas or workaround?
thanks
It seems not every parameter was encoded, example: chd=a:10238,10200 should be chd=a%3A10238%2C10200.
encodeURI won't produce URL safe, you will need to rely on encodeURIComponent but it will encode the whole url ('/chart?' included) so it's not an option either.
If you are doing this server-side from NodeJS:
// node v10+
const url = require('url');
const querystring = require('querystring');
function encode_uri(chart_url) {
const parsed_url = url.parse(chart_url);
// parse the querytring and then encode every parameter values
parsed_url.query = querystring.stringify(querystring.parse(parsed_url.query));
// generate the full url
return url.format({
...parsed_url,
href:undefined,
path:undefined,
search:'?' + parsed_url.query,
});
}
let chart_url = 'https://image-charts.com/chart?cht=pd&chd=a:10238,10200&chs=400x300&chdlp=b&chdls=9e9e9e,10&chco=FFC00C,03A9F4&chtt=Ocupación en almacén&chli=100.37%&chl=10238|10200&chdl=Contratado|Ocupado&chof=.png';
console.log(encode_uri(chart_url));
// Fully encoded URL
// https://image-charts.com/chart?cht=pd&chd=a%3A10238%2C10200&chs=400x300&chdlp=b&chdls=9e9e9e%2C10&chco=FFC00C%2C03A9F4&chtt=Ocupaci%C3%B3n%20en%20almac%C3%A9n&chli=100.37%25&chl=10238%7C10200&chdl=Contratado%7COcupado&chof=.png
If you are doing this on the browser side then use:
function encode_uri(chart_url) {
// use https://developer.mozilla.org/en-US/docs/Web/API/URL
// not supported in IE10
const parsed_url = new URL(chart_url);
// encode every parameter values
[...parsed_url.searchParams.keys()].forEach(key => parsed_url.searchParams.set(key, encodeURIComponent(parsed_url.searchParams.get(key))));
// generate back the full url
return parsed_url.toString();
}
let chart_url = 'https://image-charts.com/chart?cht=pd&chd=a:10238,10200&chs=400x300&chdlp=b&chdls=9e9e9e,10&chco=FFC00C,03A9F4&chtt=Ocupación en almacén&chli=100.37%&chl=10238|10200&chdl=Contratado|Ocupado&chof=.png';
console.log(encode_uri(chart_url));
// https://image-charts.com/chart?cht=pd&chd=a%253A10238%252C10200&chs=400x300&chdlp=b&chdls=9e9e9e%252C10&chco=FFC00C%252C03A9F4&chtt=Ocupaci%25C3%25B3n%2520en%2520almac%25C3%25A9n&chli=100.37%2525&chl=10238%257C10200&chdl=Contratado%257COcupado&chof=.png
I am trying to fetch local api made in asp.net api which is running in https://localhost:44388/. When I tried to fetch get request it responds ok but return html not json. The problem might occur by two reasons:
1.typo in url (But I checked in my browser, it worked)
2.Server restart needed
What might be the problem with my code?
componentDidMount(){
var proxyUrl = "http://127.0.0.1:3000/";
var targetUrl = "https://127.0.0.1:44388/api/product/getproducts";
fetch(proxyUrl+targetUrl, {
method:'GET',
headers:{
'Access-Control-Allow-Origin':'*',
'Access-Control-Allow-Mehods': '*',
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Credentials':'*',
'Content-type':'application/json'
}
})
.then(data=>{
if(!data.ok){
throw new Error("Error");
}else{
return data.json();
}
})
.then(data=>this.setState({products:data}))
}
when you give parameter as:proxyUrl+targetUrl,
actually the url which you have called is :
http://127.0.0.1:3000/https://127.0.0.1:44388/api/product/getproducts
which does not seems to be correct.
i think the structure of url you'v given to fetch function is wrong.
I have a form in googlescript where I can add a user to a sheet.
Is there a way to implement some lines in that code so the script adds a post on a wordpress page?
I read that it's possible via wp_insert_post , but I have no idea how that works in my case.
EDIT:
As Spencer suggested I tried to do it via WP REST API.
The following code seems to be working .............
function httpPostTemplate() {
// URL for target web API
var url = 'http://example.de/wp-json/wp/v2/posts';
// For POST method, API parameters will be sent in the
// HTTP message payload.
// Start with an object containing name / value tuples.
var apiParams = {
// Relevant parameters would go here
'param1' : 'value1',
'param2' : 'value2' // etc.
};
// All 'application/json' content goes as a JSON string.
var payload = JSON.stringify(apiParams);
// Construct `fetch` params object
var params = {
'method': 'POST',
'contentType': 'application/json',
'payload': payload,
'muteHttpExceptions' : true
};
var response = UrlFetchApp.fetch(url, params)
// Check return code embedded in response.
var rc = response.getResponseCode();
var responseText = response.getContentText();
if (rc !== 200) {
// Log HTTP Error
Logger.log("Response (%s) %s",
rc,
responseText );
// Could throw an exception yourself, if appropriate
}
else {
// Successful POST, handle response normally
Logger.log( responseText );
}
}
But I get the error:
[16-09-28 21:24:29:475 CEST] Response (401.0)
{"code":"rest_cannot_create","message":"Sorry, you are not allowed to
create new posts.","data":{"status":401}}
Means: I have to authenticate first.
I installed the plugin: WP REST API - OAuth 1.0a Server
I setup a new user and got a client key and client user.
But from here I have no clue what to do : /
It is possible. Wordpress has a REST API. I can be found at:
http://v2.wp-api.org/
You will use the UrlFetchApp Service to access this api. Documentation can be found at:
https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app
Read the docs and try to write some code. It you get stuck post the code that is confusing you here and I'll update this answer.
You should add you authentification in the header :
var headers = {
... ,
'Authorization' : 'Basic ' + Utilities.base64Encode('USERNAME:PASSWORD'),
};
And then add your header in your parameters :
var params = {
'method': 'POST',
'headers': headers,
'payload': JSON.stringify(payload),
'muteHttpExceptions': true
}
And then use UrlfetchApp.fetch
var response = UrlFetchApp.fetch("https://.../wp-json/wp/v2/posts/", params)
Logger.log(response);
You need to pass the basic auth, like this:
// Construct `fetch` params object
var params = {
'method': 'POST',
'contentType': 'application/json',
'payload': payload,
'muteHttpExceptions' : true,
"headers" : {
"Authorization" : "Basic " + Utilities.base64Encode(username + ":" + password)+"",
"cache-control": "no-cache"
}
};
thank you for giving me these important links.
<3
I installed WP REST API and the OAuth plugin.
In the documentation is written:
Once you have WP API and the OAuth server plugins activated on your
server, you’ll need to create a “client”. This is an identifier for
the application, and includes a “key” and “secret”, both needed to
link to your site.
I couldn't find out how to setup a client?
In my GoogleScriptCode according to the WP API I get the error:
{"code":"rest_cannot_create","message":"Sorry, you are not allowed to create new posts.","data":{"status":401}}
Edit: I found it - it's under User/Application
I'll try to figure it out and get back to you later.
I'm trying to use google apps script to login to an ASP.Net website and scrape some data that I typically have to retrieve manually. I've used Chrome Developer tools to get the correct payload names (TEXT_Username, TEXT_Password, _VIEWSTATE, _VIEWSTATEGENERATOR), I also got a ASP Net session Id to send along with my Post request.
When I run my function(s) it returns a Response Code = 200 if followRedirects is set to false and returns Response Code = 302 if followRedirects is set to true. Unfortunately in neither case do the functions successfully authenticate the website. Instead the HTML returned is that of the Login Page.
I've tried different header variants and parameters, but I can't seem to successfully login.
Couple of other points. When I do the login in Chrome using the Developer tools, the response code appears to be 302 Found.
Does anyone have any suggestions on how I can successfully login to this site. Do you see any errors in my functions that could be the cause of my problems. I'm open to any and all suggestions.
My GAS functions follow:
function login(cookie, viewState,viewStateGenerator) {
var payload =
{
"__VIEWSTATE" : viewState,
"__VIEWSTATEGENERATOR" : viewStateGenerator,
"TEXT_Username" : "myUserName",
"TEXT_Password" : "myPassword",
};
var header = {'Cookie':cookie};
Logger.log(header);
var options =
{
"method" : "post",
"payload" : payload,
"followRedirects" : false,
"headers" : header
};
var browser = UrlFetchApp.fetch("http://tnetwork.trakus.com/tnet/Login.aspx?" , options);
Utilities.sleep(1000);
var html = browser.getContentText();
var response = browser.getResponseCode();
var cookie2 = browser.getAllHeaders()['Set-Cookie'];
Logger.log(response);
Logger.log(html);
}
function loginPage() {
var options =
{
"method" : "get",
"followRedirects" : false,
};
var browser = UrlFetchApp.fetch("http://tnetwork.trakus.com/tnet/Login.aspx?" , options);
var html = browser.getContentText();
// Utilities.sleep(500);
var response = browser.getResponseCode();
var cookie = browser.getAllHeaders()['Set-Cookie'];
login(cookie);
var regExpGen = new RegExp("<input type=\"hidden\" name=\"__VIEWSTATEGENERATOR\" id=\"__VIEWSTATEGENERATOR\" value=\"(.*)\" \/>");
var viewStateGenerator = regExpGen.exec(html)[1];
var regExpView = new RegExp("<input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\" value=\"(.*)\" \/>");
var viewState = regExpView.exec(html)[1];
var response = login(cookie,viewState,viewStateGenerator);
return response
}
I call the script by running the loginPage() function. This function obtains the cookie (session id) and then calls the login function and passes along the session id (cookie).
Here is what I see in the Google Developer tools Network section when I login using Google's Chrome browser:
Remote Address: 66.92.89.141:80
Request URL: http://tnetwork.trakus.com/tnet/Login.aspx
Request Method: POST
Status Code:302 Found
**Request Headers** view source
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate
Accept-Language: en-US,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Content-Length: 252
Content-Type:application/x-www-form-urlencoded
Cookie: ASP.NET_SessionId=jayaejut5hopr43xkp0vhzu4; userCredentials=username=myUsername; .ASPXAUTH=A54B65A54A850901437E07D8C6856B7799CAF84C1880EEC530074509ADCF40456FE04EC9A4E47D1D359C1645006B29C8A0A7D2198AA1E225C636E7DC24C9DA46072DE003EFC24B9FF2941755F2F290DC1037BB2B289241A0E30AF5CB736E6E1A7AF52630D8B31318A36A4017893452B29216DCF2; __utma=260442568.1595796669.1421539534.1425211879.1425214489.16; __utmc=260442568; __utmz=260442568.1421539534.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=190106350.1735963725.1421539540.1425152706.1425212185.18; __utmc=190106350; __utmz=190106350.1421539540.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Host:tnetwork.trakus.com
Origin:http://tnetwork.trakus.com
Referer:http://tnetwork.trakus.com/tnet/Login.aspx?
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36
**Form Dataview** sourceview URL encoded
__VIEWSTATE: O7YCnq5e471jHLqfPre/YW+dxYxyhoQ/VetOBeA1hqMubTAAUfn+j9HDyVeEgfAdHMl+2DG/9Gw2vAGWYvU97gml5OXiR9E/9ReDaw9EaQg836nBvMMIjE4lVfU=
__VIEWSTATEGENERATOR:F4425990
TEXT_Username:myUsername
TEXT_Password:myPassword
BUTTON_Submit: Log In
Update: It appears that the website is using an HttpOnly cookie. As a result, I don't think I am capturing the whole cookie and therefore my header is not correct. As a result, I believe I need to set followRedirects to false and handle the redirect and cookie manually. I'm currently researching this process, but welcome input from anyone who has been down this road.
I was finally able to successfully login to the page. The issue seems to be that the urlFetchApp was unable to follow the redirect. I credit this stackoverflow post: how to fetch a wordpress admin page using google apps script
This post described the following process that led to my successful login:
Set followRedirect to false
Submit the post and capture the cookies
Use the captured cookie to issue a get with the appropriate url.
Here is the relevant code:
var url = "http://myUrl.com/";
var options = {
"method": "post",
"payload": {
"TEXT_Username" : "myUserName",
"TEXT_Password" : "myPassword",
"BUTTON_Submit" : "Log In",
},
"testcookie": 1,
"followRedirects": false
};
var response = UrlFetchApp.fetch(url, options);
if ( response.getResponseCode() == 200 ) {
// Incorrect user/pass combo
} else if ( response.getResponseCode() == 302 ) {
// Logged-in
var headers = response.getAllHeaders();
if ( typeof headers['Set-Cookie'] !== 'undefined' ) {
// Make sure that we are working with an array of cookies
var cookies = typeof headers['Set-Cookie'] == 'string' ? [ headers['Set-Cookie'] ] : headers['Set-Cookie'];
for (var i = 0; i < cookies.length; i++) {
// We only need the cookie's value - it might have path, expiry time, etc here
cookies[i] = cookies[i].split( ';' )[0];
};
url = "http://myUrl/Calendar.aspx";
options = {
"method": "get",
// Set the cookies so that we appear logged-in
"headers": {
"Cookie": cookies.join(';')
}
}
...
I notice that the provided Chrome payload includes BUTTON_Submit: Log In but your POST payload does not. I have found that for POSTs in GAS things go much more smoothly if I explicitly set a submit variable in my payload objects. In any case, if you're trying to emulate what Chrome is doing, this is a good first step.
So in your case, it's a one line change:
var payload =
{
"__VIEWSTATE" : viewState,
"__VIEWSTATEGENERATOR" : viewStateGenerator,
"TEXT_Username" : "myUserName",
"TEXT_Password" : "myPassword",
"BUTTON_Submit" : "Log In"
};
I'm encountering issues with a dashlet that I'm trying to develop for Alfresco. It's a simple drag and drop file upload dashlet using HTML 5's drag and drop and file APIs. For the drop event listener, I call the following function which is seemingly the cause of all the problems:
function handleFileSelect(evt) {
var files = evt.target.files || evt.dataTransfer.files,
tmpForm, tmpDest, tmpMeta, tmpType, tmpName, tmpData;
dropZone.className = "can-drop";
evt.stopPropagation();
evt.preventDefault();
for (var i=0,f;f=files[i];i++) {
tmpForm = document.createElement('form');
tmpDest = document.createElement('input');
tmpDest.setAttribute('type', 'text');
tmpDest.setAttribute('name', 'destination');
tmpDest.setAttribute('value', destination);
tmpForm.appendChild(tmpDest);
tmpMeta = document.createElement('input');
tmpMeta.setAttribute('type', 'text');
tmpMeta.setAttribute('name', 'mandatoryMetadata');
tmpMeta.setAttribute('value', window.metadataButton.value);
tmpForm.appendChild(tmpMeta);
tmpType = document.createElement('input');
tmpType.setAttribute('type', 'text');
tmpType.setAttribute('name', 'contenttype');
tmpType.setAttribute('value', "my:document");
tmpForm.appendChild(tmpType);
tmpName = document.createElement('input');
tmpName.setAttribute('type', 'text');
tmpName.setAttribute('name', 'filename');
tmpName.setAttribute('value', f.name);
tmpForm.appendChild(tmpName);
tmpData = document.createElement('input');
tmpData.setAttribute('type', 'file');
tmpData.setAttribute('name', 'filedata');
tmpData.setAttribute('value', f);
tmpForm.appendChild(tmpData);
Alfresco.util.Ajax.request({
url: Alfresco.constants.PROXY_URI_RELATIVE + "api/upload",
method: 'POST',
dataForm: tmpForm,
successCallback: {
fn: function(response) {
console.log("SUCCESS!!");
console.dir(response);
},
scope: this
},
failureCallback: {
fn: function(response) {
console.log("FAILED!!");
console.dir(response);
},
scope: this
}
});
}
}
The server responds with a 500, and if I turn on debug level logging for web scripts, upload.post returns with:
DEBUG [repo.jscript.ScriptLogger] ReferenceError: "formdata" is not defined.
Which, to me at least, indicates that the form above isn't getting submitted properly (if at all). When digging through it all with Chrome dev tools, I notice that that request payload looks drastically different from something such as a REST client. The above code results in the request using Content-Type: application/x-www-form-urlencoded whereas using a REST client, or Alfresco Share's standard uploader(s) are using Content-Type: multipart/form-data. If I need to submit the form using multipart/form-data, what is the easiest way to write out the request body (with the boundaries, Content-Disposition's, etc...) to include the file being uploaded?
I ditched the idea of creating a form HTML Element through javascript, and assume that if a browser supports the File API, and the Drag and Drop API, that they will likely also support the XMLHttpRequest2 API. As per HTML5 File Upload to Java Servlet, The above code now reads:
function handleFileSelect(evt) {
var files = evt.target.files || evt.dataTransfer.files,
xhr = new XMLHttpRequest();
dropZone.className = "can-drop";
evt.stopPropagation();
evt.preventDefault();
for (var i=0,f;f=files[i];i++) {
formData = new FormData();
formData.append('destination', destination);
formData.append('mandatoryMetadata', window.metadataButton.value);
formData.append('contenttype', "my:document");
formData.append('filename', f.name);
formData.append('filedata', f);
formData.append('overwrite', false);
xhr.open("POST", Alfresco.constants.PROXY_URI_RELATIVE + "api/upload");
xhr.send(formData);
}
}
with the necessary event listeners to be added later. It would seem that the Alfresco AJAX methods that come stock and standard heavily modify the underlying requests being made, making it very difficult for one to simply send a FormData() object.