Compare commits

..

2 Commits

Author SHA1 Message Date
3643f3a435
WIP: sql_app: Logger config (Broken state)
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-05 14:37:52 +03:00
7d0d1b0f0e
WIP: database rework 1 (broken state)
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-05 13:54:31 +03:00
26 changed files with 604 additions and 1396 deletions

1
.gitignore vendored
View File

@ -5,5 +5,4 @@ server.orig.key
__pycache__
venv/
*.db
sql_app.db*
.vscode/

View File

@ -1,130 +0,0 @@
From b08a24bedfb247fd148c48e00ee5d9b544991dfe Mon Sep 17 00:00:00 2001
From: HeshamTB <hishaminv@gmail.com>
Date: Thu, 14 Apr 2022 07:16:28 +0300
Subject: [PATCH] admin: All admin path functions require an APIKey
Signed-off-by: HeshamTB <hishaminv@gmail.com>
---
sql_app/auth_helper.py | 10 +++++++++-
sql_app/main.py | 19 ++++++++++---------
2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/sql_app/auth_helper.py b/sql_app/auth_helper.py
index a9b866b..12aa271 100644
--- a/sql_app/auth_helper.py
+++ b/sql_app/auth_helper.py
@@ -3,18 +3,22 @@ from typing import Optional
from decouple import config
from datetime import datetime, timedelta
from sqlalchemy.orm import Session
-from fastapi import Depends
+from fastapi import Depends, Security, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
+from fastapi.security.api_key import APIKey, APIKeyHeader
from . import crud, crypto, schemas
import jwt
import time
JWT_SECRET = config('jwt_secret')
JWT_ALGO = config('jwt_algorithm')
+__API_KEY = config('API_KEY')
+__API_KEY_NAME = config('API_KEY_NAME')
+api_key_header = APIKeyHeader(name=__API_KEY_NAME)
def create_access_token(data : dict, expires_delta : Optional[timedelta] = None):
# TODO: Consider making non-expiring token
@@ -33,3 +37,7 @@ def authenticate_user(db: Session, username : str, password : str):
return False
return crypto.verify_key(password, user.passwd_salt, user.hashed_password)
+def valid_api_key(key = Security(api_key_header)):
+ if not __API_KEY == key:
+ raise HTTPException(401, detail="invalid key")
+ return
diff --git a/sql_app/main.py b/sql_app/main.py
index 413db35..9a9434e 100644
--- a/sql_app/main.py
+++ b/sql_app/main.py
@@ -1,5 +1,6 @@
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
+from fastapi.security.api_key import APIKey
from sqlalchemy.orm import Session
from . import crud, models, schemas, auth_helper
@@ -65,31 +66,31 @@ def get_user_details(current_user: schemas.User = Depends(get_current_active_use
return current_user
@app.get("/admin/users/", response_model=List[schemas.User], tags=['Admin'])
-def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
+def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
users = crud.get_users(db, skip=skip, limit=limit)
return users
@app.get("/admin/iotentities/", response_model=List[schemas.IotEntity], tags=['Admin'])
-def read_iot_entities(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
+def read_iot_entities(skip: int = 0, limit: int = 100, db: Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
iot_entities = crud.get_iot_entities(db, skip=skip, limit=limit)
return iot_entities
# TODO: Can duplicate
@app.post("/admin/iotentities/create", response_model=schemas.IotEntity, tags=['Admin'])
-def create_iot_entities(iot_entity: schemas.IotEntityCreate, db: Session = Depends(get_db)):
+def create_iot_entities(iot_entity: schemas.IotEntityCreate, db: Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
iot_entities = crud.create_iot_entity(db, iot_entity)
return iot_entities
@app.get("/admin/users/{user_id}", response_model=schemas.User, tags=['Admin'])
-def read_user(user_id: int, db: Session = Depends(get_db)):
+def read_user(user_id: int, db: Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
db_user = crud.get_user(db, user_id=user_id)
if db_user is None:
raise HTTPException(status_code=404, detail="User not found")
return db_user
# TODO: Can duplicate
@app.post("/admin/users/allowdevice/id", tags=['Admin'])
-def allow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db)):
+def allow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
user = crud.get_user(db, request.user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
@@ -105,7 +106,7 @@ def allow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityReques
return user
@app.post("/admin/users/disallowdevice/id", tags=['Admin'])
-def disallow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db)):
+def disallow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
user = crud.get_user(db, request.user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
@@ -122,7 +123,7 @@ def disallow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityReq
return
@app.post("/admin/users/allowdevice/name", tags=['Admin'])
-def allow_user_for_iot_entity_by_name(request: schemas.UserAllowForIotEntityRequestByUsername, db: Session = Depends(get_db)):
+def allow_user_for_iot_entity_by_name(request: schemas.UserAllowForIotEntityRequestByUsername, db: Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
user = crud.get_user_by_username(db, request.username)
if not user:
raise HTTPException(status_code=404, detail="User not found")
@@ -138,11 +139,11 @@ def allow_user_for_iot_entity_by_name(request: schemas.UserAllowForIotEntityRequ
return
@app.post("/admin/users/{user_id}/deactiveate", tags=['Admin'])
-def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
+def deactiveate_user(user_id: int, db:Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
return
@app.post("/admin/users/{user_id}/activeate", tags=['Admin'])
-def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
+def deactiveate_user(user_id: int, db:Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
return
@app.get("/users/acesslist/", response_model=List[schemas.IotEntity], tags=['Users'])
--
libgit2 1.4.3

View File

@ -1,33 +0,0 @@
/*
* Wrapper around mbedtls to provide AES encryption
*
* Needs esp32 arduino platform libraries
*
* Hesham T. Banafa
* May 9th, 2022
*
*/
#include <string.h>
#include "encryption.h"
static int valid_time(long long time_epoch);
extern void aes_init(aes_t *ctx, char *key)
{
mbedtls_aes_init(&ctx->aes_ctx);
//mbedtls_aes_setkey_enc(ctx->aes_ctx, (const unsigned char*)key, strlen(key) * 8 );
ctx->psk_key = key; // Save key ptr
}
extern void aes_encrypt(aes_t *ctx, char *plain_text, char *out_buf)
{
if (ctx == NULL) return; // What are you doing? out_buf remains as is.
mbedtls_aes_setkey_enc(&ctx->aes_ctx, (const unsigned char*)ctx->psk_key, strlen(ctx->psk_key) * 8 );
mbedtls_aes_crypt_ecb(&ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, (const unsigned char*)plain_text, (unsigned char*)out_buf);
}
extern void aes_decrypt(aes_t *ctx, char *cipher_text, char *out_buf)
{
}

View File

@ -1,24 +0,0 @@
/*
* Wrapper around mbedtls to provide AES encryption
*
* Needs esp32 arduino platform libraries
*
* Hesham T. Banafa
* May 9th, 2022
*
*/
#include "mbedtls/aes.h"
typedef struct aes_t
{
const char *psk_key;
mbedtls_aes_context aes_ctx;
} aes_t;
static int valid_time(long long time_epoch);
extern void aes_init(aes_t *ctx, char *key);
extern void aes_encrypt(aes_t *ctx, char *plain_text, char *out_buf);
extern void aes_decrypt(aes_t *ctx, char *cipher_text, char *out_buf);

View File

@ -1,12 +1,9 @@
aiocoap==0.4.3
anyio==3.5.0
asgiref==3.5.0
attrs==21.4.0
bitlist==0.6.2
cbor2==5.4.2.post1
certifi==2022.5.18.1
cffi==1.15.0
charset-normalizer==2.0.12
click==8.0.4
cryptography==36.0.1
Cython==0.29.28
@ -20,31 +17,22 @@ greenlet==1.1.2
h11==0.13.0
httptools==0.3.0
idna==3.3
iniconfig==1.1.1
LinkHeader==0.4.3
packaging==21.3
parts==1.2.2
pluggy==1.0.0
py==1.11.0
pycparser==2.21
pydantic==1.9.0
Pygments==2.11.2
PyJWT==2.3.0
pyparsing==3.0.9
pytest==7.1.2
python-decouple==3.6
python-dotenv==0.19.2
python-multipart==0.0.5
PyYAML==6.0
requests==2.27.1
six==1.16.0
sniffio==1.2.0
SQLAlchemy==1.4.31
starlette==0.17.1
termcolor==1.1.0
tomli==2.0.1
typing_extensions==4.1.1
urllib3==1.26.9
uvicorn==0.17.5
uvloop==0.16.0
watchgod==0.7

10
run-tls
View File

@ -1,14 +1,4 @@
#!/bin/bash
source venv/bin/activate
cd sql_app/
./file_permissios.py
if [ $? == 1 ]
then
echo "enviorment file_permissions are incorrect"
exit 1
fi
cd ../
exec uvicorn sql_app.main:app --ssl-certfile server.crt --ssl-keyfile server.key --port 4040 --host 0.0.0.0 --no-server-header

View File

@ -1,4 +0,0 @@
#!/bin/bash
source venv/bin/activate
exec uvicorn sql_app.main:app --ssl-certfile server.crt --ssl-keyfile server.key --port 4040 --host 0.0.0.0 --no-server-header --reload

View File

@ -1,45 +1,13 @@
- [x] Constrcut DB Schema
- [x] Issue requests from Lap to Pi or vica versa
- [x] Decide HTTP vs MQTT vs CoAP
- [x] Hash passwords
- [x] Salt passwords
- [x] User registraion
- [x] User login in API
- [x] JWT token access
- [x] Look into how to revoke a signed key
- [ ] Record Session info in token & db (allow for session cancel)
- [x] Add username for users (now only email)
- [X] Expose Room monitor function (temp, count humid..)
- [X] Expose door lock function
- [X] Record access log
- [X] Expose data analysis
- [X] Load backend onto RPi
- [X] Test connections in lab network
- [X] Define emrgancy triggers (manual and automatic)
- [ ] Redesign database
- [ ] Define emrgancy triggers (manual and automatic)
- [ ] Expose temporary control in case of emergancy
- Triggers
- Acccess
- Resolve (revoke access)
- [X] Temporal door open commands (Needs door state to operate efficiatly)
- [X] Open for 1H
- [ ] Open to 1:30PM
- [ ] Set schedual
- [ ] Temporal door open commands (Needs door state to operate efficiatly)
- Open for 1H
- Open to 1:30PM
- Set schedual
- [X] Issue door open command
- [X] Make functions to gen a IotEntity token
- [ ] Write a small program/script to generate new Iot token and add new Iot Device into database
- [X] Make inital database entries automatic for easy reset
- [X] Expose access list endpoint for doors
- [X] Access list coutner for iot door
- [X] Force close in middle of timed open request
- [ ] Record user connections and time
- [ ] Record Iot dev connection and time
- [ ] Write unit tests
- [ ] Develop a program to visualize the data
- [ ] CLI frontend
- [X] Emergaency
- [X] Send state with accesslist
- [X] Split monitor into different class
- [ ] Make a script that adds types, and thier basic database ops?? (avoid writing boiler-plate)
- [ ] Make a script that emulates a door and monitor
- [ ] Check file premissions on .env file, if global reject
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJibHVldG9vdGhfbWFjIjoic3RyaW5nIn0.ELl5AfBR1NdM4_OFhl_SCTm9EMPpqjiCKOSS0CrOJps
- [ ] Save prefix of token to allow/revoke token??

View File

@ -1,5 +1,3 @@
# May 2022
# Hesham T. Banafa <hishaminv@gmail.com>
from typing import Optional
from decouple import config
@ -49,22 +47,22 @@ def create_iot_dev_token(data: dict):
encoded_jwt = jwt.encode(to_encode, JWT_SECRET, algorithm=JWT_ALGO)
return encoded_jwt
def valid_iot_token(token : str, db: Session):
def valid_iot_door_token(token : str, db: Session):
try:
payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGO])
except jwt.DecodeError:
return None
mac_signed = payload.get("bluetooth_mac")
device = crud.get_iot_entity_by_bluetooth_mac(db, mac_signed)
device = crud.get_door_by_bluetooth_mac(db, mac_signed)
return device
def valid_monitor_token(token: str, db: Session):
def valid_iot_monitor_token(token : str, db: Session):
try:
payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGO])
except jwt.DecodeError:
return None
mac_signed = payload.get("bluetooth_mac")
monitor = crud.get_monitor_bluetooth(db, mac_signed)
return monitor
device = crud.get_monitor_by_bluetooth_mac(db, mac_signed)
return device

View File

@ -1,265 +1,192 @@
# March 2022
# Hesham T. Banafa <hishaminv@gmail.com>
# CRUD (Create, Read, Update, Delete) from db
from sqlalchemy import select, join
from sqlalchemy.orm import Session
from . import models, schemas, crypto, auth_helper
from datetime import datetime
from warnings import warn
# TODO: Data we can collect or log
# - Last user connection (link to user)
# - Last Iot Entity Connection (link to IotEntity)
# - Any open request (link to user)
# - Any polling from IotEntity? Maybe to much data
def get_user(db: Session, user_id: int) -> models.User:
def get_user(db: Session, user_id: int):
return db.query(models.User).get(user_id)
def get_iot_entity(db: Session, id: int) -> models.IotEntity:
return db.query(models.IotEntity).get(id)
def get_door_by_id(door_id: int):
return db.query(models.IotDoor).get(door_id)
def get_iot_entity_by_description(db: Session, description: str):
return db.query(models.IotEntity).filter(models.IotEntity.description == description).first()
def get_door_by_description(db: Session, description: str):
# TODO: 2 or more Desciptions may collide
return db.query(models.IotDoor).filter(models.IotDoor.description == description).first()
def get_iot_entity_by_bluetooth_mac(db: Session, bluetooth_mac: str) -> models.IotEntity:
return db.query(models.IotEntity).filter(models.IotEntity.bluetooth_mac == bluetooth_mac).first()
def get_door_by_bluetooth_mac(db: Session, bluetooth_mac: str):
return db.query(models.IotDoor).filter(models.IotDoor.bluetooth_mac == bluetooth_mac).first()
def get_user_by_email(db: Session, email: str) -> models.User:
def get_monitor_by_bluetooth_mac(db: Session, bluetooth_mac: str):
return db.query(models.IotMonitor).filter(models.IotMonitor.bluetooth_mac == bluetooth_mac).first()
def get_user_by_email(db: Session, email: str):
return db.query(models.User).filter(models.User.email == email).first()
def get_user_by_username(db: Session, username: str) -> models.User:
def get_user_by_username(db: Session, username: str):
return db.query(models.User).filter(models.User.username == username).first()
def get_users(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.User).offset(skip).limit(limit).all()
def get_access_log_for_door_by_door_mac(db: Session, iot_id: str):
warn("Manual access log read is deprecated. Use device.access_log",
DeprecationWarning, stacklevel=2)
return db.query(models.DoorAccessLog)\
.filter(models.DoorAccessLog.iot_id == iot_id).all()
def get_access_log_for_room(db: Session, room_id: int):
return db.query(models.DoorAccessLog).filter(models.DoorAccessLog.room == room_id).all()
def get_access_log_for_user_by_id(db: Session, id : str):
return db.query(models.DoorAccessLog).filter(models.DoorAccessLog.user_id == id).all()
# def get_room_data_now(db: Session, door_id: int) -> models.RoomSensorData:
# door = get_iot_entity(db, door_id)
# monitor : models.Monitors = door.monitor
# if not monitor: return -1
# if len(monitor.sensor_history) == 0: return -2
# return monitor.sensor_history[-1]
def get_room_data_now(db: Session, room_id: int):
return db.query(models.IotMonitor).filter(models.IotMonitor.room_id == room_id)
def get_doors(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.IotDoor).offset(skip).limit(limit).all()
def get_monitors(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.IotMonitor).offset(skip).limit(limit).all()
def get_rooms(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.Room).offset(skip).limit(limit).all()
def get_user_room_access_list_by_username(db: Session, username: str):
user : models.User = get_user_by_username(db, username)
links : List[models.UserRoomAuth] = db.query(models.UserRoomAuth).filter(models.UserRoomAuth.user_id == user.id).all()
return db.query(models.Room).filter(models.Room.authorized_users == user.id).all()
def get_room_door(db: Session, room_id: int):
door = db.query(models.IotDoor).filter(models.IotDoor.room_id == room_id).first()
return door
def get_room(db: Session, room_id: int):
room = db.query(models.Room).get(room_id)
return room
def get_room_access_log_for_user(db: Session, user_id: int, room_id: int):
log = db.query(models.DoorAccessLog).filter(models.DoorAccessLog.user_id == user_id, models.DoorAccessLog.room == room_id).all()
return log
def get_room_current_readings(db: Session, room: schemas.Room) -> models.IotMonitor:
room : models.Room = get_room(db, room.id)
monitor = db.query(models.IotMonitor).filter(models.IotMonitor.room_id == room.id).first()
return mon
def get_monitor_for_room(db: Session, room: schemas.Room) -> models.IotMonitor:
return db.query(models.IotMonitor).filter(models.IotMonitor.room_id == room.id).first()
def get_door_for_room(db: Session, room_id: int) -> models.IotDoor:
return db.query(models.IotDoor).filter(models.IotDoor.room_id == room_id).first()
def get_room_from_door(db: Session, door: models.IotDoor):
return get_room(db, door.room_id)
def create_user(db: Session, user: schemas.UserCreate):
key = crypto.gen_new_key(user.password)
salt = key[1]
hashed_pass = key[0]
db_user = models.User(email=user.email,
username=user.username,
hashed_password=hashed_pass,
passwd_salt=salt)
db_user = models.User(email=user.email, username=user.username,hashed_password=hashed_pass, passwd_salt=salt)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
def update_user_password(db: Session, user: models.User, request: schemas.UserUpdatePassword):
key = crypto.gen_new_key(request.password)
salt = key[1]
hashed_pass = key[0]
user.passwd_salt = salt
user.hashed_password = hashed_pass
db.add(user)
db.commit()
db.refresh(user)
def get_iot_entities(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.IotEntity).offset(skip).limit(limit).all()
def get_monitors(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.Monitors).offset(skip).limit(limit).all()
def create_iot_entity(db: Session, iot_entity: schemas.IotEntityCreate):
db_item = models.IotEntity(bluetooth_mac=iot_entity.bluetooth_mac,
description=iot_entity.description)
def create_door(db: Session, door: schemas.IotDoorCreate):
db_item = models.IotDoor(room_id=door.room_id,
description=door.description,
bluetooth_mac=door.bluetooth_mac)
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item
def create_monitor(db: Session, monitor: schemas.IotEntityBase):
db_item = models.Monitors(bluetooth_mac=monitor.bluetooth_mac,
description=monitor.description)
def create_monitor(db: Session, monitor: schemas.IotMonitorCreate):
db_item = models.IotMonitor(room_id=monitor.room_id,
description=monitor.description,
bluetooth_mac=monitor.bluetooth_mac)
db.add(db_item)
db.commit()
db.refresh(db_item)
return
def create_room(db: Session, room: schemas.RoomCreate):
db_item = models.Room(building_name=room.building_name,
building_number=room.building_number)
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item
def get_monitor(db: Session, id: int) -> models.Monitors:
return db.query(models.Monitors).get(id)
def get_monitor_bluetooth(db: Session, bluetooth_mac: str) -> models.Monitors:
return db.query(models.Monitors).filter(models.Monitors.bluetooth_mac == bluetooth_mac).first()
def update_monitor(db: Session, monitor: models.Monitors):
db.add(monitor)
db.commit()
db.refresh(monitor)
def update_monitor_readings(db: Session, monitor_upadte: schemas.MonitorUpdateReadings, bluetooth_mac: str):
monitor = get_monitor_bluetooth(db, bluetooth_mac)
monitor.humidity = monitor_upadte.humidity
monitor.people = monitor_upadte.people
monitor.smoke_sensor_reading = monitor_upadte.smoke_sensor_reading
monitor.temperature = monitor_upadte.temperature
db.add(monitor)
db.commit()
db.refresh(monitor)
def create_user_link_to_iot(db: Session, user_id: int, iot_dev_id: int):
# Ensure link is not already present and it does not allow duplicates
link = db.query(models.UserAuthToIoTDev).filter(models.UserAuthToIoTDev.user_id == user_id).filter(models.UserAuthToIoTDev.iot_id == iot_dev_id).first()
if link: return True
new_link = models.UserAuthToIoTDev(user_id=user_id,
iot_id=iot_dev_id,
timestamp=datetime.now())
def allow_user_room_access(db: Session, user_id: int, room_id: int):
link = db.query(models.UserRoomAuth).filter(models.UserRoomAuth.user_id == user_id, models.UserRoomAuth.room_id == room_id).first()
if link: return link
new_link = models.UserRoomAuth(user_id=user_id, room_id=room_id)
db.add(new_link)
db.commit()
db.refresh(new_link)
return True
return link
def remove_user_link_to_iot(db: Session, user_id: int, iot_dev_id: int):
# Ensure link is not already present and it does not allow duplicates
link = (db.query(models.UserAuthToIoTDev)
.filter(models.UserAuthToIoTDev.user_id == user_id)
.filter(models.UserAuthToIoTDev.iot_id == iot_dev_id)
.first())
def disallow_user_room_access(db: Session, user_id, room_id: int):
link = db.query(models.UserRoomAuth).filter(models.UserRoomAuth.user_id == user_id, models.UserRoomAuth.room_id == room_id)
if not link: return True
db.delete(link)
db.flush()
db.commit()
#db.refresh(link)
return True
def set_open_door_request(db: Session, iot_entity_id: int, time_seconds : int):
device = get_iot_entity(db, iot_entity_id)
setattr(device, "open_request", True)
def open_door_request(db: Session, request: schemas.OpenRoomRequest, time_seconds: int = 10):
link = db.query(models.UserRoomAuth).filter(models.UserRoomAuth.user_id == request.user_id,
models.UserRoomAuth.room_id == request.room_id).first()
if not link: return False
door : models.IotDoor = db.query(models.IotDoor).filter(models.IotDoor.room_id == request.room_id).first()
if not door: return False
setattr(door, "open_request", True)
if time_seconds < 1:
time_seconds = 10 # Magic number move to global constant
setattr(device, "time_seconds", time_seconds)
db.add(device)
setattr(door, "time_seconds", time_seconds)
db.add(door)
db.commit()
db.refresh(device)
db.refresh(door)
return True
def set_close_door_request(db: Session, iot_id: int):
device : models.IotEntity = get_iot_entity(db, iot_id)
device.force_close = True
db.add(device)
def clear_open_door_request(db: Session, room_id: int):
door : models.IotDoor = db.query(models.IotDoor).filter(models.IotDoor.room_id == room_id).first()
setattr(door, "open_request", False)
setattr(door, "time_seconds", 10)
db.add(door)
db.commit()
db.refresh(device)
return True
def clear_close_door_request(db: Session, iot_id: int):
device : models.IotEntity = get_iot_entity(db, iot_id)
device.force_close = False
db.add(device)
db.commit()
def set_user_last_token(db: Session, username: str, token: str):
user : models.User = get_user_by_username(db, username)
user.last_token = token
db.add(user)
db.commit()
db.refresh(user)
return True
def set_door_state(db: Session, iot_device: models.IotEntity, state: bool):
iot_device.state = state
db.add(iot_device)
db.commit()
db.refresh(iot_device)
def get_user_last_token(db: Session, username: str):
user : models.User = get_user_by_username(db, username)
return user.last_token # This method is bad security practice.
def clear_open_door_request(db: Session, iot_entity_id: int):
device = get_iot_entity(db, iot_entity_id)
setattr(device, "open_request", False)
setattr(device, "time_seconds", 10)
db.add(device)
db.commit()
db.refresh(device)
db.refresh(door)
return True
def record_door_access_log(db: Session, entry: schemas.DoorAccessLog):
db_item = models.DoorAccessLog(user_id=entry.user_id,
iot_id=entry.iot_id,
command=entry.command,
room=entry.room_id,
timestamp=entry.timestamp)
db.add(db_item)
db.commit()
db.refresh(db_item)
def record_room_sensor_data(db: Session, entry: schemas.MonitorUpdateReadings,
monitor :models.Monitors):
def record_room_sensor_data(db: Session, entry: schemas.IotMonitorRoomInfo):
db_item = models.RoomSensorData(humidity=entry.humidity,
people=entry.people,
temperature=entry.temperature,
smoke_sensor_reading=entry.smoke_sensor_reading,
timestamp=datetime.now(),
monitor_id=monitor.id)
smoke=entry.smoke,
timestamp=datetime.now())
db.add(db_item)
db.commit()
db.refresh(db_item)
monitor.humidity = entry.humidity
monitor.temperature = entry.temperature
monitor.people = entry.people
monitor.smoke_sensor_reading = entry.smoke_sensor_reading
db.add(monitor)
def on_access_list_change(db: Session, room_id: int, allow: bool):
# Use when a user is allowed or disallowed to a room.
door = get_door_for_room(db, room_id)
door.accesslist_counter = door.accesslist_counter + 1
db.add(door)
db.commit()
db.refresh(monitor)
db.refresh(door)
def increment_door_access_list_counter(db: Session, iot_entity: models.IotEntity):
iot_entity.acces_list_counter = iot_entity.acces_list_counter + 1
db.add(iot_entity)
db.commit()
db.refresh(iot_entity)
def record_user_connection(db: Session, user: models.User, time: datetime):
entry = models.UserConnectionHistory(user_id=user.id, timestamp=time)
db.add(entry)
db.commit()
db.refresh(entry)
# def get_sensor_data_for_room(db: Session, monitor_id: int, count_last: int):
# data = db.query(models.RoomSensorData).all()
# if not data or len(data) == 0: return -1
# return data[-count_last]
def update_user_status(db: Session, user: models.User, state: bool):
user.is_active = state
db.add(user)
db.commit()
db.refresh(user)
def record_emergancy_entry(db: Session, monitor_data: schemas.MonitorUpdateReadings, monitor_id: int):
new_entry : models.EmergancyNotice = models.EmergancyNotice(
monitor_id=monitor_id,
people=monitor_data.people,
temperature=monitor_data.temperature,
smoke_sensor_reading=monitor_data.smoke_sensor_reading,
timestamp=datetime.now()
)
db.add(new_entry)
db.commit()
db.refresh(new_entry)
# TODO: Get room sensor data
# TODO: Get room door status

View File

@ -1,5 +1,3 @@
# March 2022
# Hesham T. Banafa <hishaminv@gmail.com>
import os
from hashlib import pbkdf2_hmac

View File

@ -1,11 +1,8 @@
# March 2022
# Hesham T. Banafa <hishaminv@gmail.com>
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db"
SQLALCHEMY_DATABASE_URL = "sqlite:///./data.db"
# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db"
# For sqlite

View File

@ -1,45 +0,0 @@
# Quick enroll new device
# Hesham T. Banafa
# Jun 12th, 2022
from decouple import config
import requests
# idk if this stays in memory...
headers = {
"accept": "application/json",
"Content-type": "application/json"
}
def main():
if len(sys.argv) != 4:
print_help()
exit(1)
device_type = sys.argv[1]
bluetooth_mac = sys.argv[2]
description = sys.argv[3]
if device_type == 'DOOR':
mkdoor(bluetooth_mac, description)
elif device_type == 'MONITOR':
mkmonitor(bluetooth_mac, description)
else:
print('Device type not DOOR or MONITOR', file=sys.stderr)
exit(1)
# gen print token of bluetooth_mac
print(create_iot_dev_token(bluetooth_mac))
def mkdoor(bluetooth_mac: str, description: str):
data = {
"bluetooth_mac": bluetooth_mac,
"description": description
}
#response = requests.post("")
def mkmonitor(bluetooth_mac: str, description: str):
pass
def print_help():
msg = 'usgae: enroll_iotdevice <DOOR|MONITOR> <bluetooth_mac> <description>'
print(msg)

View File

@ -1,18 +0,0 @@
#!/bin/python
# Hesham T. Banafa
# Jun 12th, 2022
# Check enviorment file permissions and return -1 if fails or 0
import os
import stat
ENV_FILE='.env'
st = os.stat(ENV_FILE)
if st.st_mode & stat.S_IROTH or \
st.st_mode & stat.S_IWOTH or \
st.st_mode & stat.S_IXOTH:
exit(1)
exit(0)

View File

@ -1,137 +0,0 @@
# June 2022
# Hesham T. Banafa <hishaminv@gmail.com>
from . import crud, main, schemas, auth_helper
from decouple import config
from .database import SessionLocal
from datetime import timedelta, datetime
from random import randint
db = SessionLocal()
def init_user():
user = schemas.UserCreate(email="hisham@banafa.com.sa",
username="Hesham",
password=config('first_user_pass'))
user_exists = crud.get_user_by_email(db, user.email)
if user_exists: return
crud.create_user(db, user)
token = auth_helper.create_access_token(data={"sub": user.username}, expires_delta=timedelta(minutes=15))
res = crud.set_user_last_token(db, user.username, token)
user_exists = None
user = schemas.UserCreate(email="osama@mail.none",
username="Osama",
password=config('first_user_pass'))
user_exists = crud.get_user_by_email(db, user.email)
if user_exists: return
crud.create_user(db, user)
token = auth_helper.create_access_token(data={"sub": user.username}, expires_delta=timedelta(minutes=15))
res = crud.set_user_last_token(db, user.username, token)
user_exists = None
user = schemas.UserCreate(email="Hussain@mail.none",
username="Hussain",
password=config('first_user_pass'))
user_exists = crud.get_user_by_email(db, user.email)
if user_exists: return
crud.create_user(db, user)
token = auth_helper.create_access_token(data={"sub": user.username}, expires_delta=timedelta(minutes=15))
res = crud.set_user_last_token(db, user.username, token)
user_exists = None
user = schemas.UserCreate(email="Assad@mail.none",
username="Assad",
password=config('first_user_pass'))
user_exists = crud.get_user_by_email(db, user.email)
if user_exists: return
crud.create_user(db, user)
token = auth_helper.create_access_token(data={"sub": user.username}, expires_delta=timedelta(minutes=15))
res = crud.set_user_last_token(db, user.username, token)
def init_door():
iot_door = schemas.IotEntityCreate(bluetooth_mac="94:b9:7e:fb:57:1a",
description="Iot Lab Door")
door_exists = crud.get_iot_entity_by_bluetooth_mac(db, iot_door.bluetooth_mac)
if door_exists: return
crud.create_iot_entity(db, iot_door)
def init_monitor():
iot_monitor = schemas.IotEntityCreate(bluetooth_mac="ff:ff:ff",
description="Iot Lab Monitor")
monitor_exists = crud.get_monitor_bluetooth(db, iot_monitor.bluetooth_mac)
if monitor_exists: return
crud.create_monitor(db, iot_monitor)
def init_allowance():
crud.create_user_link_to_iot(db, 1, 1)
def init_sensor_data():
monitor = crud.get_monitor(db, 1)
if monitor.sensor_history: return
for i in range(50):
room_data = \
schemas.\
IotMonitorRoomInfo\
(humidity=randint(20, 80),
people=randint(0, 10),
temperature=randint(18, 27),
smoke_sensor_reading=randint(150, 700),
token='dummy')
crud.record_room_sensor_data(db, room_data, monitor)
def init_open_close_requests():
user = crud.get_user_by_email(db, "hisham@banafa.com.sa")
if user.access_log: return
crud.set_open_door_request(db, 1, 10)
log_entry = schemas.DoorAccessLog(user_id=user.id,
iot_id=1,
command="OPEN",
timestamp=datetime.now())
crud.record_door_access_log(db, log_entry)
log_entry = schemas.DoorAccessLog(user_id=user.id,
iot_id=1,
command="OPEN",
timestamp=datetime.now())
crud.record_door_access_log(db, log_entry)
log_entry = schemas.DoorAccessLog(user_id=user.id,
iot_id=1,
command="OPEN",
timestamp=datetime.now())
crud.record_door_access_log(db, log_entry)
log_entry = schemas.DoorAccessLog(user_id=user.id,
iot_id=1,
command="CLOSE",
timestamp=datetime.now())
crud.record_door_access_log(db, log_entry)
def init_user_connections():
users = [ crud.get_user(db, 1),
crud.get_user(db, 2),
crud.get_user(db, 3)]
for i in range(3):
crud.record_user_connection(db, users[i], datetime.now())
crud.record_user_connection(db, users[i], datetime.now())
crud.record_user_connection(db, users[i], datetime.now())
def init_link_room_monitor():
monitor = crud.get_monitor(db, 1)
door = crud.get_iot_entity(db, 1)
monitor.door = door
crud.update_monitor(db, monitor)
def init():
init_user()
init_door()
init_monitor()
init_allowance()
init_sensor_data()
init_open_close_requests()
init_user_connections()
init_link_room_monitor()

View File

@ -4,17 +4,3 @@ echo "API_KEY=$(./gen_secret.sh)" >> .env
echo "API_KEY_NAME=big_boy" >> .env
echo "jwt_secret=$(./gen_secret.sh)" >> .env
echo "jwt_algorithm=HS256" >> .env
read -s -p "First User password: " firstpass
echo
read -s -p "Retype First User password: " secondpass
echo
if [ $firstpass != $secondpass ];
then
echo "Passwords dont match!"
exit 255
fi
echo "first_user_pass=$firstpass" >> .env
chmod 600 .env

26
sql_app/logger_config.py Normal file
View File

@ -0,0 +1,26 @@
log_config = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"access": {
"()": "uvicorn.logging.AccessFormatter",
"fmt": '%(levelprefix)s %(asctime)s :: %(client_addr)s - "%(request_line)s" %(status_code)s',
"use_colors": True
},
},
"handlers": {
"access": {
"formatter": "access",
"class": "logging.StreamHandler",
"stream": "ext://sys.stdout",
},
},
"loggers": {
"uvicorn.access": {
"handlers": ["access"],
"level": "INFO",
"propagate": False
},
},
}

View File

@ -1,15 +1,10 @@
# March 2022
# Hesham T. Banafa <hishaminv@gmail.com>
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm, OAuth2AuthorizationCodeBearer
from fastapi.security.api_key import APIKey
from fastapi.responses import PlainTextResponse
from sqlalchemy.orm import Session
from . import crud, models, schemas, auth_helper, init_db
from . import crud, models, schemas, auth_helper
from .database import SessionLocal, engine
from .utils import get_db, EMERG_SMOKE, EMERG_TEMP, EMERG_OPEN_TIME_SEC
from typing import List
from datetime import timedelta, datetime
@ -20,151 +15,229 @@ oauth = OAuth2PasswordBearer(tokenUrl="tkn")
app = FastAPI(title="IoT Building System")
# Split into endpoints modules
#app.include_router(users.router,prefix="/users", tags=["User"])
init_db.init()
def get_current_user(token: str = Depends(oauth), db: Session = Depends(get_db)):
credentials_exception = HTTPException(
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
headers={"WWW-Authenticate": "Bearer"})
inactive_user_exception = HTTPException(status_code=status.HTTP_403_FORBIDDEN,
detail="Inactive user")
email_used_exception = HTTPException(status_code=400,
detail="Email already registered")
username_used_exception = HTTPException(status_code=400,
detail="Username already registerd")
user_not_found_exception = HTTPException(status_code=404,
detail="User not found")
room_not_found_exception = HTTPException(status_code=404,
detail="Room not found")
unauth_to_open = HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail="Unauthrized to open")
str_not_implemented = 'Not Implemented'
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
def get_current_user(token: str = Depends(oauth), db: Session = Depends(get_db)):
try:
payload = jwt.decode(token, auth_helper.JWT_SECRET, algorithms=[auth_helper.JWT_ALGO])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
token_data = schemas.TokenData(username=username)
#token_data = schemas.TokenData(username=username)
except jwt.PyJWTError:
raise credentials_exception
user = crud.get_user_by_username(db, username=token_data.username)
user = crud.get_user_by_username(db, username=username)
if user is None:
raise credentials_exception
return user
def get_current_active_user(current_user: schemas.User = Depends(get_current_user)):
if not current_user.is_active:
raise HTTPException(status_code=400, detail="Inactive user")
raise inactive_user_exception
return current_user
def get_current_iot_device(current_device: schemas.IotBluetoothMac = Depends(),
db: Session = Depends(get_db)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
payload = jwt.decode(token, auth_helper.JWT_SECRET, algorithms=[auth_helper.JWT_ALGO])
mac_signed = payload.get("bluetooth_mac")
if (mac_signed != current_device): raise credentials_exception
device = crud.get_iot_entity_by_bluetooth_mac(db, mac_signed)
return device
@app.post("/users/reg", response_model=schemas.User, tags=['Users'])
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
db_user = crud.get_user_by_email(db, email=user.email)
if db_user:
raise HTTPException(status_code=400, detail="Email/Username already registered")
raise email_used_exception
db_user = crud.get_user_by_username(db, username=user.username)
if db_user:
raise HTTPException(status_code=400, detail="Email/Username already registered")
raise username_used_exception
db_user = crud.create_user(db=db, user=user)
if not db_user:
raise HTTPException(status_code=500, detail="Failed to create user")
access_token = auth_helper.create_access_token(
data={"sub": db_user.username}, expires_delta=timedelta(minutes=15)
)
crud.set_user_last_token(db, db_user.username, access_token)
#crud.record_user_connection(db, db_user, datetime.now())
return db_user
return crud.create_user(db=db, user=user)
@app.get("/users/me/", response_model=schemas.User, tags=['Users'])
def get_user_details(db: Session = Depends(get_db),
current_user: schemas.User = Depends(get_current_active_user)):
#crud.record_user_connection(db, current_user, datetime.now())
def get_user_details(current_user: schemas.User = Depends(get_current_active_user)):
return current_user
@app.get("/admin/users/", response_model=List[schemas.User], tags=['Admin'])
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
users = crud.get_users(db, skip=skip, limit=limit)
return users
@app.get("/admin/doors/", response_model=List[schemas.IotDoor], tags=['Admin'])
def read_iot_doors(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
doors = crud.get_doors(db, skip=skip, limit=limit)
return doors
@app.get("/admin/monitors/", response_model=List[schemas.IotMonitor], tags=['Admin'])
def read_iot_doors(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
monitors = crud.get_monitors(db, skip=skip, limit=limit)
return monitors
@app.get("/admin/rooms/", response_model=List[schemas.Room], tags=['Admin'])
def read_iot_doors(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
rooms = crud.get_rooms(db, skip=skip, limit=limit)
return rooms
@app.post("/admin/create/door/", response_model=schemas.IotDoor, tags=['Admin'])
def create_iot_entities(door: schemas.IotDoorCreate, db: Session = Depends(get_db)):
#iot_entities = crud.create_iot_entity(db, iot_entity)
new_door = crud.create_door(db, door)
return new_door
@app.post("/admin/create/monitor/", response_model=schemas.IotMonitor, tags=['Admin'])
def create_iot_entities(monitor: schemas.IotMonitorCreate, db: Session = Depends(get_db)):
#iot_entities = crud.create_iot_entity(db, iot_entity)
new_monitor = crud.create_monitor(db, monitor)
return new_monitor
@app.post("/admin/create/room/", response_model=schemas.Room, tags=['Admin'])
def create_iot_entities(room: schemas.RoomCreate, db: Session = Depends(get_db)):
new_room = crud.create_room(db, room)
return new_room
@app.get("/admin/users/{user_id}", response_model=schemas.User, tags=['Admin'])
def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user(db, user_id=user_id)
if db_user is None:
raise user_not_found_exception
return db_user
@app.post("/admin/users/allowaccess/id", response_model=schemas.AllowRoomAccessRequestID, tags=['Admin'])
def allow_user_room_access_by_id(request: schemas.AllowRoomAccessRequestID,
db: Session = Depends(get_db)):
user = crud.get_user(db, request.user_id)
if not user:
raise user_not_found_exception
room = crud.get_room(db, request.room_id)
if not room:
raise room_not_found_exception
#res = crud.create_user_link_to_iot(db, request.user_id, request.iot_entity_id)
res = crud.allow_user_room_access(db, request.user_id, request.room_id)
if not res:
raise HTTPException(status_code=500, detail="Could not complete operation")
return request
@app.post("/admin/users/disallowaccess/id", tags=['Admin'])
def disallow_user_room_access_by_id(request: schemas.AllowRoomAccessRequestID,
db: Session = Depends(get_db)):
user = crud.get_user(db, request.user_id)
if not user:
raise user_not_found_exception
room = crud.get_room(db, request.room_id)
if not room:
raise room_not_found_exception
res = crud.disallow_user_room_access(db, request.user_id, request.room_id)
if not res:
raise HTTPException(status_code=500, detail="Could not complete operation")
return
@app.post("/admin/users/{user_id}/deactiveate", tags=['Admin'], description=str_not_implemented)
def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
return
@app.post("/admin/users/{user_id}/activeate", tags=['Admin'], description=str_not_implemented)
def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
return
@app.post("/admin/iotdevice/gentoken/", response_model=schemas.Token, tags=['Admin'])
def generate_token_for_iot_device(bluetooth_mac : schemas.IotBluetoothMac,
api_key: APIKey = Depends(auth_helper.valid_api_key)):
# We get here after a valid admin key, so send back permenant token
data = {"bluetooth_mac": bluetooth_mac.bluetooth_mac}
tkn = auth_helper.create_iot_dev_token(data)
return {"access_token": tkn, "token_type": "bearer"}
@app.post("/admin/room/accesslog/", tags=['Admin'])
def get_access_log_for_door(request : schemas.RoomAccessLogRequest,
db : Session = Depends(get_db)):
room = crud.get_room(db, request.room_id)
if not room: raise room_not_found_exception
return crud.get_access_log_for_room(db, request.room_id)
@app.post("/admin/room/authrizedusers/", tags=['Admin'])
def get_room_authrized_users(room: schemas.Room,
db: Session = Depends(get_db)):
room: models.Room = crud.get_room(db, room_id=room.id)
return room.authorized_users
@app.post("/admin/user/accesslog/room/", tags=['Admin'])
def get_room_access_log_history_for_user(request : schemas.RoomAccessLogRequestUserID,
db : Session = Depends(get_db)):
user = crud.get_user(db, request.user_id)
if not user: raise user_not_found_exception
room = crud.get_room(db, request.room_id)
if not room: raise room_not_found_exception
return crud.get_room_access_log_for_user(db, request.user_id, request.room_id)
@app.post("/admin/user/accesslog/room/username", tags=['Admin'])
def get_room_access_log_history_for_user_by_username(request : schemas.RoomAccessLogRequestUserUsername,
db : Session = Depends(get_db)):
user = crud.get_user_by_username(db, request.username)
if not user: raise user_not_found_exception
return crud.get_room_access_log_for_user(db, user.id, request.room_id)
@app.get("/users/acesslist/", response_model=List[schemas.Room], tags=['Users'])
def get_room_access_list_for_user(db: Session = Depends(get_db),
current_user: models.User = Depends(get_current_active_user)):
# Can use the ORM method current_user.authrized_rooms pulls from database on demand...
return current_user.authorized_rooms
@app.get("/admin/roominfo/now/", response_model=schemas.IotMonitor, tags=['Admin'])
def get_room_data(room : schemas.Room,
db: Session = Depends(get_db)):
monitor = crud.get_room_current_readings(db, room)
return monitor
@app.get("/admin/roominfo/now/all", response_model=List[schemas.IotMonitor], tags=['Admin'])
def get_all_rooms_data(db: Session = Depends(get_db)):
monitors = crud.get_monitors(db)
return monitors
@app.post("/users/open", tags=['Users'])
def issue_open_door_command(command: schemas.OpenDoorRequestTime,
def issue_open_door_command(request: schemas.OpenRoomRequest,
db: Session = Depends(get_db),
current_user: schemas.User = Depends(get_current_active_user)):
err = HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail="Unauthrized to open")
device = crud.get_iot_entity_by_bluetooth_mac(db, command.bluetooth_mac)
if not device: raise err
# TODO: Use database search rather then this linear search
user = crud.get_user(db, current_user.id)
for dev in user.authorized_devices:
if dev.bluetooth_mac == device.bluetooth_mac:
crud.set_open_door_request(db, device.id, command.time_seconds)
log_entry = schemas.DoorAccessLog(user_id=current_user.id,
iot_id=device.id,
command="OPEN",
timestamp=datetime.now())
crud.record_door_access_log(db, log_entry)
#crud.record_user_connection(db, current_user, datetime.now())
return device
raise err
@app.post("/users/close", tags=['Users'])
def issue_close_door_command(command: schemas.CloseDoorRequest,
db: Session = Depends(get_db),
current_user: schemas.User = Depends(get_current_active_user)):
err = HTTPException(status.HTTP_401_UNAUTHORIZED,
detail="Unaithrized to close")
device = crud.get_iot_entity_by_bluetooth_mac(db, command.bluetooth_mac)
if not device: raise err
user = crud.get_user(db, current_user.id)
for dev in user.authorized_devices:
if dev.bluetooth_mac == device.bluetooth_mac:
crud.set_close_door_request(db, device.id)
log_entry = schemas.DoorAccessLog(user_id=current_user.id,
iot_id=device.id,
command="CLOSE",
timestamp=datetime.now())
crud.record_door_access_log(db, log_entry)
#crud.record_user_connection(db, current_user, datetime.now())
return device
@app.get("/users/acesslist/", response_model=List[schemas.RoomOverview], tags=['Users'])
def get_iot_access_list_for_user(db: Session = Depends(get_db), current_user: schemas.User = Depends(get_current_active_user)):
user = crud.get_user_by_username(db, current_user.username)
access_list = list()
for device in user.authorized_devices:
door : models.IotEntity = device
monitor : models.Monitors = door.monitor
if not monitor: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="No Room link")
entry : schemas.RoomOverview = schemas.RoomOverview(
id=door.id,
description=door.description,
bluetooth_mac=door.bluetooth_mac,
open_request=door.open_request,
time_seconds=door.time_seconds,
acces_list_counter=door.acces_list_counter,
humidity=monitor.humidity,
people=monitor.people,
temperature=monitor.temperature,
smoke_sensor_reading=monitor.smoke_sensor_reading,
force_close=door.force_close,
state=door.state
)
access_list.append(entry)
#crud.record_user_connection(db, user, datetime.now())
return access_list
@app.patch("/users/updatepassword", tags=['Users'])
def change_user_password(request: schemas.UserUpdatePassword,
current_user: models.User = Depends(get_current_active_user),
db: Session = Depends(get_db)):
crud.update_user_password(db, current_user, request)
#device = crud.open_door_request(db, request.room_id, request.time_seconds)
#if not device: raise unauth_to_open # To no leak info
user : models.User = crud.get_user(db, current_user.id)
log_entry = schemas.DoorAccessLog(user_id=current_user.id,
room_id=request.room_id,
timestamp=datetime.now())
res = crud.open_door_request(db, request=request)
if not res: raise unauth_to_open
crud.record_door_access_log(db, log_entry)
return
@app.post("/users/tkn", response_model=schemas.Token, tags=['Users'])
@ -181,273 +254,30 @@ def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(), db:
access_token = auth_helper.create_access_token(
data={"sub": form_data.username}, expires_delta=timedelta(minutes=15)
)
crud.set_user_last_token(db, form_data.username, access_token)
#crud.record_user_connection(db, user, datetime.now())
return {"access_token": access_token, "token_type": "bearer"}
@app.get("/admin/users/", response_model=List[schemas.User], tags=['Admin'])
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
users = crud.get_users(db, skip=skip, limit=limit)
return users
@app.get("/admin/iotentities/", response_model=List[schemas.IotEntity], tags=['Admin'])
def read_iot_entities(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
iot_entities = crud.get_iot_entities(db, skip=skip, limit=limit)
return iot_entities
@app.get("/admin/monitors/", response_model=List[schemas.Monitor], tags=['Admin'])
def read_iot_monitors(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
monitors = crud.get_monitors(db, skip=skip, limit=limit)
return monitors
# TODO: Can duplicate
@app.post("/admin/iotentities/create", response_model=schemas.IotEntity, tags=['Admin'])
def create_iot_entities(iot_entity: schemas.IotEntityCreate, db: Session = Depends(get_db)):
iot_entities = crud.create_iot_entity(db, iot_entity)
return iot_entities
@app.post("/admin/monitor/create", response_model=schemas.Monitor, tags=['Admin'])
def create_monitor(iot_entity: schemas.IotEntityBase,
db: Session = Depends(get_db)):
monitor = crud.create_monitor(db, iot_entity)
return monitor
@app.get("/admin/users/{user_id}", response_model=schemas.User, tags=['Admin'])
def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user(db, user_id=user_id)
if db_user is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="User not found")
return db_user
@app.patch("/admin/users/allowdevice/id", tags=['Admin'])
def allow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db)):
user = crud.get_user(db, request.user_id)
if not user:
raise HTTPException(status.HTTP_404_NOT_FOUND,
detail="User not found")
iot_entity = crud.get_iot_entity(db, request.iot_entity_id)
if not iot_entity:
raise HTTPException(status.HTTP_404_NOT_FOUND,
detail="Iot Entity not found")
res = crud.create_user_link_to_iot(db, request.user_id, request.iot_entity_id)
if not res:
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Could not complete operation")
crud.increment_door_access_list_counter(db, iot_entity)
return
@app.patch("/admin/users/disallowdevice/id", tags=['Admin'])
def disallow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db)):
user = crud.get_user(db, request.user_id)
if not user:
raise HTTPException(status.HTTP_404_NOT_FOUND,
detail="User not found")
iot_entity = crud.get_iot_entity(db, request.iot_entity_id)
if not iot_entity:
raise HTTPException(status.HTTP_404_NOT_FOUND,
detail="Iot Entity not found")
res = crud.remove_user_link_to_iot(db, request.user_id, request.iot_entity_id)
if not res:
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Could not complete operation")
crud.increment_door_access_list_counter(db, iot_entity)
return
@app.patch("/admin/users/allowdevice/name", tags=['Admin'])
def allow_user_for_iot_entity_by_name(request: schemas.UserAllowForIotEntityRequestByUsername, db: Session = Depends(get_db)):
user = crud.get_user_by_username(db, request.username)
if not user:
raise HTTPException(status.HTTP_404_NOT_FOUND,
detail="User not found")
iot_entity = crud.get_iot_entity_by_description(db, request.description)
if not iot_entity:
raise HTTPException(status.HTTP_404_NOT_FOUND,
detail="Iot Entity not found")
res = crud.create_user_link_to_iot(db, user.id, iot_entity.id)
if not res:
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Could not complete operation")
return
@app.patch("/admin/users/{user_id}/deactiveate", tags=['Admin'])
def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
user = crud.get_user(db, user_id)
crud.update_user_status(db, user, False)
@app.patch("/admin/users/{user_id}/activeate", tags=['Admin'])
def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
user = crud.get_user(db, user_id)
crud.update_user_status(db, user, True)
@app.post("/admin/iotdevice/gentoken/", response_model=schemas.Token, tags=['Admin'])
def generate_token_for_iot_device(bluetooth_mac : schemas.IotBluetoothMac):
# api_key: APIKey = Depends(auth_helper.valid_api_key)
# We get here after a valid admin key, so send back permenant token
data = {"bluetooth_mac": bluetooth_mac.bluetooth_mac}
tkn = auth_helper.create_iot_dev_token(data)
return {"access_token": tkn, "token_type": "bearer"}
@app.patch("/admin/link/monitor/{monitor_id}/door/{door_id}", tags=['Admin'])
def link_monitor_with_door(monitor_id: int, door_id: int,
db: Session = Depends(get_db)):
monitor = crud.get_monitor(db, monitor_id)
door = crud.get_iot_entity(db, door_id)
monitor.door = door
crud.update_monitor(db, monitor)
return monitor
@app.post("/admin/user/accesslog/email/", tags=['Admin'])
def get_access_log_history_for_user(request : schemas.UserAccessLogRequestEmail,
db : Session = Depends(get_db)):
user = crud.get_user_by_email(db, request.email)
if not user: raise HTTPException(status.HTTP_404_NOT_FOUND, detail="User not found")
return user.access_log
@app.post("/admin/user/accesslog/username/", tags=['Admin'])
def get_access_log_history_for_user(request : schemas.UserAccessLogRequestUsername,
db : Session = Depends(get_db)):
user = crud.get_user_by_username(db, request.username)
if not user: raise HTTPException(status.HTTP_404_NOT_FOUND, detail="User not found")
return user.access_log
@app.get("/admin/roominfo/{door_id}/now", tags=['Admin'])
def get_room_data(door_id: int, db: Session = Depends(get_db)):
door = crud.get_iot_entity(db, door_id)
if not door:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="Door not found")
monitor : models.Monitors = door.monitor
if not monitor:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="No Room link")
data = monitor.sensor_history
if not data or len(data) == 0:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="No Sensor data")
return data[-1]
@app.get("/admin/roominfo/{monitor_id}/now", tags=['Admin'])
def get_room_data(monitor_id: int, db: Session = Depends(get_db)):
monitor = crud.get_monitor(db, monitor_id)
if not monitor: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="Monitor not found")
if not monitor.door_id:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Monitor not linked")
data = crud.get_room_data_now(db, monitor.door_id)
if data == -1: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="No Room link")
if data == -2: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="No Sensor data")
return data
@app.get("/admin/roominfo/{monitor_id}/last/{count}", tags=['Admin'])
def get_all_sensor_history(monitor_id: int, count: int,
db: Session = Depends(get_db)):
monitor = crud.get_monitor(db, monitor_id)
if not monitor: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="Monitor not found")
data = monitor.sensor_history
if not data or len(data) == 0:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="No Sensor data")
return data[-count:]
@app.post("/admin/roominfo/accesslog",response_model=List[schemas.DoorAccessLog], tags=['Admin'])
def get_access_log_for_door(request : schemas.AccessLogRequest,
db : Session = Depends(get_db)):
device: models.IotEntity = crud.get_iot_entity(db, request.iot_id)
if not device: raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Iot Entity not found")
return device.access_log
@app.post("/iotdevice/door/status", response_model=schemas.IotDoorPollingResponse, tags=['Iot'])
def polling_method_for_iot_entity(request: schemas.IotDoorPollingRequest,
@app.post("/iotdevice/door/status", response_model=schemas.IotDoor, tags=['Iot'])
def polling_method_for_door(request: schemas.IotDoorPollingRequest,
db: Session = Depends(get_db)):
device: models.IotEntity = auth_helper.valid_iot_token(request.token, db)
device: models.IotDoor = auth_helper.valid_iot_door_token(request.token, db)
if not device:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials")
response : schemas.IotDoorPollingResponse = schemas.IotDoorPollingResponse(
open_command=device.open_request,
acces_list_counter=device.acces_list_counter,
time_seconds=device.time_seconds,
force_close=device.force_close,
state=device.state)
room : models.Room = crud.get_room_from_door(db, device)
# Reset open_request to False
crud.clear_open_door_request(db, device.id)
crud.clear_close_door_request(db, device.id)
crud.set_door_state(db, device, bool(request.state))
return response
#crud.clear_open_door_request(db, room_id=room.id) # Make response object to perserve values;
return device
@app.post("/iotdevice/monitor/status", tags=['Iot'])
def polling_method_for_room_monitor(request: schemas.MonitorUpdateReadings,
def polling_method_for_room_monitor(request: schemas.IotMonitorRoomInfo,
db: Session = Depends(get_db)):
device : models.Monitors = auth_helper.valid_monitor_token(request.token, db)
device : schemas.IotMonitor = auth_helper.valid_iot_monitor_token(request.token, db)
if not device:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials")
crud.record_room_sensor_data(db, request, device)
if request.temperature >= EMERG_TEMP or request.smoke_sensor_reading >= EMERG_SMOKE:
print("********EMERGENCY AT %s********" % device.description)
door : models.IotEntity = device.door
print("********OPENING DOOR %s ID:%d********" % (door.description, door.id))
crud.set_open_door_request(db, door.id, EMERG_OPEN_TIME_SEC)
crud.record_emergancy_entry(db, request, device.id)
# Call into a hook to notify with room and people
print(request)
crud.record_room_sensor_data(db, request)
return request
@app.post("/iotdevice/door/users", response_class=PlainTextResponse, tags=['Iot'])
def get_allowed_usernames(request: schemas.IotDoorPollingRequest,
db: Session = Depends(get_db)):
iot_door : models.IotEntity = auth_helper.valid_iot_token(request.token, db)
if not iot_door:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials")
usernames = str()
for user in iot_door.authorized_users:
db_user : models.User = user
usernames = usernames + db_user.username + '\n'
return usernames
@app.post("/iotdevice/door/tkns", response_class=PlainTextResponse, tags=['Iot'])
def get_allowed_usernames(request: schemas.IotDoorPollingRequest,
db: Session = Depends(get_db)):
iot_door : models.IotEntity = auth_helper.valid_iot_token(request.token, db)
if not iot_door:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials")
tkns = str()
for user in iot_door.authorized_users:
db_user : models.User = user
tkns = tkns + db_user.last_token + '\n'
return tkns
@app.get("/test")
def get(db: Session = Depends(get_db)):
mon = crud.get_monitor(db, "ff:ff:ff:ff")
return mon.door

View File

@ -1,6 +1,3 @@
# March 2022
# Hesham T. Banafa <hishaminv@gmail.com>
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, DateTime
from sqlalchemy.orm import relationship
@ -16,87 +13,122 @@ class User(Base):
hashed_password = Column(String, nullable=False)
passwd_salt = Column(String, nullable=False)
is_active = Column(Boolean, default=True, nullable=False)
last_token = Column(String, nullable=True)
connections = relationship("UserConnectionHistory")
authorized_devices = relationship("IotEntity", secondary="user_iot_link", back_populates="authorized_users")
connections = relationship("UserConnectionHistory")
access_log = relationship("DoorAccessLog", back_populates="user")
class IotEntity(Base):
__tablename__ = "iot_entities"
authorized_rooms = relationship("Room", secondary= 'user_room_link', lazy='dynamic')
class Room(Base):
__tablename__ = 'rooms'
id = Column(Integer, primary_key=True, index=True)
bluetooth_mac = Column(String(512), index=True, unique=True)
description = Column(String(512))
open_request = Column(Boolean, default=False)
time_seconds = Column(Integer, default=10)
acces_list_counter = Column(Integer, default=0)
force_close = Column(Boolean, default=False)
state = Column(Boolean, default=False) # True is open, False is closed
authorized_users = relationship("User", secondary="user_iot_link", back_populates="authorized_devices")
access_log = relationship("DoorAccessLog", back_populates="iot_device") # one-to-many
monitor = relationship("Monitors", back_populates="door", uselist=False) # one-to-one
#door_id = Column(Integer, ForeignKey('iot_doors.id'))
building_name = Column(String(512))
building_number = Column(Integer)
class Monitors(Base):
__tablename__ = "monitors"
authorized_users = relationship("User", secondary='user_room_link')
id = Column(Integer, primary_key=True)
bluetooth_mac = Column(String(512), index=True, unique=True)
description = Column(String(512))
class UserRoomAuth(Base):
__tablename__ = 'user_room_link'
user_id = Column(Integer, ForeignKey('user_accounts.id'), primary_key=True, index=True)
room_id = Column(Integer, ForeignKey('rooms.id'), primary_key=True, index=True)
class IotMonitor(Base):
__tablename__ = 'iot_monitors'
id = Column(Integer, primary_key=True, index=True)
room_id = Column(Integer, ForeignKey('rooms.id'))
temp_c = Column(Integer, default=0)
smoke = Column(Integer, default=0)
humidity = Column(Integer, default=0)
people = Column(Integer, default=0)
temperature = Column(Integer, default=0)
smoke_sensor_reading = Column(Integer, default=0)
door_id = Column(Integer, ForeignKey("iot_entities.id"))
door = relationship("IotEntity", back_populates="monitor")
sensor_history = relationship("RoomSensorData", back_populates="monitor")
description = Column(String(512))
bluetooth_mac = Column(String(512))
class UserAuthToIoTDev(Base):
__tablename__ = "user_iot_link"
class IotDoor(Base):
__tablename__ = 'iot_doors'
user_id = Column(Integer, ForeignKey("user_accounts.id"), primary_key=True)
iot_id = Column(Integer, ForeignKey("iot_entities.id"), primary_key=True)
id = Column(Integer, primary_key=True, index=True)
room_id = Column(Integer, ForeignKey('rooms.id'))
open_request = Column(Boolean, default=False)
time_seconds = Column(Integer, default=10)
is_open = Column(Boolean, default=False)
force_close = Column(Boolean, default=False)
accesslist_counter = Column(Integer, default=0)
description = Column(String(512))
bluetooth_mac = Column(String(512))
class MonitorReadings(Base):
__tablename__ = 'monitor_readings'
reading_id = Column(Integer, primary_key=True, index=True)
timestamp = Column(DateTime)
temp_c = Column(Integer)
smoke = Column(Integer)
humidity = Column(Integer)
people = Column(Integer)
class DoorAccessLog(Base):
__tablename__ = "door_access_log"
__tablename__ = 'door_access_log'
entry_id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey('user_accounts.id'), index=True)
user = relationship("User", back_populates="access_log")
iot_id = Column(Integer, ForeignKey('iot_entities.id'), index=True)
iot_device = relationship("IotEntity", back_populates="access_log")
command = Column(String(16))
room = Column(Integer, ForeignKey('rooms.id'), index=True)
timestamp = Column(DateTime)
class RoomSensorData(Base):
__tablename__ = "room_sensor_data"
class UserConnections(Base):
__tablename__ = 'user_connection_history'
reading_id = Column(Integer, primary_key=True, index=True)
humidity = Column(Integer)
people = Column(Integer)
temperature = Column(Integer)
smoke_sensor_reading = Column(Integer)
entry_id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey('user_accounts.id'))
timestamp = Column(DateTime)
monitor_id = Column(Integer, ForeignKey("monitors.id"), index=True)
monitor = relationship("Monitors", back_populates="sensor_history")
class UserConnectionHistory(Base):
__tablename__ = "user_connection_history"
class IotDoorConnections(Base):
__tablename__ = 'door_connection_history'
reading_id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey("user_accounts.id"), index=True)
entry_id = Column(Integer, primary_key=True, index=True)
door_id = Column(Integer, ForeignKey('iot_doors.id'))
timestamp = Column(DateTime)
# TODO: add ip
class EmergancyNotice(Base):
__tablename__ = "emergency_notice"
class IotMonitorConnections(Base):
__tablename__ = 'monitor_connection_history'
id = Column(Integer, primary_key=True)
monitor_id = Column(Integer, ForeignKey("monitors.id"), index=True)
people = Column(Integer)
temperature = Column(Integer)
smoke_sensor_reading = Column(Integer)
entry_id = Column(Integer, primary_key=True, index=True)
monitor_id = Column(Integer, ForeignKey('iot_monitors.id'))
timestamp = Column(DateTime)
# class IotEntity(Base):
# __tablename__ = "iot_entities"
# id = Column(Integer, primary_key=True, index=True)
# bluetooth_mac = Column(String(512))
# description = Column(String(512))
# open_request = Column(Boolean, default=False)
# time_seconds = Column(Integer, default=10)
# authorized_users = relationship("User", secondary= 'user_iot_link')
# class UserAuthToIoTDev(Base):
# __tablename__ = "user_iot_link"
# user_id = Column(Integer, ForeignKey('user_accounts.id'), primary_key=True, index=True)
# iot_entity_id = Column(Integer, ForeignKey('iot_entities.id'), primary_key=True, index=True)
# class DoorAccessLog(Base):
# __tablename__ = "door_access_log"
# entry_id = Column(Integer, primary_key=True, index=True)
# user_id = Column(Integer, ForeignKey('user_accounts.id'))
# iot_dev_bluetooth_mac = Column(Integer, ForeignKey('iot_entities.id'))
# timestamp = Column(DateTime)
# class RoomSensorData(Base):
# __tablename__ = "room_sensor_data"
# # Data is now not related to a room. We should have a construct for rooms
# reading_id = Column(Integer, primary_key=True, index=True)
# humidity = Column(Integer)
# people = Column(Integer)
# temperature = Column(Integer)
# smoke_sensor_reading = Column(Integer)
# timestamp = Column(DateTime)
# TODO: Add table to store active sessions. May periodically clear.

