-
-
Save MattyK14/0553d56c571c6499c88d59427fa29c73 to your computer and use it in GitHub Desktop.
MQTT AWS Snippet
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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