I'm using Gigya Comment Notification service in my node app and trying generate a valid signature. I have followed this documentation, but my code generate wrong hash.
This is my code:
var crypto = require('crypto');
var params = [the notification object from the request];
var eventData = JSON.stringify(params.eventData);
var text = params.event + '_'
+ eventData + '_'
+ params.nonce + '_'
+ params.timestamp;
var secret = new Buffer('Qmxxxxxxxxxxxxx...xxxxxxw=', 'base64');
var hash = crypto.createHmac('sha1', secret).update(text).digest('base64');
if (hash !== params.signature) {
console.log('Not ok')
} else{
console.log('Ok')
}
I think the signature base (text variable) construction may not valid.
This is what my text variable contains (with fake datas):
newComment_[{"categoryID":"category","streamID":"stream","commentID":"123","comment":{"ID":"123","etc":"foobar","timestamp":1447078842653,"threadTimestamp":1447078842653,"status":"published"}}]_aaaaaaaa-bbbb-cccc-dddd-ffffffffffff_1447078842
How can I generate the right signature?
Your signature base construction looks correct, although a nonce doesn't generally have any dashes in it.
The most common reason for a generating an incorrect signature is using the incorrect Secret Key.
Your partner's Secret Key is provided in BASE64 encoding, at the bottom of the Sites Table in the Dashboard section in Gigya website (please make sure that you are logged in to Gigya's website and that you have completed the Gigya's Site Setup process). Please make sure that you are using the partner's Secret Key and not your user's Secret Key.
Related
I am trying to create an HMAC signature in Postman using a pre-request script. Without going too far into the details of implementation,
I have confirmed that my means for generating the signature is messed up. I can see what the expected result should be with a proof of concept example but I’m missing something somewhere and cannot tell if it is in the conversion. I’ve read around from other questions on SO that binary is the default provided by cryptojs internally and that simply calling for the hash is the equivalent of asking for the digest with conversions completed for you. Here is the code I’m trying to run in postman and the working implementation code as shown in nodeJS.
var CryptoJS = require("crypto-js");
const d = new Date();
const timestamp = d.getTime();
const postData = {};
postData.nonce = 100; //timestamp * 1000; //nanosecond
postman.setEnvironmentVariable('nonce', postData.nonce);
const secret = CryptoJS.enc.Base64.parse(pm.environment.get("apiSecret"));
const path = pm.globals.get("balanceMethod");
const message = CryptoJS.SHA256( encodeURI(postData.nonce + postData)) ; // ...
const hmacDigest = CryptoJS.HmacSHA512(path + message, secret);
postman.setEnvironmentVariable('API-Signature', CryptoJS.enc.Base64.stringify(hmacDigest));
console.log(CryptoJS.enc.Base64.stringify(hmacDigest));
Does this apply to my situation in that I’d need to convert my sha256 message into a bytes array in order to work?
Reference code for building implementation that does work with nodeJS:
const getMessageSignature = (path, request, secret, nonce) => {
const message = qs.stringify(request);
const secret_buffer = new Buffer(secret, 'base64');
const hash = new crypto.createHash('sha256');
const hmac = new crypto.createHmac('sha512', secret_buffer);
const hash_digest = hash.update(nonce + message).digest('binary');
const hmac_digest = hmac.update(path + hash_digest, 'binary').digest('base64');
return hmac_digest;
};
Same reference code for building implementation in python3:
req['nonce'] = 100 #int(1000*time.time())
postdata = urllib.parse.urlencode(req)
# Unicode-objects must be encoded before hashing
encoded = (str(req['nonce']) + postdata).encode()
message = urlpath.encode() + hashlib.sha256(encoded).digest()
signature = hmac.new(base64.b64decode(self.secret),
message, hashlib.sha512)
sigdigest = base64.b64encode(signature.digest())
The only post data I'm sending is the Nonce at this time and I've purposely set it to 100 to be able to replicate the result to fix the generated signature. Seems close but not matching result. The python and nodeJS do match expected results and work properly.
Check out the answer in this thread. It helped me with the my problem and may be what is happening in your case also. All it is necessary is break the input of the HMAC into two parts.
I've been searching for ways to restrict access to an API made for using a AWS Lambda function written on javascript.
I've found documentation on how to use AWS Signature S4, but I still do not understand it.
According to creating a signature, after applying the pseudocode I should get the signature to be placed on the header.
I've found the following code that addresses this point:
// Example of signature generator
var crypto = require("crypto-js");
function getSignatureKey(Crypto, key, dateStamp, regionName, serviceName) {
var kDate = Crypto.HmacSHA256(dateStamp, "AWS4" + key);
var kRegion = Crypto.HmacSHA256(regionName, kDate);
var kService = Crypto.HmacSHA256(serviceName, kRegion);
var kSigning = Crypto.HmacSHA256("aws4_request", kService);
return kSigning;
}
console.log(getSignatureKey(crypto,'secretkey','date','us-east-2','iam'));
Here comes my first question, I do not know what should be the output of getSignatureKey()? This is because on the documentation it is a very long string, while the output I got was {words:[x,x,x,x,x,x,x,x],sigBytes: 32},where the x are random numbers.
Moreover, after getting the signature and filling the header for the request with the "authorization" field and others, how do I filter unproper requests? Do I have to create a policy for the AWS API so it only allows signed requests? Here I guess I should follow Signing Requests.
Thanks!
Here is the simple implementation of Signed URL's. aws-cloudfront-sign package offers simpler implementation.
var cfsign = require('aws-cloudfront-sign');
var signingParams = {
keypairId: process.env.PUBLIC_KEY,
privateKeyString: process.env.PRIVATE_KEY,
// Optional - this can be used as an alternative to privateKeyString
privateKeyPath: '/path/to/private/key',
expireTime: 1426625464599
}
// Generating a signed URL
var signedUrl = cfsign.getSignedUrl(
'http://example.cloudfront.net/path/to/s3/object',
signingParams
);
https://aws.amazon.com/blogs/developer/creating-amazon-cloudfront-signed-urls-in-node-js/
Purpose of SignedURL is to serve Private Contents.
More details at,
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html
Hope it helps.
The context
There is a button on the homepage of each document set in a document library on a SharePoint Online environment. When the button is clicked, an Outlook window opens with the title and body set and all the files in the document set should be added as the attachments.
The code
Here's the code I have so far:
var olApp = new ActiveXObject("Outlook.Application");
var olNs = olApp.GetNameSpace("MAPI");
var olItem = olApp.CreateItem(0);
var signature = olItem.HTMLBody;
signature.Importance = 2;
olItem.To = "";
olItem.Cc = "";
olItem.Bcc = "";
olItem.Subject = "Pre filled title";
olItem.HTMLBody =
"<span style='font-size:11pt;'>" +
"<p>Pre filled body</p>" +
"</span>";
olItem.HTMLBody += signature;
olItem.Display();
olItem.GetInspector.WindowState = 2;
var docUrl = "https://path_to_site/Dossiers/13245_kort titel/New Microsoft Word Document.docx";
olItem.Attachments.Add(docUrl);
The Problem
When I run this code, an Outlook window opens with everything set correctly. But on the line where the attachment is added I get following very vague error message:
SCRIPT8: The operation failed.
I thought it could be the spaces in the url so I replaced them:
docUrl = docUrl.replace(/ /g, "%20");
Also didn't work (same error) and providing all parameters like this also didn't work:
olItem.Attachments.Add(docUrl, 1, 1, "NewDocument");
Passing a path to a local file (e.g. C:/folder/file.txt) or a publicly available url to an image does work. So my guess is it has something to do with permissions or security. Does anybody know how to solve this?
PS: I know using an ActiveX control is not the ideal way of working (browser limitations, security considerations, ...) but the situation is what it is and not in my power to change.
You cannot pass a url to MailItem.Attachments.Add in OOM (it does work in Redemption - I am its author - for RDOMail.Attachments.Add). Outlook Object Model only allows a fully qualified path to a local file or a pointer to another item (such as MailItem).
Hi I am buliding my first web app using javascript and fetching data using API from www.openweathermap.org/
I have used the API key as mentioned in the documentation still it is giving an error of unauthorization. Can there be any other reason for this error while calling a function or so . Thank you in advance.
var APPID = "my_secret_key";
var temp;
var loc;
var icon;
var wind;
var humidity;
var direction;
function updateByZip(zip){
var url = "http://api.openweathermap.org/data/2.5/weather?" +
"zip = " + zip +
"&APPID =" + APPID ;
sendRequest(url);
}
function sendRequest(url){
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
var data = JSON.parse(xmlhttp.responseText) ;
var weather = {};
weather.wind = data.wind.speed;
weather.direction = data.wind.deg;
weather.loc = data.name;
weather.temp = data.main.temp;
weather.icon = data.weather[0].id;
weather.humidity=data.main.humidity;
update(weather);
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
It's the spaces near the equal signs in your URL. It's likely urlencoding the space and sending your parameter as APPID%20 which is not being recognized as valid.
var url = "http://api.openweathermap.org/data/2.5/weather?" +
"zip=" + zip +
"&APPID=" + APPID;
for future users, as i was having 401 error but solved it differently.
Error:
Invalid API key. Please see http://openweathermap.org/faq#error401 for more info
API calls responds with 401 error:
You can get the error 401 in the following cases:
You did not specify your API key in API request.
Your API key is not activated yet. Within the next couple of hours, it will be activated and ready to use.
You are using wrong API key in API request. Please, check your right API key in personal account.
You have free subscription and try to get access to our paid services (for example, 16 days/daily forecast API, any historical weather data, Weather maps 2.0, etc). Please, check your tariff in your [personal account]([price and condition]).
here are some steps to find problem.
1) Check if API key is activated
some API services provide key information in dashboard whether its activated, expired etc. openWeatherMap don't.
to verify whether your key is working 'MAKE API CALL FROM BROWSER'
api.openweathermap.org/data/2.5/weather?q=peshawar&appid=API_key
replace API_key with your own key, if you get data successfully then your key is activated otherwise wait for few hours to get key activated.
2) Check .env for typos & syntax
.env is file which is used to hide credentials such as API_KEY in server side code.
make sure your .env file variables are using correct syntax which is
NAME=VALUE
API_KEY=djgkv43439d90bkckcs
no semicolon, quotes etc
3) Check request URL
check request url where API call will be made , make sure
It doesn't have spaces, braces etc
correct according to URL encoding
correct according to API documentation
4) Debug using dotenv:
to know if you dotenv package is parsing API key correctly use the following code
const result = dotenv.config()
if (result.error) {
throw result.error
}
console.log(result.parsed)
this code checks if .env file variables are being parsed, it will print API_KEY value if its been parsed otherwise will print error which occur while parsing.
Hopefully it helps :)
Others suggestion
5) Check location of .env file
look for location of .env file in your directory, moving it to root directory might help (suggested in comments)
For those who followed the previous answers and are still facing the 401 issue: it seems it is now required to access the the API via HTTPS --- at least that's the case for me. Some older guides and tutorials might continue to use http:// in their code, so you'll have to change it to https://.
As far as I know, there is no mention of this in OpenWeather's official docs, and they don't include the protocol in their examples too.
Is there a way to create a hash value in Google Apps Script? Google Apps Script will run server side code in the .gs code file. The .gs file is written in JavaScript. Because JavaScript is mostly a client side language, and encrypting anything client side isn't secure, maybe something like HMAC for Javascript isn't available? When I do a web search on hmac in javascript the first thing I get is crypto-js. But it looks like I need to link to some services in <script> tags:
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-md5.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha1.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha256.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha512.js"></script>
<script>
var hash = CryptoJS.HmacMD5("Message", "Secret Passphrase");
var hash = CryptoJS.HmacSHA1("Message", "Secret Passphrase");
var hash = CryptoJS.HmacSHA256("Message", "Secret Passphrase");
var hash = CryptoJS.HmacSHA512("Message", "Secret Passphrase");
</script>
The Secret Passphrase would be in your client side HTML. That doesn't make any sense! Oh! I just found some pseudocode in wikipedia.
Wikipedia HMAC pseudo Code
Here is my attempt at refactoring it:
//blocksize is the size in bytes and is set to 64 bytes.
//byte size of any UTF-8 string
function byteCount(s) {
return encodeURI(s).split(/%..|./).length - 1;
};
function hmac(key, message) {
var blocksize = 64;
var keyLngth = byteCount(key);
if (keyLngth > blocksize) {
key = hash(key); // keys longer than blocksize are shortened
}
else if (keyLngth < blocksize) {
key = key + [0x00 * (blocksize - keyLngth)]; // keys shorter than blocksize are zero-padded
};
var o_key_pad = [0x5c * blocksize] ⊕ key; // Where blocksize is that of the underlying hash function
var i_key_pad = [0x36 * blocksize] ⊕ key; // Where ⊕ is exclusive or (XOR)
return hash(o_key_pad + hash(i_key_pad + message));
};
I guess wherever the pseudo Code states: hash(key) one of the following hash functions: SHA-1, MD5, RIPEMD-128/160 needs to be used.
So I did a search on SHA-1 in JavaScript and found this:
http://www.movable-type.co.uk
Any info on how to create a HMAC value using Javascript would be greatly appreciated. I'll probably keep working on it, in the meantime. Even though it's Javascript, it's a Google .gs Apps Script code file, which runs on the server.
Apps Script has a built in Class Utility for creating HMAC Sha256 signature or token:
Official Apps Script Documentation HMAC Sha256 signature