Doorbot.ts - Let me in the building, with Typescript
2020-02-13
A common issue with makerspaces is letting people in the door. Members sign up and should have access immediately. Members leave and should have their access dropped just as fast. Given the popularity of the Raspberry Pi among makers, it makes sense to start there, but how do you handle the software end?
Doorbot.ts is a modular solution to this problem. It’s split into three parts:
- A Reader takes input from some device. It could be a USB key reader, or a Wiegand RFID reader
- An Authenticator checks if the given input credentials are allowed
- An Activator does something if the input passes
A basic setup might read a keyfob from the reader, authenticate against an API held on a central server, and then (assuming everything checks out) activate a GPIO pin on the Raspberry Pi for 30 seconds. This pin could be connected to a solenoid or magnetic hold to unlock the door (usually with a MOSFET or relay, since the RPi can’t drive the voltages for either of those).
The parts that interface to a Raspberry Pi (such as a Wiegand reader or activating a GPIO pin) are in a separate repository here: https://github.com/frezik/rpi-doorbot-ts
Security
The system can be compromised in quite a few ways. RFID tags can be copied. Cheap 10 digit keys can be brute forced. If you buy cheaply in bulk, there’s a good chance those RFIDs are sequential or otherwise predictable. The Raspberry Pi can be compromised. The database can be compromised.
Which is not to say it’s hopeless. That is, it’s no more hopeless than what security you already have. An attacker can put a rock through any window. Physical locks can be picked, often without much skill at all. If you’re like many makerspaces, you’ll give a keyfob to anyone who shows up with membership dues, and you probably don’t even check their ID.
So no, it’s not the most secure system in the world, but it’s also not the weakest point in the chain, either.
This isn’t to say security should be ignored. Take basic precautions here, like using good passwords, and keeping the systems up to date.
Wiegand
Wiegand is a common protocol for RFID readers. There are cheap readers that work like a USB keyboard, “typing” the numbers of the fob. However, they’re usually not built for outdoor mounting. There are cheap Wiegand options that are.
The protocol runs over two wires (plus power/ground). There is a Reader module in rpi-doorbot-ts for handling it directly. I don’t recommend using it. The issue is that reading the data over GPIO pins means using tight timing, and doing this in Node.js is often unreliable. It often resulted in needing to scan fobs two or three times before getting a clean read.
Instead, you can use a C program who’s only job is to read Wiegand, interpret the bits, and spit out the number. Doorbot.ts then has as Reader that can read a filehandle. So you launch the C program, pipe its stdout into the Reader, and there you go. From practical testing, this has been far more reliable in scanning fobs the first time.
Installing the System
I recommend creating a directory in your home dir on your Raspberry Pi:
$ mkdir doorbot-deployment
$ cd doorbot-deployment
And then create a basic package.json
:
{
"name": "doorbot",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@frezik/doorbot-ts": "^0.13.0",
"@frezik/rpi-doorbot-ts": "^0.6.0"
}
}
Be sure typescript is installed globally, and then install all the dependencies:
$ sudo npm install -g typescript
$ npm install
Next, make an index.ts
to run the system:
import * as Doorbot from '../index';
const INPUT_FILE = "database.json";
let reader = new Doorbot.FHReader(
process.stdin
);
let auth = new Doorbot.JSONAuthenticator( INPUT_FILE );
let act = new Doorbot.DoNothingActivator( () => {
console.log( "Activate!" );
});
Doorbot.init_logger();
Doorbot.log.info( "Init" );
reader.setAuthenticator( auth );
auth.setActivator( act );
reader.init();
Doorbot.log.info( "Ready to read" );
reader
.run()
.then( () => {} );
This code creates a reader that works from STDIN, and authenticates against a JSON file, which would have entries like this:
{
"1234": true,
"5678": true,
"0123": false
}
It then hooks the reader, authenticator, and activator together and starts it running. You can type the key codes (“1234”, “5678”, etc.) in to get a response.
I’ll be following up with some more advanced usages in future posts.