View File

@ -1,6 +1,3 @@
# March 2022
# Hesham T. Banafa <hishaminv@gmail.com>
from typing import Any, List, Optional
from pydantic import BaseModel
@ -8,6 +5,8 @@ from datetime import datetime
class IotEntityBase(BaseModel):
# Common attributes for all Iot devices
room_id: int # Used to link with sensors and other devices
bluetooth_mac: str
description: str
@ -15,136 +14,180 @@ class UserBase(BaseModel):
email: str
username: str
class IotEntityCreate(IotEntityBase):
pass
class UserCreate(UserBase):
# For when creating users (needs password once to store)
password: str
class IotEntity(IotEntityBase):
id: int
description: str
bluetooth_mac: str
#authorized_users: List[User] = []
open_request: bool # Flag to open
time_seconds: int
force_close: bool
acces_list_counter: int
state: bool
class IotDoor(IotEntityBase):
id: int # Door ID
open_request: bool # Standing flag to open
time_seconds: int # Used when open request
force_close: bool # Force a close mid timed open request
is_open: bool
accesslist_counter: int
class Config:
orm_mode = True
class IotBluetoothMac(BaseModel):
bluetooth_mac : str
class Monitor(IotEntityBase):
# bluetooth_mac: str
# description: str
id: int
bluetooth_mac: str
description: str
humidity: int
people: int
temperature: int
smoke_sensor_reading: int
class Config:
orm_mode = True
class MonitorUpdateReadings(BaseModel):
humidity : int
people : int
temperature : int
smoke_sensor_reading : int
token: str # Contains mac
class User(UserBase):
id: int
is_active: bool
authorized_devices: List[IotEntity] = []
class Config:
orm_mode = True
class Token(BaseModel):
access_token : str
token_type : str
class TokenData(BaseModel):
username : str
# Token can conatin information. But we are already recording this in a database
# for scalability.
class UserAllowForIotEntityRequestByID(BaseModel):
user_id: int
iot_entity_id: int
class UserAllowForIotEntityRequestByUsername(BaseModel):
username: str
description: str
class UserUpdatePassword(BaseModel):
password: str
class OpenDoorRequestBase(BaseModel):
username: str
bluetooth_mac: str
class OpenDoorRequestTime(OpenDoorRequestBase):
time_seconds: int
class CloseDoorRequest(OpenDoorRequestBase):
pass
# Device sends this periodcally
class IotDoorPollingRequest(BaseModel):
bluetooth_mac : str
state: int
token : str
bluetooth_mac: str
token: str
class IotDoorPollingResponse(BaseModel):
open_command : bool
acces_list_counter : int
time_seconds : int
force_close: bool
state: bool
class IotMonitor(IotEntityBase):
# Info of room monitor and current readings
id: int
room_id: int
people: int
temp_c: int
smoke: int
humidity: int
class Config:
orm_mode = True
class IotMonitorRoomInfo(BaseModel):
humidity : int
people : int
temperature : int
smoke_sensor_reading : int
smoke : int
token: str
# class Config:
# orm_mode = True
class IotMonitorRoomInfoTimestamped(IotMonitorRoomInfo):
time: datetime
class IotDoorCreate(IotEntityBase):
room_id: int
class IotMonitorCreate(IotEntityBase):
room_id: int
class Room(BaseModel):
id: int
building_name: str
building_number: int
class Config:
orm_mode = True
class RoomCreate(BaseModel):
building_name: str
building_number: int
class IotBluetoothMac(BaseModel):
bluetooth_mac : str
class User(UserBase):
id: int
is_active: bool
authorized_rooms: List[Room] = [] # TODO: Change to auth rooms not devs
class Config:
orm_mode = True
class Token(BaseModel):
access_token: str
token_type: str
class UserTokenData(BaseModel):
username: str
class IotDeviceTokenData(BaseModel):
bluetooth_mac: str
class DoorAccessLog(BaseModel):
user_id: int
iot_id: str
command: str
room_id: int
timestamp: datetime
class Config:
orm_mode = True
#token: str
class AccessLogRequest(BaseModel):
iot_id : int
class UserAccessLogRequestUsername(BaseModel):
username : str
class UserAccessLogRequestEmail(BaseModel):
email : str
class UserAccessLogRequestID(BaseModel):
id : int
class RoomOverview(IotEntity):
class IotMonitorRoomEntry(BaseModel):
humidity : int
people : int
temperature : int
smoke_sensor_reading : int
smoke: int
token: str
class Config:
orm_mode = True
class AllowRoomAccessRequestID(BaseModel):
user_id: int
room_id: int
class AllowRoomAccessRequestName(BaseModel):
username: str
description: int
class UserRoomAccessLogRequest(BaseModel):
username: str
class RoomAccessLogRequest(BaseModel):
room_id: int
class RoomAccessLogRequestUserID(BaseModel):
room_id: int
user_id: int
class RoomAccessLogRequestUserUsername(BaseModel):
username: str
room_id: int
class OpenRoomRequest(BaseModel):
user_id: int
room_id: int
time_seconds: int
# class UserAllowForIotEntityRequestByID(BaseModel):
# user_id: int
# iot_entity_id: int
# class UserAllowForIotEntityRequestByUsername(BaseModel):
# username: str
# description: str
# class OpenDoorRequestBase(BaseModel):
# username: str
# bluetooth_mac: str
# class OpenDoorRequestTime(OpenDoorRequestBase):
# time_seconds: int
# # Device sends this periodcally
# class IotDoorPollingRequest(BaseModel):
# bluetooth_mac : str
# token : str
# class Config:
# orm_mode = True
# class IotDoorPollingResponse(BaseModel):
# open_command : bool
# acces_list_counter : int
# time_seconds : int
# class IotMonitorRoomInfo(BaseModel):
# humidity : int
# people : int
# temperature : int
# smoke_sensor_reading : int
# token: str
# class Config:
# orm_mode = True
# class IotMonitorRoomInfoTimestamped(IotMonitorRoomInfo):
# time: datetime
# class Config:
# orm_mode = True
# class DoorAccessLog(BaseModel):
# user_id: int
# door_bluetooth_mac: str
# time: datetime
# class Config:
# orm_mode = True
# class AccessLogRequest(BaseModel):
# bluetooth_mac : str
# class UserAccessLogRequestUsername(BaseModel):
# username : str
# class UserAccessLogRequestEmail(BaseModel):
# email : str
# class UserAccessLogRequestID(BaseModel):
# id : int

