Skip to content

Commit

Permalink
Updated README:
Browse files Browse the repository at this point in the history
- Added component descriptions
- Added phase list
- Added component diagram per phase
  • Loading branch information
bkwrm95 committed Feb 21, 2024
1 parent b0d67aa commit 3522773
Show file tree
Hide file tree
Showing 10 changed files with 342 additions and 10 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
104 changes: 104 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
<style>
body {
color: #fda501;
background-color: #2b2b2b;
}
</style>

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

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+
Expand All @@ -15,3 +40,82 @@ Access Control software written for FamiLAB.
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

#### Central Relay Board

- 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.

#### Better Auth Server hosting/networking security

- 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.
113 changes: 113 additions & 0 deletions docs/diagrams/sequence-diagram.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
@startuml
!include _shared.puml!style

title Phase 0
hide footbox

participant user as "User"

box FamiLAB
box "Access Control Point"
participant reader as "RFID Reader" <<MFRC522>>
participant mcu as "Microcontroller" <<ESP-32>>
participant lock as "Door Lock"
end box

box "Raspberry Pi"
participant server as "Authentication\nServer"
end box
end box

== Badge Entry: Valid ==

user -> reader: User scans badge
activate user
activate reader
reader -> mc: Read badge id
deactivate reader
activate mc
mc -> server: Validate badge id
activate server
server->server: Compare badge id\nto hardcoded users list
return ""200"" Ok
lock <- mc: Unlock
deactivate mc
user <- lock: User can enter
deactivate user

== Badge Entry: Invalid ==

user -> reader: User scans badge
activate user
activate reader
reader -> mc: Read badge id
deactivate reader
activate mc
mc -> server: Validate badge id
activate server
server->server: Compare badge id\nto hardcoded users list
return ""401"" Unauthorized
user <- mc: Nothing happens
@enduml

@startuml
!include _shared.puml!style

title Phase 1
hide footbox

participant user as "User"

box FamiLAB
box "Access Control Point"
participant reader as "RFID Reader" <<MFRC522>>
participant mcu as "Microcontroller" <<ESP-32>>
participant lock as "Door Lock"
end box

box "Raspberry Pi"
participant server as "Authentication\nServer"
end box
end box

box "Cloud"
participant google as "Google Sheet"
end box

== Badge Entry: Valid ==

user -> reader: User scans badge
activate user
activate reader
reader -> mc: Read badge id
deactivate reader
activate mc
mc -> server: Validate badge id
activate server
server -> google: Fetch all users and badges
activate google
return All users and badges
server->server: Compare badge id\nto users list
return ""200"" Ok
lock <- mc: Unlock
deactivate mc
user <- lock: User can enter
deactivate user

== Badge Entry: Invalid ==

user -> reader: User scans badge
activate user
activate reader
reader -> mc: Read badge id
deactivate reader
activate mc
mc -> server: Validate badge id
activate server
server -> google: Fetch all users and badges
activate google
return All users and badges
server->server: Compare badge id\nto users list
return ""401"" Unauthorized
user <- mc: Flash red light or something
@enduml

0 comments on commit 3522773

Please sign in to comment.