Skip to content

Commit

Permalink
Merge pull request #6 from familab/mjh/feature/docs
Browse files Browse the repository at this point in the history
Added documentation of the implementation phases going forward
  • Loading branch information
BZWingZero authored Feb 21, 2024
2 parents cf1c874 + 3522773 commit 786c07e
Show file tree
Hide file tree
Showing 10 changed files with 345 additions and 28 deletions.
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.yml]
indent_size = 2
125 changes: 107 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,121 @@
<style>
body {
color: #fda501;
background-color: #2b2b2b;
}
</style>

FamiLAB Access Controller
=========================

Access Control software written for Familab.
Access Control software written for FamiLAB.

## Components

### Access Control Point

- Badge scanner and door unlock trigger.
- Microcontroller written in CircuitPython.
- Reads badge, calls auth server, if ✅ then open door.

See [nfc/README.md](./nfc/README.md)

### Authentication Server

- HTTP server written in Typescript.
- Exposes `/access` endpoint.
- `/access` endpoint fetches badge list from Google Sheets for validation.

See [api/README.md](./api/README.md)

## Development Setup

1. Install Node 18+
2. Globally install `pnpm`
```bash
npm install --global pnpm
```
```bash
npm install --global pnpm
```
3. Install Node packages
```bash
pnpm install
```
```bash
pnpm install
```
4. Follow Development Setup instructions for the sub-project you wish to work on.

## Project Status

Currently implementing Phase 0.

### Phase 0

Phase 0 is the absolute minimum functionality that allows badge access to the new facility. It is not meant to be
long-term, it is not meant to be well-designed. Has the minimum number of infrastructure dependencies.

#### Requirements

- Working door lock
- ACP that can read badges and unlock door
- WiFi network without Internet

#### Functionality

1. User scans badge
2. ACP calls Auth Server with badge and location
3. Auth Server checks against hardcoded list and responds ✅/❌
4. If user has access, ACP triggers relay to unlock door

#### Hardware

- ACP: ESP-32 and MFRC522 connected on a breadboard, possibly powered by USB
- Auth Server: Living on a raspberry pi or something

#### Component Diagram

![Phase 0 Component Diagram](./docs/diagrams/out/component-diagram-Phase_0.png)

### Phase 1

This is the first _real_ version of the access control system.

#### Requirements

- 12/24v DC power line run to the door location
- Internet access

#### Functionality

1. User scans badge
2. ACP calls Auth Server with badge and location
3. Auth Server fetches Google Sheet contents (or checks cache) and responds ✅/❌
4. If user has access, ACP triggers relay to unlock door

#### Hardware

- ACP: MFRC522 mounted outside door, ESP32 mounted inside. Powered by hardwired DC.
- Auth Server: Can still be on temp hardware, but now has internet access.

#### Component Diagram

![Phase 1 Component Diagram](./docs/diagrams/out/component-diagram-Phase_1.png)

### Phase 2

Some enhancements that can be made in the future, fairly independently.

#### Permanent ACP hardware build

- Manufactured PCB
- External antenna for MFRC522
- Status LED/display

## Version 2 Goals
* Move the canonical list of badges to the cloud to protect from an SD card failure
* Expand the system to support more access types than just the front door
* Improve security for who can update the badge list
#### Central Relay Board

## API v2
_Note: More details can be found in the readme in the api_v2 folder_.
- Centralized relay board that powers all door locks
- ACP would then not be responsible for door lock, just communicating with auth server
- All power control in one place
- Allows for remote opening of doors, doors unlocked for open house, etc.

Includes a single API endpoint.
Retrieves badge access list from a Google Spreadsheet.
Compares badge and location from API request to list from google spreadsheets and returns a boolean true/false.
#### Better Auth Server hosting/networking security

## Microcontroller v2
TBD
- Permanent hosting infrastructure, more reliable server than Raspberry Pi
- Internal DNS hostname would allow for TLS, reduces sniffing/man-in-the-middle attacks
- Put all access control devices on separate subnet/vlan, improves network security
41 changes: 31 additions & 10 deletions api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,53 @@ FamiLAB Access Controller API
====================================

