Limit exposed go2rtc api to bare minimum (#8762)

* only permit GET requests to go2rtc

* bare minimum go2rtc passthrough

* support frigate card

* expose go2rtc streams data only
This commit is contained in:
Blake Blackshear 2023-11-28 00:25:47 +00:00 committed by GitHub
parent 15644a2b0c
commit a490c375f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 20 deletions

View File

@ -164,19 +164,38 @@ http {
include proxy.conf; include proxy.conf;
} }
location /live/mse/ { # frigate lovelace card uses this path
proxy_pass http://go2rtc/; location /live/mse/api/ws {
limit_except GET {
deny all;
}
proxy_pass http://go2rtc/api/ws;
include proxy.conf; include proxy.conf;
} }
location /live/webrtc/ { location /live/webrtc/api/ws {
proxy_pass http://go2rtc/; limit_except GET {
deny all;
}
proxy_pass http://go2rtc/api/ws;
include proxy.conf; include proxy.conf;
} }
location ~* /api/go2rtc([/]?.*)$ { # pass through go2rtc player
proxy_pass http://go2rtc; location /live/webrtc/webrtc.html {
rewrite ^/api/go2rtc(.*)$ /api$1 break; limit_except GET {
deny all;
}
proxy_pass http://go2rtc/webrtc.html;
include proxy.conf;
}
# frontend uses this to fetch the version
location /api/go2rtc/api {
limit_except GET {
deny all;
}
proxy_pass http://go2rtc/api;
include proxy.conf; include proxy.conf;
} }

View File

@ -16,6 +16,7 @@ from urllib.parse import unquote
import cv2 import cv2
import numpy as np import numpy as np
import pytz import pytz
import requests
from flask import ( from flask import (
Blueprint, Blueprint,
Flask, Flask,
@ -1345,6 +1346,22 @@ def config_schema():
) )
@bp.route("/go2rtc/streams")
def go2rtc_streams():
r = requests.get("http://127.0.0.1:1984/api/streams")
if not r.ok:
logger.error("Failed to fetch streams from go2rtc")
return make_response(
jsonify({"success": False, "message": "Error fetching stream data"}),
500,
)
stream_data = r.json()
for data in stream_data.values():
for producer in data["producers"]:
producer["url"] = clean_camera_user_pass(producer["url"])
return jsonify(stream_data)
@bp.route("/version") @bp.route("/version")
def version(): def version():
return VERSION return VERSION

View File

@ -41,7 +41,7 @@ export default function System() {
const cameraNames = Object.keys(cameras || emptyObject); const cameraNames = Object.keys(cameras || emptyObject);
const processesNames = Object.keys(processes || emptyObject); const processesNames = Object.keys(processes || emptyObject);
const { data: go2rtc } = useSWR('go2rtc'); const { data: go2rtc } = useSWR('go2rtc/api');
const onHandleFfprobe = async (camera, e) => { const onHandleFfprobe = async (camera, e) => {
if (e) { if (e) {
@ -103,9 +103,9 @@ export default function System() {
className="text-blue-500 hover:underline" className="text-blue-500 hover:underline"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="/live/webrtc/" href="/api/go2rtc/streams"
> >
dashboard streams info
</Link> </Link>
</span> </span>
)} )}
@ -302,16 +302,16 @@ export default function System() {
<Tr> <Tr>
<Th>GPU %</Th> <Th>GPU %</Th>
<Th>Memory %</Th> <Th>Memory %</Th>
{'dec' in gpu_usages[gpu] && (<Th>Decoder %</Th>)} {'dec' in gpu_usages[gpu] && <Th>Decoder %</Th>}
{'enc' in gpu_usages[gpu] && (<Th>Encoder %</Th>)} {'enc' in gpu_usages[gpu] && <Th>Encoder %</Th>}
</Tr> </Tr>
</Thead> </Thead>
<Tbody> <Tbody>
<Tr> <Tr>
<Td>{gpu_usages[gpu]['gpu']}</Td> <Td>{gpu_usages[gpu]['gpu']}</Td>
<Td>{gpu_usages[gpu]['mem']}</Td> <Td>{gpu_usages[gpu]['mem']}</Td>
{'dec' in gpu_usages[gpu] && (<Td>{gpu_usages[gpu]['dec']}</Td>)} {'dec' in gpu_usages[gpu] && <Td>{gpu_usages[gpu]['dec']}</Td>}
{'enc' in gpu_usages[gpu] && (<Td>{gpu_usages[gpu]['enc']}</Td>)} {'enc' in gpu_usages[gpu] && <Td>{gpu_usages[gpu]['enc']}</Td>}
</Tr> </Tr>
</Tbody> </Tbody>
</Table> </Table>
@ -350,14 +350,14 @@ export default function System() {
<Link href={`/cameras/${camera}`}>{camera.replaceAll('_', ' ')}</Link> <Link href={`/cameras/${camera}`}>{camera.replaceAll('_', ' ')}</Link>
<div className="flex"> <div className="flex">
{config.cameras[camera]['webui_url'] && ( {config.cameras[camera]['webui_url'] && (
<Button <Button href={config.cameras[camera]['webui_url']} target="_blank">
href={config.cameras[camera]['webui_url']} Web UI
target="_blank" <WebUI className="ml-1 h-4 w-4" fill="white" stroke="white" />
>
Web UI<WebUI className="ml-1 h-4 w-4" fill="white" stroke="white" />
</Button> </Button>
)} )}
<Button className="ml-2" onClick={(e) => onHandleFfprobe(camera, e)}>ffprobe</Button> <Button className="ml-2" onClick={(e) => onHandleFfprobe(camera, e)}>
ffprobe
</Button>
</div> </div>
</div> </div>
<div className="p-2"> <div className="p-2">