Skip to content

Instantly share code, notes, and snippets.

@MattyK14
Created July 5, 2017 13:47
Show Gist options
  • Save MattyK14/0553d56c571c6499c88d59427fa29c73 to your computer and use it in GitHub Desktop.
Save MattyK14/0553d56c571c6499c88d59427fa29c73 to your computer and use it in GitHub Desktop.
MQTT AWS Snippet
import AWS, { CognitoIdentityCredentials } from 'aws-sdk/dist/aws-sdk-react-native';
import { CognitoUserPool } from 'react-native-aws-cognito-js';
import { Client, Message } from 'react-native-paho-mqtt';
import appConfig from '../helpers/appConfig';
import SigV4Utils from '../helpers/SigV4Utils';
class Home extends Component {
componentDidMount() {
this.connectIoT();
}
componentWillUnmount() {
this.client.disconnect();
}
/**
* Creates a MQTT client, grants the user IoT permissions, connects the client
* to AWS IoT & subscribes to the user's topic. Parses any messages received
* from string to JSON to be handled by handleIoTMessage().
*/
connectIoT() {
AWS.config.credentials.get(() => {
var ioturl = SigV4Utils.getSignedUrl(appConfig.iotEndpoint, appConfig.region, AWS.config.credentials);
const client = new Client({ uri: ioturl, clientId: 'Some Unqiue ID', storage: AsyncStorage });
this.client = client;
client.on('messageReceived', (message) => {
const jsonResponse = JSON.parse(message.payloadString);
// console.log(jsonResponse);
this.handleIoTMessage(jsonResponse);
});
client.on('connectionLost', (responseObject) => {
console.log('CLIENT DC');
if (responseObject.errorCode !== 0) {
clearInterval(this.publishInterval);
console.log('CONNECTIONLOST TRIGGERED:', responseObject.errorMessage);
}
});
var connectOptions = {
useSSL: true,
timeout: 30000, // In milliseconds, it turns out
mqttVersion: 4,
};
const IoT = new AWS.Iot();
var params = {
policyName: appConfig.policyName,
principal: AWS.config.credentials.identityId
};
IoT.attachPrincipalPolicy(params, (err) => {
if (err) {
console.log('ERROR attachPrincipalPolicy: ', err);
}
client.connect(connectOptions).then(() => {
client.subscribe('Some relevant topic');
})
.catch((responseObject) => {
console.log(responseObject);
if (responseObject.errorCode !== 0) {
console.log(`CATCH ONCONNECTIONLOSTTRIGGERED: ${responseObject.errorMessage}`);
}
});
});
});
}
}
import AWS from 'aws-sdk/dist/aws-sdk-react-native';
export default function SigV4Utils() {}
/**
* Used to create signature key for signing the URL.
* @param {string} key - User's secretAccessKey stored in AWS.credentials.
* @param {string} date - (format: YYYYMMDD).
* @param {string} region - Our AWS region (us-east-1).
* @param {string} service - The service being used (iotdevicegateway).
*/
SigV4Utils.getSignatureKey = (key, date, region, service) => {
var kDate = AWS.util.crypto.hmac(`AWS4${key}`, date, 'buffer');
var kRegion = AWS.util.crypto.hmac(kDate, region, 'buffer');
var kService = AWS.util.crypto.hmac(kRegion, service, 'buffer');
var kCredentials = AWS.util.crypto.hmac(kService, 'aws4_request', 'buffer');
return kCredentials;
};
/**
* Used to sign the IoT endpoint URL to establish a MQTT websocket.
* @param {string} host - Our AWS IoT endpoint.
* @param {string} region - Our AWS region (us-east-1).
* @param {object} credentials - Current user's stored AWS.config.credentials object.
*/
SigV4Utils.getSignedUrl = (host, region, credentials) => {
var datetime = AWS.util.date.iso8601(new Date()).replace(/[:-]|\.\d{3}/g, '');
var date = datetime.substr(0, 8);
var method = 'GET';
var protocol = 'wss';
var uri = '/mqtt';
var service = 'iotdevicegateway';
var algorithm = 'AWS4-HMAC-SHA256';
var credentialScope = `${date}/${region}/${service}/aws4_request`;
var canonicalQuerystring = `X-Amz-Algorithm=${algorithm}`;
var credentialsURI = encodeURIComponent(`${credentials.accessKeyId}/${credentialScope}`);
canonicalQuerystring += `&X-Amz-Credential=${credentialsURI}`;
canonicalQuerystring += `&X-Amz-Date=${datetime}`;
canonicalQuerystring += '&X-Amz-SignedHeaders=host';
var canonicalHeaders = `host:${host}\n`;
var payloadHash = AWS.util.crypto.sha256('', 'hex');
// Linter throws an error on string concatenation here. I couldn't get a template string to work -MK.
var canonicalRequest = method + '\n' + uri + '\n' + canonicalQuerystring + '\n' + canonicalHeaders + '\nhost\n' + payloadHash;
var stringToSign = `${algorithm}\n${datetime}\n${credentialScope}\n${AWS.util.crypto.sha256(canonicalRequest, 'hex')}`;
var signingKey = SigV4Utils.getSignatureKey(credentials.secretAccessKey, date, region, service);
var signature = AWS.util.crypto.hmac(signingKey, stringToSign, 'hex');
canonicalQuerystring += `&X-Amz-Signature=${signature}`;
if (credentials.sessionToken) {
canonicalQuerystring += `&X-Amz-Security-Token=${encodeURIComponent(credentials.sessionToken)}`;
}
var requestUrl = `${protocol}://${host}${uri}?${canonicalQuerystring}`;
return requestUrl;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment