Reimplement UI injection (#236)
This commit is contained in:
committed by
GitHub
parent
fdc93e2719
commit
fd3643685d
70
custom_components/auth_oidc/endpoints/device_sse.py
Normal file
70
custom_components/auth_oidc/endpoints/device_sse.py
Normal file
@@ -0,0 +1,70 @@
|
||||
"""SSE handler for OIDC device authentication."""
|
||||
|
||||
import asyncio
|
||||
from aiohttp import web
|
||||
from homeassistant.components.http import HomeAssistantView
|
||||
from ..provider import OpenIDAuthProvider
|
||||
from ..tools.helpers import get_valid_state_id
|
||||
|
||||
PATH = "/auth/oidc/device-sse"
|
||||
|
||||
|
||||
class OIDCDeviceSSE(HomeAssistantView):
|
||||
"""OIDC Plugin SSE Handler."""
|
||||
|
||||
requires_auth = False
|
||||
url = PATH
|
||||
name = "auth:oidc:device-sse"
|
||||
|
||||
def __init__(self, oidc_provider: OpenIDAuthProvider) -> None:
|
||||
self.oidc_provider = oidc_provider
|
||||
|
||||
async def get(self, req: web.Request) -> web.Response:
|
||||
"""Check for mobile sign-in completion with short server-side polling."""
|
||||
state_id = await get_valid_state_id(req, self.oidc_provider)
|
||||
if not state_id:
|
||||
raise web.HTTPBadRequest(text="Missing session cookie")
|
||||
|
||||
timeout_seconds = 300
|
||||
started_at = asyncio.get_running_loop().time()
|
||||
|
||||
response = web.StreamResponse(
|
||||
status=200,
|
||||
headers={
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Connection": "keep-alive",
|
||||
},
|
||||
)
|
||||
await response.prepare(req)
|
||||
|
||||
try:
|
||||
while True:
|
||||
if (
|
||||
await self.oidc_provider.async_get_redirect_uri_for_state(state_id)
|
||||
is None
|
||||
):
|
||||
await response.write(b"event: expired\ndata: false\n\n")
|
||||
break
|
||||
|
||||
ready = await self.oidc_provider.async_is_state_ready(state_id)
|
||||
if ready:
|
||||
await response.write(b"event: ready\ndata: true\n\n")
|
||||
break
|
||||
|
||||
if asyncio.get_running_loop().time() - started_at >= timeout_seconds:
|
||||
await response.write(b"event: timeout\ndata: false\n\n")
|
||||
break
|
||||
|
||||
await response.write(b"event: waiting\ndata: false\n\n")
|
||||
await asyncio.sleep(0.5)
|
||||
except (ConnectionResetError, RuntimeError):
|
||||
# Client disconnected while listening for state changes.
|
||||
pass
|
||||
finally:
|
||||
try:
|
||||
await response.write_eof()
|
||||
except ConnectionResetError:
|
||||
pass
|
||||
|
||||
return response
|
||||
Reference in New Issue
Block a user