View File

@ -1,4 +0,0 @@
#!/bin/bash
source ../../venv/bin/activate
pytest

View File

@ -1,92 +0,0 @@
from sys import path
import random
import string
from fastapi.testclient import TestClient
from requests import Response
from ..main import app
from ..schemas import UserCreate
MAX_ASCII = 255
RAND_CHAR_SET = string.ascii_letters
client = TestClient(app)
def gen_rand_str(size: int) -> str:
return ''.join(random.choice(RAND_CHAR_SET) for x in range(size))
def gen_new_user_dict() -> UserCreate:
noune = gen_rand_str(16)
new_user = UserCreate(email=f"testuser{noune}@mail.none",
username=f"testuser{noune}",
password=noune)
return new_user
def get_user_json(user: UserCreate) -> dict:
if type(user) != UserCreate: assert False
new_user_json = {
'email' : user.email,
'username': user.username,
'password': user.password
}
return new_user_json
def post_request(response: Response):
print(response.text)
print(response.reason)
test_user : UserCreate = gen_new_user_dict()
common_headres = {
'accept': 'application/json',
'Content-Type': 'application/json'
}
def test_create_user():
response = client.request("POST", "/users/reg",
json=get_user_json(test_user),
headers=common_headres)
assert response.status_code == 200
post_request(response)
def test_create_user_duplicate_fields():
# Assumed that this test runs after test_create_user()
response = client.request("POST", "/users/reg",
json=get_user_json(test_user),
headers=common_headres)
assert response.status_code == 400
post_request(response)
def test_obtain_user_token():
headers = {
'accept': 'application/json',
'Content-type': 'application/x-www-form-urlencoded'
}
data = f"grant_type=&username={test_user.username}&password={test_user.password}&scope=&client_id=&client_secret="
response = client.request("POST", "/users/tkn", headers=headers, data=data)
# if response.status_code == 200 and 'application/json' in response.headers.get('Content-Type',''):
# print(response.json())
assert response.status_code == 200
post_request(response)
def test_reject_false_creds():
headers = {
'accept': 'application/json',
'Content-type': 'application/x-www-form-urlencoded'
}
data = f"grant_type=&username={test_user.username}flaty&password=badpass{test_user.password}&scope=&client_id=&client_secret="
response = client.request("POST", "/users/tkn", headers=headers, data=data)
assert response.status_code == 401
post_request(response)
def test_create_iot_entity():
pass

