AMQJS0011E Invalid state not connected. AWS IoT core - javascript

I'm trying to have some sort of real-time dashboard that can subscribe to AWS IoT core topics and maybe publish too.
I have found a couple of items online, but I can't figure it out.
This is what I currently have:
function p4(){}
p4.sign = function(key, msg) {
const hash = CryptoJS.HmacSHA256(msg, key);
return hash.toString(CryptoJS.enc.Hex);
};
p4.sha256 = function(msg) {
const hash = CryptoJS.SHA256(msg);
return hash.toString(CryptoJS.enc.Hex);
};
p4.getSignatureKey = function(key, dateStamp, regionName, serviceName) {
const kDate = CryptoJS.HmacSHA256(dateStamp, 'AWS4' + key);
const kRegion = CryptoJS.HmacSHA256(regionName, kDate);
const kService = CryptoJS.HmacSHA256(serviceName, kRegion);
const kSigning = CryptoJS.HmacSHA256('aws4_request', kService);
return kSigning;
};
function getEndpoint() {
const REGION = "eu-west-1";
const IOT_ENDPOINT = "blablablabla-ats.iot.eu-west-1.amazonaws.com";
// your AWS access key ID
const KEY_ID = "My-key";
// your AWS secret access key
const SECRET_KEY = "my-access-token";
// date & time
const dt = (new Date()).toISOString().replace(/[^0-9]/g, "");
const ymd = dt.slice(0,8);
const fdt = `${ymd}T${dt.slice(8,14)}Z`
const scope = `${ymd}/${REGION}/iotdevicegateway/aws4_request`;
const ks = encodeURIComponent(`${KEY_ID}/${scope}`);
let qs = `X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=${ks}&X-Amz-Date=${fdt}&X-Amz-SignedHeaders=ho
const req = `GET\n/mqtt\n${qs}\nhost:${IOT_ENDPOINT}\n\nhost\n${p4.sha256('')}`;
qs += '&X-Amz-Signature=' + p4.sign(
p4.getSignatureKey( SECRET_KEY, ymd, REGION, 'iotdevicegateway'),
`AWS4-HMAC-SHA256\n${fdt}\n${scope}\n${p4.sha256(req)}`
);
return `wss://${IOT_ENDPOINT}/mqtt?${qs}`;
}
// gets MQTT client
function initClient() {
const clientId = Math.random().toString(36).substring(7);
const _client = new Paho.MQTT.Client(getEndpoint(), clientId);
// publish method added to simplify messaging
_client.publish = function(topic, payload) {
let payloadText = JSON.stringify(payload);
let message = new Paho.MQTT.Message(payloadText);
message.destinationName = topic;
message.qos = 0;
_client.send(message);
}
return _client;
}
function getClient(success) {
if (!success) success = ()=> console.log("connected");
const _client = initClient();
const connectOptions = {
useSSL: true,
timeout: 3,
mqttVersion: 4,
onSuccess: success
};
_client.connect(connectOptions);
return _client;
}
let client = {};
function init() {
client = getClient();
client.onMessageArrived = processMessage;
client.onConnectionLost = function(e) {
console.log(e);
}
}
function processMessage(message) {
let info = JSON.parse(message.payloadString);
const publishData = {
retailer: retailData,
order: info.order
};
client.publish("sc/delivery", publishData);
}
$(document).ready(() => {
init();
client.subscribe("sc/orders/");
});
I keep getting the same error; AMQJS0011E Invalid state not connected., but I do see in the requests pane of chrome that there is an connection or so... What am I doing wrong here?
I don't see any of the logs anyhow...

Related

Uncaught TypeError: store.put is not a function at store.onsuccess

I can't update any data in IndexedDb. When I run the code it says "store.put is not a function at store.onsuccess".
I tried from many browsers, same error in all
I also tried .update instead of .put function but it didn't work and
gave the same error
const request = window.indexedDB.open("AdminDatabase");
request.onsuccess = (event) => {
const db = event.target.result;
const txn = db.transaction('floors', 'readwrite');
const store = txn.objectStore('floors').get(parseInt(getRoomButtonNumber));
store.onsuccess = function (event) {
var floorDataFromDb = event.target.result;
console.log("RenameFloor: getDbResult: FloorName: " + floorIdFromDb.Name);
floorDataFromDb.Name = person;
console.log("RenameFloor: Json New Name: " + floorDataFromDb.Name);
//In this line caught error
store.put(floorDataFromDb);
store.onsuccess = function (event) {
console.log("floorData Updated: " + event.target.result);
}
};
store.onerror = function (event) {
console.log("GET Error DB: " + event);
};
};
IndexedDb Browser View
You issue is on this line:
const store = txn.objectStore('floors').get(parseInt(getRoomButtonNumber));
You define store as an IDBRequest.
Obviously, this does not have a put method. You would instead change it to this:
const store = txn.objectStore('floors');
const res = store.get(parseInt(getRoomButtonNumber));
res.onsuccess = evt => {
...
store.put(data, key);
...
}
res.onerror = evt => {
...
}