## Goals
Create a single, authorative data source for members that the access control system can tie into.

Create a single, authoritative data source for members that the access control system can tie into.

* Expand the door control system to be able to support other devices.
* Allow "dumb" device control that only needs to make a single api call to check for access.

## Design

A google spreadsheet will be used as the authoritative data source for badges.
The accessController API will provide a single endpoint with two variables: `badgeId` and `location`. When a request comes in, a canonical google sheet will be queried via Google's APIs to retrieve the list of badges and their access.
The accessController API will provide a single endpoint with two variables: `badgeId` and `location`. When a request
comes in, a canonical google sheet will be queried via Google's APIs to retrieve the list of badges and their access.

From the returned spreadsheet, a row matching the `badgeId` will be checked for a matching value for `location`.
accessController API will then return a boolean true/false.

## Development Setup

1. Install Node 18+
2. Globally install `pnpm`
```bash
npm install --global pnpm
```
3. Install Node packages
```bash
pnpm install
```

From the returned spreadsheet, a row matching the `badgeId` will be checked for a matching value for `location`. accessController API will then return a boolean true/false.
## Development

## Download and Build:
### Prerequisites:
`nodejs` v16.15 or later.
### Download:
Pull branch and run `npm install` to download dependencies
### Build:
Run `npm build run` from the working directory. Server will start on localhost at the port specified in the `.env` file.
To run the code as a development server, run:

```bash
npm run dev
```

## Development Status:

### Complete:

* Create GET endpoint supporting two variables: `badgeId`, `location`
* Query google spreadsheet using google API
* Parse retrieved sheet to JSON
* Compare incoming `badgeId` and `location` to parsed json and return `[true, false]`
* Log requests to disk (and console.)

### TODO:

* Provide a way to retrieve logs that's nicer than grepping the .log file.
* Rotate logfile occasionally if it ends up growing too big.
* Create a default badge list to be stored in the .env file to use when device starts in offline.
Expand Down
30 changes: 30 additions & 0 deletions docs/diagrams/_shared.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@startuml(id=style)
!theme crt-amber
!pragma teoz true
skinparam componentStyle rectangle
skinparam backgroundColor transparent
skinparam backgroundColor #3C3D3E

<style>
fontColor: #fda501
note, group {
backgroundColor: #151515
}
note {
fontStyle: bold
}
box {
lineStyle: 0
roundCorner: 8
linecolor: #151515
}
</style>

header "FamiLAB Access Control"
hide footbox
@enduml

@startuml
!include _shared.puml!style
component TestComponent
@enduml
61 changes: 61 additions & 0 deletions docs/diagrams/component-diagram.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
@startuml
!include _shared.puml!style

title Phase 0

actor user as "User"

package "Access Control Point" {
[reader] as "RFID Reader" <<MFRC522>>
[mcu] as "Microcontroller" <<ESP-32>>
[lock] as "Door Lock"
}

package "Raspberry Pi" {
[server] as "Authentication\nServer"
}

user --> reader: Scans badge
reader -> mcu: reads badge id
mcu --> server: Is user allowed?

server -> server: Checks hardcoded user list

mcu <-- server: User is/is not allowed
mcu -> lock: unlocks door

user <-- lock: Opens for
@enduml

@startuml
!include _shared.puml!style

title Phase 1

actor user as "User"

package "Access Control Point" {
[reader] as "RFID Reader" <<MFRC522>>
[mcu] as "Microcontroller" <<ESP-32>>
[lock] as "Door Lock"
}

package "Raspberry Pi" {
[server] as "Authentication\nServer"
}

cloud "Google" {
[google] as "Google Sheet"
}

user --> reader: Scans badge
reader -> mcu: reads badge id
mcu --> server: Is user allowed?

server <--> google: Fetch user access info

mcu <-- server: User is/is not allowed
mcu -> lock: unlocks door

user <-- lock: Opens for
@enduml
Binary file added docs/diagrams/out/component-diagram-Phase_0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/diagrams/out/component-diagram-Phase_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/diagrams/out/sequence-diagram-Phase_0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/diagrams/out/sequence-diagram-Phase_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 786c07e

Please sign in to comment.