GAS Wialon Local Remote API: Retrieve login data - json

Good day,
I have a Wialon Local server (GPS monitoring system) and am planning to update a shared Google sheet using time-driven installable triggers.
As per the Wialon documentation, I am able to get the desired response when entering my API call in a browser.
However, in GAS, I am getting the below error when trying to retrieve data from the response.
API Call:
let apiURL = `http://my.tracking.site.come/wialon/ajax.html?svc=token/login&params={"token":"5dce19710a5e26ab8b7b898XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXFCEED7DC03BC48FF5F8"}`
console.log(apiURL) // This URL works in a web browser as expected
var resText = UrlFetchApp.fetch(apiURL).getContentText() // error is raised on this line
console.log(resText)
The error:
11:48:27 AM Error
Exception: Invalid argument: http://my.tracking.site.come/wialon/ajax.html?svc=token/login&params={"token":"5dce19710a5e26ab8b7b898XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXFCEED7DC03BC48FF5F8"}
wialonLogin # wialon.gs:20
Kindly advise what I am doing wrong here as I have very little experience with both GAS and Wialon Remote API ... will appreciate any assitance.
Thanks.

Solution is to encode the URL.
let apiURL = `http://my.tracking.site.come/wialon/ajax.html?svc=token/login&params={"token":"5dce19710a5e26ab8b7b898XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXFCEED7DC03BC48FF5F8"}`
console.log(apiURL) // This URL works in a web browser as expected
var urlEncoded = encodeURI(apiURL);
var resText = UrlFetchApp.fetch(urlEncoded).getContentText() // error is raised on this line
console.log(resText)

Related

How to authenticate with Blockfrost.io API?