Why is node Sequelize givng me a circular reference error?

I created a model of my database using the "sequelize-auto" package. It has worked great up until today. For some reason this morning it started giving me this error: ERROR: MCAIntranet.initModels is not a function which is accompanied by the warning (node:35036) Warning: Accessing non-existent property 'initModels' of module exports inside circular dependency
This same function call (dataqueries.getSitemap) worked fine yesterday with no changes being made to this code. The import (MCAIntranet) for the model returns an empty JSON array for some reason.
Here is all the relevant code involved.
The controller, the sequelize query file, the initModel file and the table model in order:
const express = require('express');
const router = express.Router();
const Users = require('../components/Users');
const dataQuery = require('../components/dataQueries');
router.get('/', async (req, res, next) => {
try {
let user = await Users.getUserName(req);
//get groups and sitemap data
let groups = await Users.getUserRoles(user);
// let sitemap = await dataQuery.loadFile('./data/sitemap.json', 'ascii');
let sitemap=await dataQuery.getSitemap(); //ERROR OCCURS AT THIS LINE
let ret = { 'userRoles': groups, 'siteMap': sitemap };
res.send(JSON.stringify(ret));
} catch (ex) {
console.log("ERROR: ", ex.message);
}
})
module.exports = router;
let sql = require('mssql');
let fs = require('fs');
// let { Connection } = require('../ConfigData/database');
const MCAIntranet = require('../configData/models/mcaintranet/init-models')
const DB = require('../ConfigData/Connector');
const runQuery = async (query, database) => {
try {
let pool = await Connection(database);
let results = await pool.request().query(query);
// console.log("Query results: ", results.recordsets[0])
return results.recordset;
} catch (ex) {
// console.log("dataQueries.js 17", ex);
return "False! ", ex;
} finally {
sql.close();
}
}
const bulkInsert = async (database, table) => {
let pool = await Connection(database);
let insert = await pool.request()
await insert.bulk(table, (err, result) => {
if (err) {
console.log("ERROR: " + err)
} else {
console.log("SUCCESS", result);
}
});
}
const loadFile = async (filePath, type) => {
let file = fs.readFileSync(filePath, type);
return file;
}
const writeFile = async (filePath, data) => {
return fs.writeFile(
filePath,
data,
(res) => { console.log(res) },
() => {/* Empty callback function*/ })
}
const getSitemap = async () => {
const sequelize = DB.GetDB(DB.MCAIntranet);
const propsDB = MCAIntranet.initModels(sequelize); //ERROR OCCURS AT THIS LINE
//get all values contained for user
let props = await propsDB.tblSitemap.findAll({
attributes: ['JSON']
},
{ raw: true, output: true })
let sitemap = props[0].dataValues.JSON;
return JSON.parse(sitemap);
}
const writeSitemap = async (sitemap) => {
const sequelize = DB.GetDB(DB.MCAIntranet);
const propsDB = MCAIntranet.initModels(sequelize);
propsDB.tblSitemap.update(
{
JSON: JSON.stringify(sitemap)
},
{ where: { id: 1 } }
)
}
module.exports = {
loadFile: loadFile,
writeFile: writeFile,
runQuery: runQuery,
bulkInsert: bulkInsert,
getSitemap: getSitemap,
writeSitemap: writeSitemap,
}
var DataTypes = require("sequelize").DataTypes;
var _tblAttendance = require("./tblAttendance");
var _tblCollectorCodes = require("./tblCollectorCodes");
var _tblCollectors = require("./tblCollectors");
var _tblContactsData = require("./tblContactsData");
var _tblEmployees = require("./tblEmployees");
var _tblExpectingData = require("./tblExpectingData");
var _tblIntranetMessage = require("./tblIntranetMessage");
var _tblLANSAAccess = require("./tblLANSAAccess");
var _tblLANSAHeadings = require("./tblLANSAHeadings");
var _tblLANSAReportHeadings = require("./tblLANSAReportHeadings");
var _tblLANSAReports = require("./tblLANSAReports");
var _tblMessageDisplay = require("./tblMessageDisplay");
var _tblPDFFiles = require("./tblPDFFiles");
var _tblPagesVisited = require("./tblPagesVisited");
var _tblPreAuth = require("./tblPreAuth");
var _tblPreAuthDebtorInfo = require("./tblPreAuthDebtorInfo");
var _tblPreAuthFlatFiles = require("./tblPreAuthFlatFiles");
var _tblRetailReports = require("./tblRetailReports");
var _tblRogersFiles = require("./tblRogersFiles");
var _tblRogersTemp1 = require("./tblRogersTemp1");
var _tblRogersWirelessPayfiles = require("./tblRogersWirelessPayfiles");
var _tblRoles = require("./tblRoles");
var _tblSMS = require("./tblSMS");
var _tblSMSSent = require("./tblSMSSent");
var _tblSMSSents = require("./tblSMSSents");
var _tblShawAccts = require("./tblShawAccts");
var _tblSickDays = require("./tblSickDays");
var _tblSiteLayout = require("./tblSiteLayout");
var _tblSiteLayoutDesks = require("./tblSiteLayoutDesks");
var _tblSiteLayoutSites = require("./tblSiteLayoutSites");
var _tblSitemap = require("./tblSitemap");
var _tblStatusAccts = require("./tblStatusAccts");
var _tblStatusUpdates = require("./tblStatusUpdates");
var _tblUDWin = require("./tblUDWin");
var _tblUserProperties = require("./tblUserProperties");
var _vwUserRoles = require("./vwUserRoles");
var _tblUserRoles = require("./tblUserRoles");
var _tblUsers = require("./tblUsers");
var _tblVacationMain = require("./tblVacationMain");
var _tblVacationRequests = require("./tblVacationRequests");
var _tblVacations = require("./tblVacations");
var _vwLoggedIn = require("./vwLoggedIn");
function initModels(sequelize) {
var tblAttendance = _tblAttendance(sequelize, DataTypes);
var tblCollectorCodes = _tblCollectorCodes(sequelize, DataTypes);
var tblCollectors = _tblCollectors(sequelize, DataTypes);
var tblContactsData = _tblContactsData(sequelize, DataTypes);
var tblEmployees = _tblEmployees(sequelize, DataTypes);
var tblExpectingData = _tblExpectingData(sequelize, DataTypes);
var tblIntranetMessage = _tblIntranetMessage(sequelize, DataTypes);
var tblLANSAAccess = _tblLANSAAccess(sequelize, DataTypes);
var tblLANSAHeadings = _tblLANSAHeadings(sequelize, DataTypes);
var tblLANSAReportHeadings = _tblLANSAReportHeadings(sequelize, DataTypes);
var tblLANSAReports = _tblLANSAReports(sequelize, DataTypes);
var tblMessageDisplay = _tblMessageDisplay(sequelize, DataTypes);
var tblPDFFiles = _tblPDFFiles(sequelize, DataTypes);
var tblPagesVisited = _tblPagesVisited(sequelize, DataTypes);
var tblPreAuth = _tblPreAuth(sequelize, DataTypes);
var tblPreAuthDebtorInfo = _tblPreAuthDebtorInfo(sequelize, DataTypes);
var tblPreAuthFlatFiles = _tblPreAuthFlatFiles(sequelize, DataTypes);
var tblRetailReports = _tblRetailReports(sequelize, DataTypes);
var tblRogersFiles = _tblRogersFiles(sequelize, DataTypes);
var tblRogersTemp1 = _tblRogersTemp1(sequelize, DataTypes);
var tblRogersWirelessPayfiles = _tblRogersWirelessPayfiles(sequelize, DataTypes);
var tblRoles = _tblRoles(sequelize, DataTypes);
var tblSMS = _tblSMS(sequelize, DataTypes);
var tblSMSSent = _tblSMSSent(sequelize, DataTypes);
var tblSMSSents = _tblSMSSents(sequelize, DataTypes);
var tblShawAccts = _tblShawAccts(sequelize, DataTypes);
var tblSickDays = _tblSickDays(sequelize, DataTypes);
var tblSiteLayout = _tblSiteLayout(sequelize, DataTypes);
var tblSiteLayoutDesks = _tblSiteLayoutDesks(sequelize, DataTypes);
var tblSiteLayoutSites = _tblSiteLayoutSites(sequelize, DataTypes);
var tblSitemap = _tblSitemap(sequelize, DataTypes); //ERROR OCCURS CALLING THIS TABLE
var tblStatusAccts = _tblStatusAccts(sequelize, DataTypes);
var tblStatusUpdates = _tblStatusUpdates(sequelize, DataTypes);
var tblUDWin = _tblUDWin(sequelize, DataTypes);
var tblUserProperties = _tblUserProperties(sequelize, DataTypes);
var vwUserRoles = _vwUserRoles(sequelize, DataTypes);
var tblUserRoles = _tblUserRoles(sequelize, DataTypes);
var tblUsers = _tblUsers(sequelize, DataTypes);
var tblVacationMain = _tblVacationMain(sequelize, DataTypes);
var tblVacationRequests = _tblVacationRequests(sequelize, DataTypes);
var tblVacations = _tblVacations(sequelize, DataTypes);
var vwLoggedIn = _vwLoggedIn(sequelize, DataTypes);
return {
tblAttendance,
tblCollectorCodes,
tblCollectors,
tblContactsData,
tblEmployees,
tblExpectingData,
tblIntranetMessage,
tblLANSAAccess,
tblLANSAHeadings,
tblLANSAReportHeadings,
tblLANSAReports,
tblMessageDisplay,
tblPDFFiles,
tblPagesVisited,
tblPreAuth,
tblPreAuthDebtorInfo,
tblPreAuthFlatFiles,
tblRetailReports,
tblRogersFiles,
tblRogersTemp1,
tblRogersWirelessPayfiles,
tblRoles,
tblSMS,
tblSMSSent,
tblSMSSents,
tblShawAccts,
tblSickDays,
tblSiteLayout,
tblSiteLayoutDesks,
tblSiteLayoutSites,
tblSitemap,
tblStatusAccts,
tblStatusUpdates,
tblUDWin,
tblUserProperties,
vwUserRoles,
tblUserRoles,
tblUsers,
tblVacationMain,
tblVacationRequests,
tblVacations,
vwLoggedIn,
};
}
module.exports = initModels;
module.exports.initModels = initModels;
module.exports.default = initModels;
const sequelize = require('sequelize');
module.exports = function (sequelize, DataTypes) {
return sequelize.define('tblSitemap', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
JSON: {
type: DataTypes.TEXT,
allowNull: false
}
}, {
sequelize,
tableName: 'tblSitemap',
schema: 'dbo',
timestamps: false
});
};
As the sitemap is the first data called in the application, and contains reference data for all other components (lazy loading) I am unable to test other functions.
I am sure that I am missing something small but I can't spot it.
It turns out that the issue was case sensitivity. Node is case sensitive to path names even in a Windows environment. Therefore in the second file listed, const MCAIntranet = require('../configData/models/mcaintranet/init-models') should instead have been const MCAIntranet = require('../ConfigData/models/mcaintranet/init-models')
Note the capitalization of "C" in "../ConfigData/...."
Such a small, almost unnoticeable thing causing so much grief.
Hope this helps someone out :)

