Compare commits

...

55 Commits

Author SHA1 Message Date
059d45b117
patch to require admin APIKey on admin endpoints
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-16 02:19:41 +03:00
39b7d25a57 WIP: enroll device
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-16 02:18:59 +03:00
fc9f1c5c05 file headers
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-16 02:18:43 +03:00
7f90e104d3 sql_app: emergency open time
For some reason, having 3600 set as the
	time for door to stay open in a case of
	fire does not open the door at all.
	Prob a limtiation in door implementation

Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-12 21:53:37 +03:00
2c3206fc06
verbose at emerg
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-12 19:56:00 +03:00
b704aee0fc
init_secrets: change file mode when making .env file
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-12 19:34:31 +03:00
99ac2acc0d sql_app: open door on emergency
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-12 19:30:14 +03:00
6a771c589b sql_app: init_db: do not recreate sensor_data and access_log
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-12 12:57:38 +03:00
2c60e14260 sql_app: enforce strict file permissions for .env
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-12 12:52:04 +03:00
21aef6ec6c sql_app: update monitor column
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-11 20:28:39 +03:00
20dfa6dcc4 sql_app: Respond to emergency events record db entry
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-11 18:05:52 +03:00
e1a7c4023b
sql_app: tools: Iot door emulator for testing in absence of door
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-11 17:39:18 +03:00
50a7d8251c
print monitor requests
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-10 21:45:44 +03:00
6ae5b811f4
sql_app: correct monitor mac
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-10 19:11:12 +03:00
21d72f17b2 sql_app: fixed error while setting door state
Old code was taking state from device itself,
	meaning it never changes. Now it is set from
	the incoming request.

Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-09 22:41:07 +03:00
dcd2ff5b89 sql_app: Split doors and monitors
A alot of interface and database boiler plate

Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-09 21:52:42 +03:00
a316374da6 sql_app: remove api key from some functions for testing
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-09 18:21:02 +03:00
a034f17a63 Merge branch 'master' of https://github.com/HeshamTB/ibs
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-08 18:30:09 +03:00
40030c91a1 sql_app: systemd unit file
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-08 18:27:25 +03:00
cdf3a6dfb1 sql_app: implement user activate/deactivate
Previous code now rejects all user authenticated
	endpoints. Even /users/me.

Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-08 14:37:26 +03:00
35f0e8abb4 sql_app: Use ORM relations for access log requests
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-08 14:31:47 +03:00
6942d4881d sql_app: missing attribute force_close
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-08 14:31:08 +03:00
6a3d9d9e95 sql_app: Use more relations in database
Instead of using manual db lookup for access log,
	use device.access_list to fetch the data from
	access_log table. This does the SQL query underneath.

	To do so, instructions from SQLAlchemey were followed
	to to many-to-one relations for users and devices,
	respectevly.

Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-08 14:19:27 +03:00
ae5f4e040d sql_app: init_db: added connections and open/close commands
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-08 14:18:43 +03:00
0a4a560ac5 sql_app: fixed errors in room access log endpoints
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-08 13:26:41 +03:00
fdb5be583b sql_app: data: Endpoint to fetch sensor data
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-08 13:01:47 +03:00
c2048d8dba sql_app: User can change password
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-08 12:00:12 +03:00
84db98b6f6
sql_app: Remove hard coded HTTPException codes
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 21:40:01 +03:00
2811b8a5ef
sql_app: update TODO
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 21:29:08 +03:00
b394bd9f2b
hot fix
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 21:14:25 +03:00
4fdd7c231c
sql_app: door: check if valid token on file requests
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 21:09:38 +03:00
b790c6657a
sql_app: door: send actual access_list_counter instead of 0
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 20:15:24 +03:00
0125f3e5fc
sql_app: Add correct door mac
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 20:01:43 +03:00
6f45fc95aa sql_app: remove record_user_connection() due to bug. fix later
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 19:17:32 +03:00
3bcb333df6
sql_app: Added state to Iot Door
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 18:58:23 +03:00
2eed2db77e sql_app: data: collect user connection times
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 16:11:39 +03:00
d9f3a9da4e
sql_app: Introduce force_close flag for Iot Door
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 15:48:28 +03:00
4789b2778c
sql_app: init_db: Added a link (allowance)
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 15:02:33 +03:00
6850823ae8
sql_app: init_db: Add total of 3 users
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 14:54:04 +03:00
2d7ba032a8
encryption: scrapped attempt for BT encryption on esp32
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 14:43:43 +03:00
e45e335d50 sql_app: added init db
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 14:41:48 +03:00
311058f09b sql_app: init_secrets: add new variable for first user password
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 14:41:06 +03:00
01e6c990f7
sql_app: Reorder
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 12:58:56 +03:00
bf14c97cb6
sql_app: main: User access list now includes room sensor data
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-07 12:56:10 +03:00
317b3825c3
helper scripts
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-06 20:07:26 +03:00
7c94abebe5
tests: refactor and added user token tests
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-06 20:03:15 +03:00
1006baa212
sql_app: tests: Add basic unit tests (User Create)
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-06 19:26:48 +03:00
868c97fe73
sql_apps: tests: Add reqs
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-06 18:24:32 +03:00
89f0bc354c sql_app: Added new endpoints to fetch iot dev access list info
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-06 18:17:03 +03:00
80f6c629d4 sql_app: create user now stores new api token
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-06 18:16:06 +03:00
2b4d3bf7f5 sql_app: Implemented access list counter:
A counter is associated with every
	Iot Device. The counter is always increment
	when a user is allowed or disallowed to use
	the device, hence, ensuring coherency.
	It is also now exposed in the
	IotDoorPollingRequest schema, enabling the
	Iot Device to fetch the new access list.

Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-06 16:38:35 +03:00
3a6a1ccefd sql_app: db: Changed incorrect variable name
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-06 16:33:02 +03:00
244b7c6b91
sql_app: db: Fixed column copy warning.
A warning was raised whenever the user<->device
	relation was accessed. The assumption is that
	now the queries perform faster, having fixed
	this issue.

Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-05 17:10:35 +03:00
232ff82c46 sql_app: save last issued token in user record
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-05 16:25:20 +03:00
59757ae269
sql_app: TODO
Signed-off-by: HeshamTB <hishaminv@gmail.com>
2022-06-05 14:02:50 +03:00
25 changed files with 1263 additions and 182 deletions

1
.gitignore vendored
View File

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

View File

@ -0,0 +1,130 @@
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

33
encryption/encryption.c Normal file
View File

@ -0,0 +1,33 @@
/*
* 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)
{
}

24
encryption/encryption.h Normal file
View File

@ -0,0 +1,24 @@
/*
* 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,9 +1,12 @@
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
@ -17,22 +20,31 @@ 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,4 +1,14 @@
#!/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

4
run-tls-reload Executable file
View File

@ -0,0 +1,4 @@
#!/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,13 +1,45 @@
- [ ] Redesign database
- [ ] Define emrgancy triggers (manual and automatic)
- [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)
- [ ] Expose temporary control in case of emergancy
- Triggers
- Acccess
- Resolve (revoke access)
- [ ] Temporal door open commands (Needs door state to operate efficiatly)
- Open for 1H
- Open to 1:30PM
- Set schedual
- [X] Temporal door open commands (Needs door state to operate efficiatly)
- [X] Open for 1H
- [ ] Open to 1:30PM
- [ ] Set schedual
- [X] Issue door open command
- [X] Make functions to gen a IotEntity token
- [ ] Save prefix of token to allow/revoke 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

View File

@ -1,3 +1,5 @@
# May 2022
# Hesham T. Banafa <hishaminv@gmail.com>
from typing import Optional
from decouple import config
@ -55,4 +57,14 @@ def valid_iot_token(token : str, db: Session):
mac_signed = payload.get("bluetooth_mac")
device = crud.get_iot_entity_by_bluetooth_mac(db, mac_signed)
return device
return device
def valid_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

View File

@ -1,10 +1,15 @@
# 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)
@ -12,49 +17,71 @@ from datetime import datetime
# - Any open request (link to user)
# - Any polling from IotEntity? Maybe to much data
def get_user(db: Session, user_id: int):
def get_user(db: Session, user_id: int) -> models.User:
return db.query(models.User).get(user_id)
def get_iot_entity(db: Session, id: int):
def get_iot_entity(db: Session, id: int) -> models.IotEntity:
return db.query(models.IotEntity).get(id)
def get_iot_entity_by_description(db: Session, description: str):
return db.query(models.IotEntity).filter(models.IotEntity.description == description).first()
def get_iot_entity_by_bluetooth_mac(db: Session, bluetooth_mac: str):
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_user_by_email(db: Session, email: str):
def get_user_by_email(db: Session, email: str) -> models.User:
return db.query(models.User).filter(models.User.email == email).first()
def get_user_by_username(db: Session, username: str):
def get_user_by_username(db: Session, username: str) -> models.User:
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, bluetooth_mac : str):
return db.query(models.DoorAccessLog).filter(models.DoorAccessLog.iot_dev_bluetooth_mac == bluetooth_mac).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_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):
return db.query(models.RoomSensorData)[-1]
# 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 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,
@ -64,11 +91,44 @@ def create_iot_entity(db: Session, iot_entity: schemas.IotEntityCreate):
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)
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_entity_id == iot_dev_id).first()
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_entity_id=iot_dev_id)
new_link = models.UserAuthToIoTDev(user_id=user_id,
iot_id=iot_dev_id,
timestamp=datetime.now())
db.add(new_link)
db.commit()
db.refresh(new_link)
@ -76,7 +136,10 @@ def create_user_link_to_iot(db: Session, user_id: int, iot_dev_id: int):
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_entity_id == iot_dev_id).first()
link = (db.query(models.UserAuthToIoTDev)
.filter(models.UserAuthToIoTDev.user_id == user_id)
.filter(models.UserAuthToIoTDev.iot_id == iot_dev_id)
.first())
if not link: return True
db.delete(link)
db.flush()
@ -95,6 +158,38 @@ def set_open_door_request(db: Session, iot_entity_id: int, time_seconds : int):
db.refresh(device)
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)
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)
@ -106,18 +201,65 @@ def clear_open_door_request(db: Session, iot_entity_id: int):
def record_door_access_log(db: Session, entry: schemas.DoorAccessLog):
db_item = models.DoorAccessLog(user_id=entry.user_id,
iot_dev_bluetooth_mac=entry.door_bluetooth_mac,
timestamp=entry.time)
iot_id=entry.iot_id,
command=entry.command,
timestamp=entry.timestamp)
db.add(db_item)
db.commit()
db.refresh(db_item)
def record_room_sensor_data(db: Session, entry: schemas.IotMonitorRoomInfo):
def record_room_sensor_data(db: Session, entry: schemas.MonitorUpdateReadings,
monitor :models.Monitors):
db_item = models.RoomSensorData(humidity=entry.humidity,
people=entry.people,
temperature=entry.temperature,
smoke_sensor_reading=entry.smoke_sensor_reading,
timestamp=datetime.now())
timestamp=datetime.now(),
monitor_id=monitor.id)
db.add(db_item)
db.commit()
db.refresh(db_item)
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)
db.commit()
db.refresh(monitor)
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)

View File

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

View File

@ -1,3 +1,6 @@
# 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

45
sql_app/enroll_door.py Normal file
View File

@ -0,0 +1,45 @@
# 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)

18
sql_app/file_permissios.py Executable file
View File

@ -0,0 +1,18 @@
#!/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)

137
sql_app/init_db.py Normal file
View File

@ -0,0 +1,137 @@
# 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,3 +4,17 @@ 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

View File

@ -1,10 +1,15 @@
# 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
from . import crud, models, schemas, auth_helper, init_db
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
@ -15,13 +20,10 @@ 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_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
def get_current_user(token: str = Depends(oauth), db: Session = Depends(get_db)):
credentials_exception = HTTPException(
@ -64,135 +66,29 @@ def get_current_iot_device(current_device: schemas.IotBluetoothMac = Depends(),
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 already registered")
raise HTTPException(status_code=400, detail="Email/Username already registered")
db_user = crud.get_user_by_username(db, username=user.username)
if db_user:
raise HTTPException(status_code=400, detail="Username already registerd")
return crud.create_user(db=db, user=user)
raise HTTPException(status_code=400, detail="Email/Username already registered")
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
@app.get("/users/me/", response_model=schemas.User, tags=['Users'])
def get_user_details(current_user: schemas.User = Depends(get_current_active_user)):
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())
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/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
# 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.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=404, detail="User not found")
return db_user
@app.post("/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_code=404, detail="User not found")
iot_entity = crud.get_iot_entity(db, request.iot_entity_id)
if not iot_entity:
raise HTTPException(status_code=404, 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_code=500, detail="Could not complete operation")
return
@app.post("/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_code=404, detail="User not found")
iot_entity = crud.get_iot_entity(db, request.iot_entity_id)
if not iot_entity:
raise HTTPException(status_code=404, 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_code=500, detail="Could not complete operation")
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)):
user = crud.get_user_by_username(db, request.username)
if not user:
raise HTTPException(status_code=404, detail="User not found")
iot_entity = crud.get_iot_entity_by_description(db, request.description)
if not iot_entity:
raise HTTPException(status_code=404, detail="Iot Entity not found")
res = crud.create_user_link_to_iot(db, user.id, iot_entity.id)
if not res:
raise HTTPException(status_code=500, detail="Could not complete operation")
return
@app.post("/admin/users/{user_id}/deactiveate", tags=['Admin'])
def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
return
@app.post("/admin/users/{user_id}/activeate", tags=['Admin'])
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/iotdevice/accesslog/", tags=['Admin'])
def get_access_log_for_door(request : schemas.AccessLogRequest,
db : Session = Depends(get_db)):
device = crud.get_iot_entity_by_bluetooth_mac(db, request.bluetooth_mac)
if not device: raise HTTPException(status_code=404, detail="Iot Entity not found")
return crud.get_access_log_for_door_by_door_mac(db, request.bluetooth_mac)
@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_code=404, detail="User not found")
return crud.get_access_log_for_user_by_id(db, user.id)
@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_code=404, detail="User not found")
return crud.get_access_log_for_user_by_id(db, user.id)
@app.get("/users/acesslist/", response_model=List[schemas.IotEntity], 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)
return user.authorized_devices
@app.get("/admin/roominfo/now/", tags=['Admin'])
def get_room_data(db: Session = Depends(get_db)):
return crud.get_room_data_now(db)
@app.post("/users/open", tags=['Users'])
def issue_open_door_command(command: schemas.OpenDoorRequestTime,
db: Session = Depends(get_db),
@ -207,12 +103,70 @@ def issue_open_door_command(command: schemas.OpenDoorRequestTime,
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,
door_bluetooth_mac=command.bluetooth_mac,
time=datetime.now())
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)
return
@app.post("/users/tkn", response_model=schemas.Token, tags=['Users'])
@app.post("/tkn", response_model=schemas.Token, tags=['Users'])
def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)):
@ -227,14 +181,201 @@ 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,
db: Session = Depends(get_db)):
device: schemas.IotEntity = auth_helper.valid_iot_token(request.token, db)
device: models.IotEntity = auth_helper.valid_iot_token(request.token, db)
if not device:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
@ -242,19 +383,71 @@ def polling_method_for_iot_entity(request: schemas.IotDoorPollingRequest,
response : schemas.IotDoorPollingResponse = schemas.IotDoorPollingResponse(
open_command=device.open_request,
acces_list_counter=0,
time_seconds=device.time_seconds)
acces_list_counter=device.acces_list_counter,
time_seconds=device.time_seconds,
force_close=device.force_close,
state=device.state)
# 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
@app.post("/iotdevice/monitor/status", tags=['Iot'])
def polling_method_for_room_monitor(request: schemas.IotMonitorRoomInfo,
def polling_method_for_room_monitor(request: schemas.MonitorUpdateReadings,
db: Session = Depends(get_db)):
device : schemas.IotEntity = auth_helper.valid_iot_token(request.token, db)
device : models.Monitors = auth_helper.valid_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)
return request
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)
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,3 +1,6 @@
# March 2022
# Hesham T. Banafa <hishaminv@gmail.com>
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, DateTime
from sqlalchemy.orm import relationship
@ -13,43 +16,87 @@ class User(Base):
hashed_password = Column(String, nullable=False)
passwd_salt = Column(String, nullable=False)
is_active = Column(Boolean, default=True, nullable=False)
authorized_devices = relationship("IotEntity", secondary= 'user_iot_link')
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"
id = Column(Integer, primary_key=True, index=True)
bluetooth_mac = Column(String(512))
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)
authorized_users = relationship("User", secondary= 'user_iot_link')
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
class Monitors(Base):
__tablename__ = "monitors"
id = Column(Integer, primary_key=True)
bluetooth_mac = Column(String(512), index=True, unique=True)
description = Column(String(512))
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")
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)
user_id = Column(Integer, ForeignKey("user_accounts.id"), primary_key=True)
iot_id = Column(Integer, ForeignKey("iot_entities.id"), primary_key=True)
timestamp = Column(DateTime)
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'))
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))
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)
monitor_id = Column(Integer, ForeignKey("monitors.id"), index=True)
monitor = relationship("Monitors", back_populates="sensor_history")
# TODO: Add table to store active sessions. May periodically clear.
class UserConnectionHistory(Base):
__tablename__ = "user_connection_history"
reading_id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey("user_accounts.id"), index=True)
timestamp = Column(DateTime)
# TODO: add ip
class EmergancyNotice(Base):
__tablename__ = "emergency_notice"
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)
timestamp = Column(DateTime)
# TODO: Add table to store active sessions. May periodically clear.

View File

@ -1,3 +1,6 @@
# March 2022
# Hesham T. Banafa <hishaminv@gmail.com>
from typing import Any, List, Optional
from pydantic import BaseModel
@ -26,12 +29,35 @@ class IotEntity(IotEntityBase):
#authorized_users: List[User] = []
open_request: bool # Flag to open
time_seconds: int
force_close: bool
acces_list_counter: int
state: bool
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
@ -58,6 +84,9 @@ class UserAllowForIotEntityRequestByUsername(BaseModel):
username: str
description: str
class UserUpdatePassword(BaseModel):
password: str
class OpenDoorRequestBase(BaseModel):
username: str
bluetooth_mac: str
@ -65,17 +94,20 @@ class OpenDoorRequestBase(BaseModel):
class OpenDoorRequestTime(OpenDoorRequestBase):
time_seconds: int
class CloseDoorRequest(OpenDoorRequestBase):
pass
# Device sends this periodcally
class IotDoorPollingRequest(BaseModel):
bluetooth_mac : str
state: int
token : str
class Config:
orm_mode = True
class IotDoorPollingResponse(BaseModel):
open_command : bool
acces_list_counter : int
time_seconds : int
force_close: bool
state: bool
class IotMonitorRoomInfo(BaseModel):
humidity : int
@ -83,8 +115,8 @@ class IotMonitorRoomInfo(BaseModel):
temperature : int
smoke_sensor_reading : int
token: str
class Config:
orm_mode = True
# class Config:
# orm_mode = True
class IotMonitorRoomInfoTimestamped(IotMonitorRoomInfo):
time: datetime
@ -93,13 +125,14 @@ class IotMonitorRoomInfoTimestamped(IotMonitorRoomInfo):
class DoorAccessLog(BaseModel):
user_id: int
door_bluetooth_mac: str
time: datetime
iot_id: str
command: str
timestamp: datetime
class Config:
orm_mode = True
class AccessLogRequest(BaseModel):
bluetooth_mac : str
iot_id : int
class UserAccessLogRequestUsername(BaseModel):
username : str
@ -109,3 +142,9 @@ class UserAccessLogRequestEmail(BaseModel):
class UserAccessLogRequestID(BaseModel):
id : int
class RoomOverview(IotEntity):
humidity : int
people : int
temperature : int
smoke_sensor_reading : int

View File

4
sql_app/tests/run-tests Executable file
View File

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

View File

@ -0,0 +1,92 @@
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

@ -0,0 +1,40 @@
# 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")

31
sql_app/tools/ibs.service Normal file
View File

@ -0,0 +1,31 @@
# 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

16
sql_app/utils.py Normal file
View File

@ -0,0 +1,16 @@
# 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