I'm trying to create a google script that generates a HMAC signature using SHA512 for authentication to an API. Here is the code I'm using:
var SystemTimeMilli = Date.now()
var InputString = ('Some Text' + '\n' + SystemTimeMilli);
var PrivateKey = 'bEDtDJnW0y/Ll4YZitxb+D5sTNnEpQKH67EJRCmQCqN9cvGiB8+IHzB7HjsOs3mSlxLmu4aiPDRpe9anuWzylw==' //sample private key
var signature = Utilities.base64Encode(Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512, InputString, PrivateKey, Utilities.Charset.UTF_8));
Logger.log(signature);
This generates a string to the log but when compared to results using web based hash generators the results differ.
However if I use
var InputString = ('Some Text' + SystemTimeMilli);
without the \n the results generated in my Google Script and the web based hash generators match.
So I'm assuming the way Google Script is handling the new line is different to the web base generators but I can't figure out how to get them match or which one is the correct result.
EDIT
To add some further information:
Lets say SystemTimeMilli = 1234567890123
When I enter ('Some Text' + SystemTimeMilli) into my script using
bEDtDJnW0y/Ll4YZitxb+D5sTNnEpQKH67EJRCmQCqN9cvGiB8+IHzB7HjsOs3mSlxLmu4aiPDRpe9anuWzylw== as the PrivateKey
I get
oDVJk38b634G9Ykdqm+hVmSb5C8h6/re5/XG+MjyddTKygWcoZjWu0DfNGY/JWu5Be41zLDKfEZnuFcACrvs7w== returned.
Which is the same if I enter /account/balance1234567890123 into https://quickhash.com using SHA-512 (SHA2) as the Algorithm and Base64 Encoding as the Output Format.
However if I enter ('Some Text' + '\n' + SystemTimeMilli) in my script it returns 3sj1jbx1tQ4nc8XOkk3nW8TvG5zvCam2LN51fQWDXOKU5O/1KBAdzdp+YV+aAdYHWCY2x3jqCfbXKoOmfoD0KA==
But using
/account/balance
1234567890123
in quickhash.com returns something different. I've tried a whole bunch of different combinations but I never get the same result as my script.
I having trouble with getting my script to authenticate to the API so I really want to determine if I'm getting the correct HMAC to begin with.
Related
JSON.parse of a URLFetchApp on Google App Scripts changes all colons in a string to an equals sign. It's doing the exact opposite of what I thought JSON.parse is supposed to do. I tried parsing the same string in different places and even made a node.js fetch and output all works. Seems to be a problem with Google AppScript
Example:
CODE
var res = UrlFetchApp.fetch(url, options)
var text = res.getContentText()
var json = JSON.parse(text)
Logger.log(text)
Logger.log(json)
LOG:
{"status":{"timestamp":"2021-03-24T16:01:13.657Z","error_code":0,"error_message":null,"elapsed":20,"credit_count":1,"notice":null},"data":[{"id":1,"symbol":"BTC","name":"Bitcoin","amount":1,"last_updated":"2021-03-24T16:00:03.000Z","quote":{"GBP":{"price":41091.43869808855,"last_updated":"2021-03-24T16:00:21.000Z"}}}]}
{status={elapsed=20.0, timestamp=2021-03-24T16:01:13.657Z, error_message=null, notice=null, credit_count=1.0, error_code=0.0}, data=[{amount=1.0, symbol=BTC, last_updated=2021-03-24T16:00:03.000Z, id=1.0, name=Bitcoin, quote={GBP={price=41091.43869808855, last_updated=2021-03-24T16:00:21.000Z}}}]}
It's not a problem, it's a feature.
Instead of Logger.log(json) use Logger.log(JSON.stryngify(json)).
Related
Log Javascript object as string Google App Scripts
Objects with and without quotation marks
I need to retrieve the corresponding ID for a sectors name in our CRM application.
I am using the CRM's API through a get request in JavaScript. I have tried using encodeURI, encodeURIComponent, and escape. The get request works with some sector names but others do not work and return an error.
//The url was masked but the query is the same.
let URL = "http://domain/instance/api/data/v8.2/new_occurrencereportsectors?$select=new_occurrencereportsectorid,new_name&$filter=new_name eq ";
//This part works
let encodedURI = encodeURI(URL);
//This is the string I am trying to pass to the CRM API. This does not work.
let query = "Ontario - Outside the Greenbelt / Ontario - à l'extérieur de la ceinture";
//This is me trying out all the enocdings.
let encodedQuery = encodeURI(query);
encodedQuery = encodeURIComponent(encodedQuery);
encodedQuery = escape(encodedQuery);
//This is the string which I am using for the get request.
let finalString = encodedURI + encodedQuery;
//Note this is an example so I am just putting the printed.
//URL into the search bar in the browser.
console.log(finalString);
I expected the return value to be an ID which will be in the format {XXXXXXXX}.
The output is a syntax error. Please see below for the error message. I left out the inner error because it is lengthy and I didn't see it telling anything/
"error":{
"code":"","message":"Syntax error: character '%' is not valid at position 19 in 'new_name eq Ontario%2520-%2520Outside%2520the%2520Greenbelt%2520%2F%2520Ontario%2520-%2520%25C3%25A0%2520l'ext%25C3%25A9rieur%2520de%2520la%2520ceinture'."
So I figured out my issue. Dynamics CRM wasn't liking single quotes. The functions escape and encodeURI don't encode single quotes. But apparently in Dynamics CRM 365 single quotes are encoded by using two single quotes.
For example 'You're name', will become 'You''re name'. Leaving a single quote on the outside since the parameter has spaces.
Problem:
I'd like to be able to count the number of lines in a Google Document. For example, the script must return 6 for the following text.
There doesn't seem to be any reliable method of extracting '\n' or '\r' characters from the text though.
text.findText(/\r/g) //OR
text.findText(/\n/g)
The 2nd line of code is not supposed to work anyway, because according to GAS documentation, 'new line characters are automatically converted to /r'
If you are still looking for the solution, how about this answer? Unfortunately, I couldn't find the prepared methods for retrieving the number of lines in the Google Document. In order to do this, how about this workaround?
If the end of each line can be detected, the number of lines can be retrieved. So I tried to add the end markers of each line using OCR. I think that there might be several workarounds to solve your issue. So please think of this as one of them.
At Google Documents, when a sentence is over the page width, the sentence automatically has the line break. But the line break has no \r\n or \n. When users give the line break by the enter key, the line break has \r\n or \n. By this, the text data retrieved from the document has only the line breaks which were given by users. In your case, it seems that your document has the line breaks for after incididunt and consequat.. So the number of lines doesn't become 6.
I thought that OCR may be able to be used for this situation. The flow is as follows.
Convert Google Document to PDF.
Convert PDF to text data using OCR.
I selected "ocr.space" for OCR.
If you have already known APIs of OCR, you can try to do this.
When I used OCR of Drive API, the line breaks of \r\n or \n were not added to the converted text data. So I used ocr.space. ocr.space can add the line breaks.
Count \n in the converted text data.
This number means the number of lines.
The sample script for above flow is as follows. When you use this, please retrieve your apikey at "ocr.space". When you input your information and email to the form, you will receive an email including API key. Please use it to this sample script. And please read the quota of API. I tested this using Free plan.
Sample script :
var apikey = "### Your API key for using ocr.space ###";
var id = DocumentApp.getActiveDocument().getId();
var url = "https://docs.google.com/feeds/download/documents/export/Export?id=" + id + "&format=pdf&access_token=" + ScriptApp.getOAuthToken();
var blob = UrlFetchApp.fetch(url).getBlob();
var payload = {method: "POST", headers: {apikey: apikey}, payload: {file: blob}};
var ocrRes = JSON.parse(UrlFetchApp.fetch("https://api.ocr.space/Parse/Image", payload));
var result = ocrRes.ParsedResults.map(function(e){return e.ParsedText.match(/\n/g).length})[0];
Logger.log(result)
Result :
When your sentences are used, 6 is obtained as the result of script.
Note :
Even if the last line of the document has no \r\n or \n, the converted text data has \r\n at the end of all lines.
In this case, the precision of OCR is not important. The important point is to retrieve the line breaks.
I tested this script for several documents. In my environment, the correct number of line can be retrieved. But I'm not sure whether this script works for your environment. If this script cannot be used for your environment, I'm sorry.
As you noted in the comments there is no API to do retrieve the number of lines in Google Docs. This happens because the document is rendered dynamically in the client side, so the server doesn't know this number.
One possible solution is scraping the HTML of the Google Doc, because each line is redered with it's own divwith the "kix-lineview" class, however you will need to actually open the page in an iframe or headless browser and then scroll page by page to make them render and then be able to count the divs
After publishing your Google Doc with «Publish to the web» in «File» menu, use the URL in the following script:
var url = "https://docs.google.com/document/d/e/2PACX-1vSElK...iwUhaFo/pub";
var text = UrlFetchApp.fetch(url).getContentText();
var count = (text.match(/<\/br>/g) || []).length;
Logger.log(count.toString());
This is only handy if all of your document lines are ended in </br>, although there is the possibility to add any other variants:
var url = "https://docs.google.com/document/d/e/2PACX-1vSElK...iwUhaFo/pub";
var text = UrlFetchApp.fetch(url).getContentText();
var count1 = (text.match(/<\/br>/g) || []).length;
var count2 = (text.match(/<\/p>/g) || []).length;
var count3 = (text.match(/<hr>/g) || []).length;
var count = coun1 + coung2 + count3;
Logger.log(count);
We have a program where a user can input a line-break for another system.
the problem is when substituting a string with this line-break, it simply adds "\n".
for instance :
works :
var test = 'message';
test+='\n';
console.log("message " + test); // (doesnt show \n)
doesn't work :
var test="message";
var myLineBreakFromDatabase = getMyLineBreak();//simply returns a string containing "\n"
test+=myLineBreakFromDatabase;
test is now = "message\n" which is useless.
However, we using Javascript in the entire system so I guess just to figure out how to convert a line-break from string into control-characters?
The issue is that the string you are getting back from your database is actually something like "\\n", not "\n". Most likely you have some autoescaping going on somewhere, either before things get saved in the DB or before it gets to where you are using it in your app.
Hacky workaround that isn't a great idea but will probably "work":
var myLineBreakFromDatabase = getMyLineBreak().split('\\n').join('\n');
If your linebreaks for different systems are stored in a database where the linebreak for unix is \u000A and the one for windows is \u000D\u000A, then you could read the text into myLineBreak and then do something like:
var actualLineBreakString=JSON.parse('"' + myLineBreak + '"');
You'll have to make sure your javascript has the JSON object. If needed, it can be grabbed at json.org.
This approach works for any of the special characters. See here: http://msdn.microsoft.com/en-us/library/ie/2yfce773(v=vs.94).aspx
I have an array of JSON arrays whose values I am trying to encrypt with CryptoJS and then print for use in another file, where these values should be decrypted using a user-given passphrase.
But I am doing something wrong and I am getting "Uncaught Error: Malformed UTF-8 data" when decrypting the URL's.
encrypt.js:
var encrypted = CryptoJS.AES.encrypt(item[key], pass);
json[j] += encrypted.ciphertext.toString(CryptoJS.enc.Base64);
decrypt.js:
var decrypted = CryptoJS.AES.decrypt(item[key], pass);
html += '' + icons[key] + '';
I followed this example... Help, pretty please?
That error message usually means the data wasn't decrypted correctly, and the resulting plaintext bytes don't form valid UTF-8 characters.
A couple things to check:
First, make sure you're using the same password for both encryption and decryption. You may want to keep a hash of the correct password so that you can verify if the user gave the correct password before you use it for decryption.
Second, make sure that the value item[key] is a string before encrypting. CryptoJS can't encrypt JSON objects. You'll have to serialize it first.