View File

@ -1,40 +0,0 @@
# EE495
# Hesham T. Banafa
# Jun 11th, 2022
from time import sleep
import requests
def poll(poll_url: str, data: dict, headers: dict) -> dict:
res : requests.Response = \
requests.post(poll_url, json=data, headers=headers)
#print('sent ', data)
print(res.text, res, res.reason)
if res.status_code != 200: return None
return res.json()
def emulate(poll_url, token_in: str):
mac = "94:b9:7e:fb:57:1a"
polling_interval_secons = 1
polling_headers = {
'accept' : 'application/json',
'Content-Type': 'application/json'
}
stop = False
state = False
while (not stop):
sleep(polling_interval_secons)
data = {
'bluetooth_mac': mac,
'state': state,
'token': token_in
}
data_dict = poll(poll_url, data, polling_headers)
if not data_dict: continue
if data_dict['open_command']: state = True
if __name__ == '__main__':
emulate("https://ibs.cronos.typedef.cf:4040/iotdevice/door/status",
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJibHVldG9vdGhfbWFjIjoiOTQ6Yjk6N2U6ZmI6NTc6MWEifQ.oRbL0U70g8HGkKIOnwkesDiB40VWTPmwIWiysvP-hXA")

View File

@ -1,31 +0,0 @@
# This is templte to use for python venv applications
# from https://broplanner.com/wp-content/webpc-passthru.php?src=https://broplanner.com/wp-content/uploads/2022/01/Screenshot-2022-01-25-224223-1536x237.png&nocache=1
[Unit]
After = network.target
[Service]
User=ibs
Group=ibs
WorkingDirectory=/srv/ibs/ibs
ExecStart=/srv/ibs/ibs/run-tls
Restart=on-failure
RestartSec=15
# Security
ReadWritePaths=/srv/ibs/ibs
PrivateDevices=yes
PrivateMounts=yes
PrivateTmp=yes
PrivateUsers=yes
ProtectClock=yes
ProtectControlGroups=yes
ProtectHome=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectProc=yes
ProtectHostname=yes
[Install]
WantedBy=multi-user.target

View File

@ -1,16 +0,0 @@
# May 2022
# Hesham T. Banafa <hishaminv@gmail.com>
from .database import SessionLocal
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
EMERG_TEMP = 50
EMERG_SMOKE = 1000
EMERG_OPEN_TIME_SEC = 500