REST API azure speech to text (RECOGNIZED: Text=undefined)

I am trying to use the azure api (speech to text), but when I execute the code it does not give me the audio result.
The audio is in the format requested (.WAV).
code example documentation
const fs = require('fs');
const sdk = require("microsoft-cognitiveservices-speech-sdk");
const speechConfig = sdk.SpeechConfig.fromSubscription("---", "eastus2");
function fromFile() {
let pushStream = sdk.AudioInputStream.createPushStream();
fs.createReadStream("audio/aboutSpeechSdk.wav").on('data', function (arrayBuffer) {
pushStream.write(arrayBuffer.slice());
}).on('end', function () {
pushStream.close();
});
let audioConfig = sdk.AudioConfig.fromStreamInput(pushStream);
let recognizer = new sdk.SpeechRecognizer(speechConfig, audioConfig);
recognizer.recognizeOnceAsync(result => {
console.log(`RECOGNIZED: Text=${result.text}`);
recognizer.close();
});
}
fromFile();
According to the code you provide, it seems that you do not configure Speech Recognition Language. Please add the code speechConfig.speechRecognitionLanguage = "" into you sample. For more details about language, please refer to here
For example. You can download the video to do a test.
var sdk = require("microsoft-cognitiveservices-speech-sdk");
var fs = require("fs");
var subscriptionKey = "";
var serviceRegion = "";
var language = "en-US";
function openPushStream(filename) {
// create the push stream we need for the speech sdk.
var pushStream = sdk.AudioInputStream.createPushStream();
// open the file and push it to the push stream.
fs.createReadStream(filename)
.on("data", function (arrayBuffer) {
pushStream.write(arrayBuffer.slice());
})
.on("end", function () {
pushStream.close();
});
return pushStream;
}
var audioConfig = sdk.AudioConfig.fromStreamInput(
openPushStream("aboutSpeechSdk.wav")
);
var speechConfig = sdk.SpeechConfig.fromSubscription(
subscriptionKey,
serviceRegion
);
speechConfig.speechRecognitionLanguage = language;
var recognizer = new sdk.SpeechRecognizer(speechConfig, audioConfig);
recognizer.recognizeOnceAsync(
function (result) {
console.log(result.text);
recognizer.close();
recognizer = undefined;
},
function (err) {
console.log(err);
recognizer.close();
recognizer = undefined;
}
For more details, please refer to the blog

AWS IOT GetThingShadow API request sends response "Signature expired"

const https = require('https');
const crypto = require('crypto');
const utf8 = require('utf8');
const awsIoT = require('aws-iot-device-sdk');
const {AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY} = require('../../config');
const endpointFile = require('../../endpoint.json');
function sign(key, msg){
// since we are deriving key, refer getSignatureKey function
// we use binary format hash => digest() and not digest('hex')
return crypto.createHmac("sha256", key).update(utf8.encode(msg)).digest();
}
function getSignatureKey(key, date, region, service){
// deriving the key as follows:
// HMAC(HMAC(HMAC(HMAC("AWS4" + kSecret,"20150830"),"us-east-1"),"iam"),"aws4_request")
let kDate = sign(utf8.encode(`AWS4${key}`), date);
let kRegion = sign(kDate, region);
let kService = sign(kRegion, service);
let kSigning = sign(kService, 'aws4_request');
return kSigning;
}
function getTime(){
let timeObj = new Date().toISOString();
let arr = timeObj.split(':');
let len = arr[0].length;
let hh = arr[0].slice(len-2,len);
let mm = arr[1];
let ss = arr[2].slice(0,2);
return `${hh}${mm}${ss}`;
}
function getDate(){
let timeObj = new Date().toISOString();
let arr = timeObj.split('-');
let year = arr[0];
let month = arr[1];
let day = arr[2].slice(0,2);
return `${year}${month}${day}`;
}
const ENDPOINT = endpointFile.endpointAddress;
const THING_NAME = __dirname.split('/').pop();
const URI = `https://${ENDPOINT}/things/${THING_NAME}/shadow`;
console.log(URI);
// access key = access key ID + secret access key
// SigV4
// Signing Key derived from credential scope
// Step1
// Create a canonical request (CR)
// CanonicalRequest =
// HTTPRequestMethod + '\n' +
// CanonicalURI + '\n' +
// CanonicalQueryString + '\n' +
// CanonicalHeaders + '\n' +
// SignedHeaders + '\n' +
// HexEncode(Hash(RequestPayload))
const CONTENT_TYPE = "application/json; charset=utf-8";
const HTTP_REQUEST_METHOD = "GET";
// remove the protocol part from URI and query parameters (none in this case)
const CANONICAL_URI = URI.slice(URI.indexOf('/')+2, URI.length);
// console.log(`CANONICAL_URI: ${CANONICAL_URI}`);
const CANONICAL_QUERY_STRING = "";
const HOST = `${ENDPOINT}`;
const DATE = getDate();
const TIME = getTime();
const X_AMZ_DATE = `${DATE}T${TIME}Z`;
console.log(`X_AMZ_DATE: ${X_AMZ_DATE}`);
// note the trailing \n is present
const CANONICAL_HEADER = `content-type:${CONTENT_TYPE}\n`+
`host:${HOST}\n`+
`x-amz-date:${X_AMZ_DATE}\n`;
const SIGNED_HEADER = "content-type;host;x-amz-date";
// payload is the contents of request body
const PAYLOAD = "";
const PAYLOAD_HEX_HASH_ENCODED = crypto.createHash("sha256").update(utf8.encode(PAYLOAD)).digest("hex");
// string for signing CR_STRING = canonical request + metadata
const CANONICAL_REQUEST = `${HTTP_REQUEST_METHOD}\n`+
`${CANONICAL_URI}\n`+
`${CANONICAL_QUERY_STRING}\n`+
`${CANONICAL_HEADER}\n`+
`${SIGNED_HEADER}\n`+
`${PAYLOAD_HEX_HASH_ENCODED}`;
// Step2
// signing key STR_TO_SIGN
const HASH_ALGO = "AWS4-HMAC-SHA256";
const REGION = "us-east-2";
const SERVICE = "iot";
const CREDENTIAL_SCOPE = `${DATE}/`+
`${REGION}/`+
`${SERVICE}/`+
`aws4_request`;
const STRING_TO_SIGN = `${HASH_ALGO}\n`+
`${X_AMZ_DATE}\n`+
`${CREDENTIAL_SCOPE}\n`+
crypto.createHash("sha256")
.update(CANONICAL_REQUEST)
.digest("hex");
// Step3
const SECRET_KEY = AWS_SECRET_ACCESS_KEY;
const SIGNING_KEY = getSignatureKey(SECRET_KEY, DATE, REGION, SERVICE);
const SIGNATURE = crypto.createHmac("sha256", SIGNING_KEY).update(utf8.encode(STRING_TO_SIGN)).digest("hex");
// Step4
// Add SIGNATURE to HTTP request in a header or as a query string parameter
const ACCESS_KEY_ID = AWS_ACCESS_KEY_ID;
const AUTHORIZATION_HEADER = `${HASH_ALGO}`+
` Credential=`+
`${ACCESS_KEY_ID}`+
`/`+
`${CREDENTIAL_SCOPE}`+
`, SignedHeaders=`+
`${SIGNED_HEADER}`+
`, Signature=`+
`${SIGNATURE}`;
const HEADERS = {
'host':HOST,
'content-type':CONTENT_TYPE,
'Authorization':AUTHORIZATION_HEADER,
'x-amz-date':X_AMZ_DATE
};
const OPTIONS = {
hostname: HOST,
path: `/things/${THING_NAME}/shadow`,
headers: HEADERS
};
// send request
https.get(OPTIONS, res=>{
res.setEncoding("utf-8");
let body = "";
res.on("data", data=>{
body += data;
});
res.on("end", ()=>{
body = JSON.parse(body);
console.log(body);
});
});
On running this code the typical response I'm getting is
{ message: 'Signature expired: 20201017T000000Z is now earlier than 20201017T073249Z (20201017T073749Z - 5 min.)', traceId: 'b8f04573-2afd-d26a-5f2a-a13dd2dade3' }
I don't know what is going wrong or what to do to remove this error.
The ISO format is used here with this structure YYYYMMDDTHHMMSSZ
Signature expired: YYYYMMDDT000000Z is now earlier than YYYYMMDDT073249Z (YYYYMMDDT073749Z - 5 min.)
Why is HHMMSS always zero in the reported message?
What I'm trying to do is get "thing" shadow document by sending a request to the API referring to this (AWS_IOT_GetThingShadow API)
However, for authenticating my request I have to do a lot of other stuff which is stated here Signing AWS requests. I have simply performed the 4 tasks / steps mentioned in order to sign the request.
They have provided an example script (sigv4-signed-request-examples) in python which I followed to write my code.
I have been stuck on this for quite a while now. If anyone has any idea about this please help.
EDIT: The above problem was solved by using X_AMZ_DATE in STRING_TO_SIGN and HEADERS. I was wrongly using DATE. I have updated the above code accordingly.
New error I am gettiing is
{ message: 'Credential should be scoped to correct service. ', traceId: 'e711927a-11f4-ae75-c4fe-8cdc5a120c0d' }
I am not sure what is wrong with the credentials. I have set the REGION correctly. I am using SERVICE as iot which should be correct as well for requesting shadow API.
EDIT: It turns out iot is wrong. Changed SERVICE = "iotdata" and now I can successfully request shadow data. Solution found here. It is strange that I couldn't find it anywhere in the AWS docs. Another thing wrong was CANONICAL_URI = path in URI after domain and before query strings
So in my case it will be CANONICAL_URI = /things/${THING_NAME}/shadow
I am posting the correct final version of my code in case anyone is facing similar issue.
Three things were wrong in my original code.
X_AMZ_DATE (YYYYMMDDTHHMMSSZ) didn't use it in HEADERS and STRING_TO_SIGN. Hence, was getting Signature expired error.
SERVICE I thought would be iot but it is iotdata. Credential should be scoped to correct service error was resolved.
CANONICAL_URI should only contain part after the domain and before query parameters. Eg. If request URI is https://foo.bar.baz.com/foo1/foo2/foo3?bar1=baz1&bar2=baz2 then CANONICAL_URI = "/foo1/foo2/foo3"
const https = require('https');
const crypto = require('crypto');
const utf8 = require('utf8');
const {AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY} = require('../../config');
const endpointFile = require('../../endpoint.json');
function sign(key, msg){
// since we are deriving key, refer getSignatureKey function
// we use binary format hash => digest() and not digest('hex')
return crypto.createHmac("sha256", key).update(utf8.encode(msg)).digest();
}
function getSignatureKey(key, date, region, service){
// deriving the key as follows:
// HMAC(HMAC(HMAC(HMAC("AWS4" + kSecret,"20150830"),"us-east-1"),"iam"),"aws4_request")
let kDate = sign(utf8.encode(`AWS4${key}`), date);
let kRegion = sign(kDate, region);
let kService = sign(kRegion, service);
let kSigning = sign(kService, 'aws4_request');
return kSigning;
}
function getTime(){
let timeObj = new Date().toISOString();
let arr = timeObj.split(':');
let len = arr[0].length;
let hh = arr[0].slice(len-2,len);
let mm = arr[1];
let ss = arr[2].slice(0,2);
return `${hh}${mm}${ss}`;
}
function getDate(){
let timeObj = new Date().toISOString();
let arr = timeObj.split('-');
let year = arr[0];
let month = arr[1];
let day = arr[2].slice(0,2);
return `${year}${month}${day}`;
}
const ENDPOINT = endpointFile.endpointAddress;
const THING_NAME = __dirname.split('/').pop();
const URI = `https://${ENDPOINT}/things/${THING_NAME}/shadow`;
console.log(URI);
// access key = access key ID + secret access key
// SigV4
// Signing Key derived from credential scope
// Step1
// Create a canonical request (CR)
// CanonicalRequest =
// HTTPRequestMethod + '\n' +
// CanonicalURI + '\n' +
// CanonicalQueryString + '\n' +
// CanonicalHeaders + '\n' +
// SignedHeaders + '\n' +
// HexEncode(Hash(RequestPayload))
const CONTENT_TYPE = "application/json; charset=utf-8";
const HTTP_REQUEST_METHOD = "GET";
const CANONICAL_URI = `/things/${THING_NAME}/shadow`;
const CANONICAL_QUERY_STRING = "";
const HOST = `${ENDPOINT}`;
const DATE = getDate();
const TIME = getTime();
const X_AMZ_DATE = `${DATE}T${TIME}Z`;
// note the trailing \n is present
const CANONICAL_HEADER = `content-type:${CONTENT_TYPE}\n`+
`host:${HOST}\n`+
`x-amz-date:${X_AMZ_DATE}\n`;
const SIGNED_HEADER = "content-type;host;x-amz-date";
// payload is the contents of request body
const PAYLOAD = "";
const PAYLOAD_HEX_HASH_ENCODED = crypto.createHash("sha256").update(utf8.encode(PAYLOAD)).digest("hex");
// console.log(`Payload: ${PAYLOAD_HEX_HASH_ENCODED}`);
// string for signing CR_STRING = canonical request + metadata
const CANONICAL_REQUEST = `${HTTP_REQUEST_METHOD}\n`+
`${CANONICAL_URI}\n`+
`${CANONICAL_QUERY_STRING}\n`+
`${CANONICAL_HEADER}\n`+
`${SIGNED_HEADER}\n`+
`${PAYLOAD_HEX_HASH_ENCODED}`;
// Step2
// signing key STR_TO_SIGN
const HASH_ALGO = "AWS4-HMAC-SHA256";
const REGION = "us-east-2";
const SERVICE = "iotdata";
const CREDENTIAL_SCOPE = `${DATE}/`+
`${REGION}/`+
`${SERVICE}/`+
`aws4_request`;
const STRING_TO_SIGN = `${HASH_ALGO}\n`+
`${X_AMZ_DATE}\n`+
`${CREDENTIAL_SCOPE}\n`+
crypto.createHash("sha256")
.update(CANONICAL_REQUEST)
.digest("hex");
// Step3
const SECRET_KEY = AWS_SECRET_ACCESS_KEY;
const SIGNING_KEY = getSignatureKey(SECRET_KEY, DATE, REGION, SERVICE);
const SIGNATURE = crypto.createHmac("sha256", SIGNING_KEY).update(utf8.encode(STRING_TO_SIGN)).digest("hex");
// Step4
// Add SIGNATURE to HTTP request in a header or as a query string parameter
const ACCESS_KEY_ID = AWS_ACCESS_KEY_ID;
const AUTHORIZATION_HEADER = `${HASH_ALGO}`+
` Credential=`+
`${ACCESS_KEY_ID}`+
`/`+
`${CREDENTIAL_SCOPE}`+
`, SignedHeaders=`+
`${SIGNED_HEADER}`+
`, Signature=`+
`${SIGNATURE}`;
const HEADERS = {
'host':HOST,
'content-type':CONTENT_TYPE,
'Authorization':AUTHORIZATION_HEADER,
'x-amz-date':X_AMZ_DATE
};
const OPTIONS = {
hostname: HOST,
path: `/things/${THING_NAME}/shadow`,
headers: HEADERS
};
https.get(OPTIONS, res=>{
res.setEncoding("utf-8");
let body = "";
res.on("data", data=>{
body += data;
});
res.on("end", ()=>{
body = JSON.parse(body);
console.log(body);
});
});

aws lambda function how to use responses to perform calculation

Trying to create a lambda function that lists tagged ec2 and tagged rds and performs an action thereafter. This is the first time i have used javascript and would appreciate some help.
Please see my example below
var aws = require('aws-sdk');
var ec2 = new aws.EC2();
var rds = new aws.RDS();
aws.config.region = 'us-east-1';
exports.handler = function(event,context) {
if (event) {
console.log(event.id);
}
//setup params for rds call
var rdsparams = {
DBInstanceIdentifier: 'master',
};
//setup params for ec2 call
var ec2params = {
Filters: [
{
Name: 'tag:role',
Values: [
'app'
],
}
]
};
//Get ec2 instances with app tag, may need to add a condition on running so pulled it into hash
ec2.describeInstances(ec2params, function(err, appdata) {
if (err) {
console.log(err);
return;
}
else {
var apparray={};
for(var i = 0; i < appdata.Reservations.length; i++) {
var ins = appdata.Reservations[i].Instances[0];
var id = ins.InstanceId;
var state = ins.State.Name;
apparray[id]=state;
}
console.log(apparray);
context.succeed(apparray);
}
});
rds.describeDBInstances(rdsparams, function(err, data) {
if (err) {
console.log(err, err.stack);
return;
}
else {
var rdsarray={};
var rdsarray=(data);
console.log(rdsarray);
var ins=rdsarray[0];
var name = ins.ReadReplicaDBInstanceIdentifiers[0];
rdsarray[replicant]=name;
}
context.succeed(rdsarray);
});
//context.done();
};
I want to return my filtered (apparray) and (rdsarray) back from my functions and perform a calculation on this within the main body of the script. Any ideas on how to do this.
something like
var replicas = rdsarray.length for example
Thanks in advance
var aws = require('aws-sdk');
var ec2 = new aws.EC2();
var rds = new aws.RDS();
aws.config.region = 'us-east-1';
exports.handler = function(event, context) {
if (event) {
console.log(event.id);
}
//setup params for rds call
var rdsparams = {
DBInstanceIdentifier: 'master',
};
//setup params for ec2 call
var ec2params = {
Filters: [{
Name: 'tag:role',
Values: [
'app'
],
}]
};
//Get ec2 instances with app tag, may need to add a condition on running so pulled it into hash
ec2.describeInstances(ec2params, function(err, appdata) {
if (err)
return context.done(err, null);
var apparray = {};
for (var i = 0; i < appdata.Reservations.length; i++) {
var ins = appdata.Reservations[i].Instances[0];
var id = ins.InstanceId;
var state = ins.State.Name;
apparray[id] = state;
}
console.log(apparray);
var resultData = {};
resultData.apparray = apparray;
rds.describeDBInstances(rdsparams, function(err, data) {
if (err)
return context.done(err, null);
var rdsarray = {};
var rdsarray = (data);
console.log(rdsarray);
var ins = rdsarray[0];
var name = ins.ReadReplicaDBInstanceIdentifiers[0];
rdsarray[replicant] = name;
resultData.rdsarray = rdsarray;
context.done(null, resultData);
});
});
};
and back in the code from you are calling the lambda function
var lambda = new sdk.Lambda();
var params = {
FunctionName: 'arn:aws:lambda:us-west-2:1541546477777:function:MyFunction',
Payload: JSON.stringify(/*your params here*/)
};
lambda.invoke(params, function(err, data) {
if (err) {
console.log('error ===', err);
return ;
}
var lambdaData = JSON.parse(data.Payload);
// do your stuff here
});
Is this what you needed? It may be broken but I hope you get the idea of it

Categories