Skip to content

Instantly share code, notes, and snippets.

@howinator
Last active February 4, 2017 14:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save howinator/83d8a0e7ba15eeb0a23a1600a7c3bf16 to your computer and use it in GitHub Desktop.
Save howinator/83d8a0e7ba15eeb0a23a1600a7c3bf16 to your computer and use it in GitHub Desktop.
sparkabowl-api-reference.md

Infrastructure/Data Flow

The process starts with a user making a request to the Echo. The Echo records the input and sends it to the Amazon Alexa service. The Alexa service process the recording and decomposes it to text. That text is then cross-referenced against a JSON document, found here to determine what the "intent" of the user is. The found intent is then sent with other metadata to an AWS service called Lambda. AWS Lambda can be black boxed to be thought of as just a piece of code, without any physical infrastructure, which takes input values and returns values. We develop Lambda code ourselves and I wrote it in Python because Lambda only supports a few languages (Python, Node, Java, C#). Our Lambda code uses the intent sent by Alexa to decide what to do. Right now, we have one intent, "FeedDogsIntent". When our Lambda code receives JSON with this intent, it kicks off the process of making and sending a packet to the RPi. The RPi receives this packet, and, if it is a valid request, it activates a GPIO pin which enables the motor and feeds the dogs.

Structure of JSON Packet Sent to RPi

The key to the JSON packet is the field formed here. If that field's value is as it is there, the dogs should be fed immediately. There are a couple other fields in the packet that will be there for security. One field will be a signature field. This signature field gives a way of validating that the packet received by the RPi came from our Lambda function. Basically, this field will contain the result of hash(packet-contents-without-hash+secret). Google "HMAC" to find more information about how to use this signature to validate the packet. Another field will be a timestamp. We probably don't want to allow packets that are more than 5 seconds old. This protects us against replay attacks.

RPi Program Requirements

The Haskell program will run on the RPi as a server and receive JSON packets. The Haskell program will be responsible for validating the JSON packet as described above, turning on a RPi GPIO pin and returning an HTTP status code of 200 if the dogs were succesively fed. If it fails, it should return a HTTP status code of 503.

Minimum Viable Product

At the very least, the Haskell program should accept a JSON packet of the form {'type':'FeedDogsNow'} and feed the dogs immediately. The validation of the JSON signature and timeout should be there before we deploy this to prod, but feeding based off the above JSON will be sufficient for the MVP.

What I Can Do

  • I can take care of the deployment of the code to the RPi.I've alread written about a 1,000 lines of code for provisioning the RPi and deploying code to Lambda so this shouldn't be a problem.You should probably come up with a way of running a test server on your local machine to test things.
  • I can do code review.
  • I can take care of any modifications to the Lambda code as requirements on the RPi change.
  • I can provide a sample JSON packet but of course the timestamp will be wrong.

Security

See this answer for information about cryptographic signing via HMAC in Haskell. Basically, the RPi will receive the packed which will look like JSON={'type':'FeedDogsNow', 'timestamp':'2017-02-3', 'signature':'absbu838948snafmnsf'}. The RPi will then compute HMAC(JSON['type']+JSON['timestamp']+key) and compare the result to the value of JSON['signature']. Since only the RPi and Lambda have access to key (some random string), if the value for signature sent in the JSON and the value computed by the RPi are the same, we can say that the request is valid. Furthermore, if we reject packets which are more than 5 seconds old, we prevent a class of attacks called replay attacks.

I've read quite a bit about this and the experts say that the above method is reliable and the difficult part is taken care of by the implementor of the HMAC function. If we were storing passwords/authenticating multiple users, I would say we should stay the fuck away, but this is apparently fairly straightforward crypto.

What Has Already Been Done

  • The Alexa configuration
  • The Lambda code
  • The deployment chain/infrastructure for the Lambda code.
  • The automatic provisioning of the RPi.

Everything I've done so far has been in the form of code, so don't worry about breaking anything. It can all be reverted to a known state with a couple keystrokes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment