Browse Source

auth

master
gsd 7 months ago
parent
commit
fcf459f9d7
  1. 2
      backend/config_parser.py
  2. 7
      backend/global_funcs.py
  3. 36
      backend/server.py
  4. 36
      frontend/ang_dvrip/src/app/app.component.html
  5. 24
      frontend/ang_dvrip/src/app/app.component.ts
  6. BIN
      frontend/ang_dvrip/src/assets/nonauth.webp

2
backend/config_parser.py

@ -368,6 +368,8 @@ class Config:
raw = load_config(config_name) if args == None or not args.err_check else {}
self.listen_address = raw.get("backend", {}).get("address", "0.0.0.0")
self.listen_port = int(raw.get("backend", {}).get("port", "8080"))
self.auth = raw.get("backend", {}).get("auth", {}).items()
self.recorders = []
i = 0
for raw_server in raw.get("recorders", []):

7
backend/global_funcs.py

@ -6,9 +6,12 @@ import uuid
import logging
def hexed(string:str):
return hashlib.md5(string.encode("utf8")).hexdigest()
def uuid_from_string(string:str):
hex_string = hashlib.md5(string.encode("utf8")).hexdigest()
return uuid.UUID(hex=hex_string)
return uuid.UUID(hex=hexed(string))
def app_dir():

36
backend/server.py

@ -1,20 +1,24 @@
from fastapi import FastAPI, Response, BackgroundTasks, Header
from fastapi import FastAPI, Response, BackgroundTasks, Header, Request
from fastapi.responses import StreamingResponse, FileResponse
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from fastapi.exceptions import HTTPException
import uvicorn
import traceback
import aiofiles
from config_parser import Config as ConfigParser
from config_parser import TranscodeStatus, TranscodeTools, Go2Rtc, NeedNVR
from global_funcs import create_logger
from global_funcs import create_logger, hexed
from nvr_core import NVR
from nvr_types import File
import os
import time
class Server:
app: FastAPI = FastAPI()
config: ConfigParser = ConfigParser()
go2rtc: Go2Rtc = Go2Rtc()
security = HTTPBasic()
API_BASE_REF = "/api/dvrip"
@ -22,6 +26,7 @@ class Server:
self.logger = create_logger(Server.__name__)
self.setup_events()
self.setup_routers()
self.setup_middleware()
def setup_events(self):
@self.app.on_event('startup')
@ -35,7 +40,34 @@ class Server:
self.logger.info(f"{self.config.recorders[i]} channels count: {self.config.recorders[i].channels}")
await self.go2rtc.start_go2rtc(self.config.recorders)
def setup_middleware(self):
if len(self.config.auth) != 0:
self.logger.info("auth is enabled")
@self.app.middleware("http")
async def auth_handler(request: Request, call_next):
try:
s = await self.security(request)
if s.username not in self.config.auth.mapping or hexed(s.password) != self.config.auth.mapping[s.username]:
raise HTTPException(status_code=401, headers={"WWW-Authenticate": "Basic"})
except HTTPException as e:
return Response(status_code=e.status_code, headers=e.headers)
return await call_next(request)
@self.app.get(self.API_BASE_REF + "/logout")
async def logout(request: Request):
request.scope.update(headers={"Authorization":"b"})
return Response(status_code=401)
else:
self.logger.warn("auth is disabled")
def setup_routers(self):
@self.app.get(self.API_BASE_REF + "/ping", status_code=200)
async def getPing():
return {"pong":time.time()}
@self.app.get(self.API_BASE_REF, status_code=200)
async def getRecorders(response: Response):
try:

36
frontend/ang_dvrip/src/app/app.component.html

@ -1,5 +1,17 @@
<ng-container>
<ng-container *ngIf="authed == 0">
<mat-spinner *ngIf="loading" style="margin:0 auto;" diameter="500"></mat-spinner>
<p style="text-align: center">Загрузка...</p>
</ng-container>
<ng-container *ngIf="authed == -1">
<div style="text-align: center">
<img src="assets/nonauth.webp" style="max-width: 50%">
<p>Не авторизован</p>
<button mat-button (click)="reload()">Обновить страницу</button>
</div>
</ng-container>
<ng-container *ngIf="authed == 1">
<mat-sidenav-container class="container">
<mat-sidenav #sidenav mode="over">
<div>
@ -10,6 +22,8 @@
<span>Закрыть</span>
</mat-toolbar>
<br>
<span>DVRIP Клиент <span style="color: darkgrey">{{version}}</span></span>
<br>
<mat-form-field *ngIf="availble_recorders.length>0">
<mat-label>Выбранный рекордер</mat-label>
<mat-select [(value)]="selected_recorder" (valueChange)="getChannels(selected_recorder)">
@ -26,7 +40,7 @@
</mat-form-field>
<p *ngIf="availble_channels.length==0">Нет доступных каналов</p>
<br>
<span>DVRIP Клиент <span style="color: darkgrey">{{version}}</span></span>
<button mat-button (click)="logout()">Выйти</button>
</div>
</mat-sidenav>
@ -51,21 +65,3 @@
</mat-sidenav-content>
</mat-sidenav-container>
</ng-container>
<!--<ng-container>
<mat-toolbar style="border-bottom: black 1px solid">
<span>DVRIP Клиент <span style="color: darkgrey">{{version}}</span></span>
<mat-spinner *ngIf="loading" [diameter]="50"></mat-spinner>
<span class="spacer"></span>
<ng-container *ngIf="!loading">
<span class="spacer"></span>
</ng-container>
</mat-toolbar>
<mat-toolbar *ngIf="!loading && availble_channels.length>0 && availble_recorders.length>0" style="border-bottom: black 1px solid">
</mat-toolbar>
</ng-container>
-->

24
frontend/ang_dvrip/src/app/app.component.ts

@ -16,9 +16,18 @@ export class AppComponent implements OnInit {
selected_channel:number = 0;
loading:boolean = true
version = version;
authed:number = 0;
ngOnInit(): void {
this.getRecorders();
this.getPing().subscribe(
(a:any) => {
this.authed = 1;
this.getRecorders();
},
(e:any) => {
this.authed = -1;
}
)
}
constructor(private api:ApiService,
@ -26,6 +35,10 @@ export class AppComponent implements OnInit {
private router:Router) {
}
getPing() {
return this.http.get("/api/dvrip/ping")
}
getRecorders() {
this.loading = true;
this.http.get("/api/dvrip", {}).subscribe((a:any) => {
@ -49,4 +62,13 @@ export class AppComponent implements OnInit {
goToRoot() {
this.router.navigate(["/"])
}
logout() {
this.http.get("api/dvrip/logout").subscribe();
this.reload();
}
reload() {
location.reload();
}
}

BIN
frontend/ang_dvrip/src/assets/nonauth.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Loading…
Cancel
Save