So I'm trying to import Cardano Blockchain data like address balance, amount staked, rewards etc into a Google Sheet. I found this project named Blockfrost.io which is an API for accessing Cardano blockchain info and import it into apps etc.
I think I can use this with Google Sheets. Problem is I don't know how to authenticate. I've searched all around on the documentation and it's not clear to me. It seems it's possible if your're building an app or using the terminal.
But I just want to authenticate in the easiest way possible like in the browser address bar that way it would be simple to get the JSON with the info I need and import the info to Google Sheets.
This is where it mentions the Authentication:
https://docs.blockfrost.io/#section/Authentication
I already have an API key to access. But how do I authenticate?
So if I want to check the blockchain metrics (mainnet1234567890 is a dummy key, I won't use mine here):
https://cardano-mainnet.blockfrost.io/api/v0/metrics/project_id:mainnet1234567890
The JSON will still output this:
status_code 403
error "Forbidden"
message "Missing project token. Please include project_id in your request."
Is there a correct way to authenticate on the browser address bar?
It's not clear which BlockFrost API you are using Go JavaScript etc...
the API key goes in as a header on the request object. I was manually trying to connect to the service and found for a request is what I had to do in C#...
var aWR = System.Net.WebRequest.Create(url);
aWR.Method = "GET";
aWR.Headers.Add("project_id", "mainnetTheRestOfMyKeyIsHidden");
var webResponse = aWR.GetResponse();
var webStream = webResponse.GetResponseStream();
var reader = new StreamReader(webStream);
var data = reader.ReadToEnd();
Later I realized I wanted to use their API cause they implement the rate limiter, something I would rather use than build... I use the following with the BlockFrost API in c#
const string apiKey = "mainnetPutYourKeyHere";
const string network = "mainnet";
// your key is set during the construction of the provider.
ServiceProvider provider = new ServiceCollection().AddBlockfrost(network, apiKey).BuildServiceProvider();
// from there individual services are created
var AddressService = provider.GetRequiredService<IAddressesService>();
// The call to get the data looked like
AddressTransactionsContentResponseCollection TXR = await AddressService.GetTransactionsAsync(sAddress, sHeightFrom, sHeightTo, 100, iAddressPage, ESortOrder.Desc, new System.Threading.CancellationToken());
// etc. your gonna need to set the bounds above in terms of block height
Try using postman and include the "project_id" header with api key as the value like this - it will clear up the concept for you I think:enter image description here

Cannot download file from Google Storage inside Cloud Function?

Im trying to perform a simple download of a .docx file info a buffer so I can handle it latter inside my Cloud Function. I've been using the whole Google Platform for multiple projects but never faced the need to download in server side, and now I need to, I just cant.
The following piece of code is not working, it just sends timeout as a response (I don't even get an error If I try to catch it or something):
var bucket = admin.storage().bucket("gs://myBucket.com");
return bucket.file("001Lineales/4x3-1/1000.docx").download().then((contents)=>{
var buffer = contents[0];
//I never get into this point
}).catch((error)=>{
//No error
})
I tried in a local NodeJs script and worked as expected. Also tried to perform a readStream() download but no luck, the function gets hang up in any try of downloading the file.
return new Promise((resolve,reject)=>{
var archivo = bucket.file(selectedCategory).createReadStream();
var array = [];
//Under here, never happens
archivo.on('data', (d) => {array.push(d)}).on("end",()=>{
var newbuff = Buffer.concat(array);
resolve(newbuff)
})
})
The file permissions read/write are public. And the main problem is that debugging is difficult cause Im not able to perform this function in local emulator.
What can I do? Thanks in advance.
EDIT:
Double checking a local call with emulator, I get the following error:
Anonymous caller does not have storage.objects.get access to the Google Cloud Storage object.
Double check the service account hat you've assigned to the Cloud Function and that you've given it the permission it needs.
I think Storage Object Viewer will give you what you need to read a file into the buffer.
By default, if you haven't changed it, the AppEngine's default service account gets used, which I don't think has access to Storage.

Accessing Google API from a web application

I've been trying for a couple of days now to crack this but have not had any success.
I have a web application that I want to use with Google Drives API.
I want the web application to check if there is an access token it can use and if not redirect to Google so the user can log in and grant access.
Seemingly a simple task but it's driving me mad! I've checked the Google documentation but it all seems to be geared around console applications
Google provides an interface UserService which stores details of the users using the application. If the users is not logged in redirect the user to login page using:
response.sendRedirect(userService.createLoginURL(request.getRequestURI()))
Later or if the user is logged in, redirect him to "Request for Permission" page using:
List<String> scopes = Arrays.asList(PlusScopes.PLUS_LOGIN,PlusScopes.PLUS_ME,PlusScopes.USERINFO_EMAIL,PlusScopes.USERINFO_PROFILE......); // Add/remove scopes as per your requirement
List<String> responseTypes = Arrays.asList("code");
GoogleAuthorizationCodeRequestUrl gAuthCode = new GoogleAuthorizationCodeRequestUrl(Google project client id, redirect url, scopes);
gAuthCode.setAccessType("offline");
gAuthCode.setClientId(Google project client id);
gAuthCode.setResponseTypes(responseTypes);
gAuthCode.setApprovalPrompt("force");
authURl = gAuthCode.toURL().toString();
response.sendRedirect(authURl);
Make sure you add all required scopes of the API methods you will be using. After the user has accepted, you will have to create a servlet with "/oauth2callback" mapping to get the authorization code.
request.getParameter("code")
In the same servlet using the code obtained, get refresh and access token making a rest call.
URL url = new URL("https://www.googleapis.com/oauth2/v3/token");
HttpURLConnection connection= (HttpURLConnection)url.openConnection();
connection.setRequestMethod("post");
connection.setDoInput(true);
connection.setDoOutput(true);
DataOutputStream dw= new DataOutputStream(connection.getOutputStream());
dw.writeBytes("code="+authorizationCode+"&client_id="+CLIENT_ID+"&client_secret="+CLIENT_SECRET+"&redirect_uri="+REDIRECT_URL+"&grant_type=authorization_code");
dw.flush();
dw.close();
InputStream inputStream= connection.getInputStream();
Parse the input stream to get your refresh token and access token and redirect the user to your landing page.
Now you have access token to query your api whose scopes were provided in authorization flow. Also you have a refresh token which can be used to regenerate new access token if the previously issued access token has expired.
You should be able to implement the OAuthHandshake using HTTP requests and a redirect URL to your web application. You can play around with the requests here to see what the headers and responses look like: https://developers.google.com/oauthplayground/
You can store the authorization code and tokens any way you like. You would have your web application refer to these tokens to see if they are expired. For example:
def getTokenFromFile(self):
creds = self.readCredsFromDisk()
# check if token is expired
expiration_time = datetime.datetime.strptime(creds['token_expiry'], '"%Y-%m-%dT%H:%M:%S.%f"')
if expiration_time < datetime.datetime.now():
self.refreshToken()
# reload creds
creds = self.readCredsFromDisk()
return creds['access_token']
I'm writing just a python script that does the handshake and saves the token to a plain text file. Any time the script runs a function to the Google API it will use this function.
The refresh function:
def refreshToken(self):
with open('client_secret.json') as s:
secret = json.load(s)
secret = secret['installed']
creds = self.readCredsFromDisk()
refresh_url = secret['token_uri']
post_data = {'client_id':secret['client_id'],
'client_secret':secret['client_secret'],
'refresh_token':creds['refresh_token'],
'grant_type':'refresh_token'}
headers = {'Content-type':'application/x-www-form-urlencoded'}
(resp, content) = self.http.request(refresh_url,
method='POST',
body=urlencode(post_data),
headers=headers)
content = json.loads(content)
creds['access_token'] = content['access_token']
date = datetime.datetime.now() + datetime.timedelta(seconds=content['expires_in'])
creds['token_expiry'] = json.dumps(date.isoformat())
self.writeCredsToDisk(json.dumps(creds))
You would write a function similar to this to trade the original authorization code and access code following the logic the OAuth Playground shows you.

Examine raw HTTP request from UrlFetchApp.fetch

I am working on something to interact with Amazon's REST API, but I keep getting an error in my response that points to a mal-formed request. I don't see any errors in the code (the parameter that it says is missing is clearly there), so I want to see the raw request that is being sent.
I don't see any available method that will let me do this. Maybe a server that will just include my request as its response?
Create your own endpoint that will echo to the screen your request. For example, to echo a GET request, send it to a script like this (that's been Publish > Deploy as web app):
function doGet(e) {
var test = 'Echo at ' + new Date() + '\n' + e.queryString;
return ContentService.createTextOutput(test);
}
A little late to the game (10 years) but you can now do this:
const requestResult = UrlFetchApp.getRequest(url, options);
Run it in debug mode and break after this executes to examine requestResult.
See: https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#getrequesturl,-params for an official description and a full explanation of the properties for the options parameter.

Unexpected Error Google Apps Script Fetch

I get an "Unexpected Error" from the following function:
function getBomgarFeedbackXML(){
var url = "https://help.tradingtechnologies.com/api/reporting.ns?" +
"username=xxxxxx&password=xxxxxx&generate_report=SupportCustExitSurvey&" +
"start_date=2000-01-01&duration=0&report_type=rep&id=all";
var response = UrlFetchApp.fetch(url).getContentText();
Logger.log(response);
return(Xml.parse(response, true));
}
The line that causes the error is:
var response = UrlFetchApp.fetch(url).getContentText();
I am able to fetch the URL programatically using other scripting languages, such as python
I have tried fetching the URL in my browser which I was able to do successfully
I can fetch "http://www.google.com" from Google apps script successfully
I get the following warning when navigating to the URL in chrome, could this be related to the issue ?
Any help is appreciated
Thanks
The last bit with the untrusted certs is the big clue here. Seems like the SSL cert associated with 'help.tradingtechnologies.com'is not valid or signed by a trusted CA per the Google Data Centers (from where the UrlFetch calls originate).
To work around this try this line of code instead of your UrlFetch call. Note the additional option for validateHttpsCertificates documented here.
var response = UrlFetchApp.fetch(url, {'validateHttpsCertificates':false}).getContentText();