Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 5 additions & 14 deletions blinkpy/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@

import logging
import string
import json
from json import dumps
from asyncio import sleep
from urllib.parse import urlencode, urlparse, parse_qs
from bs4 import BeautifulSoup
from blinkpy.helpers.util import (
get_time,
Throttle,
local_storage_clip_url_template,
)
from blinkpy.helpers.oauth_parser import OAuthArgsParser
from blinkpy.helpers.constants import (
TIMEOUT,
DEFAULT_USER_AGENT,
Expand Down Expand Up @@ -812,18 +811,10 @@ async def oauth_get_signin_page(auth):

# Extract CSRF token from oauth-args script tag
try:
# Parse HTML
soup = BeautifulSoup(html, "html.parser")

# Find oauth-args script
oauth_script = soup.find(
"script", {"id": "oauth-args", "type": "application/json"}
)
if oauth_script and oauth_script.string:
oauth_data = json.loads(oauth_script.string)
csrf_token = oauth_data.get("csrf-token")
if csrf_token:
return csrf_token
parser = OAuthArgsParser()
parser.feed(html)
if parser.csrf_token:
return parser.csrf_token
except Exception as error:
_LOGGER.error("Failed to extract CSRF token: %s", error)

Expand Down
39 changes: 39 additions & 0 deletions blinkpy/helpers/oauth_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""HTML parser for OAuth CSRF token extraction."""

import json
from html.parser import HTMLParser


class OAuthArgsParser(HTMLParser):
"""HTML parser to extract CSRF token from oauth-args script tag."""

def __init__(self):
"""Initialize parser."""
super().__init__()
self.csrf_token = None
self._in_oauth_script = False

def handle_starttag(self, tag, attrs):
"""Handle opening tags."""
if tag == "script":
attrs_dict = dict(attrs)
if (
attrs_dict.get("id") == "oauth-args"
and attrs_dict.get("type") == "application/json"
):
self._in_oauth_script = True

def handle_data(self, data):
"""Handle tag content."""
if self._in_oauth_script:
try:
oauth_data = json.loads(data)
self.csrf_token = oauth_data.get("csrf-token")
except (json.JSONDecodeError, AttributeError):
pass
self._in_oauth_script = False

def handle_endtag(self, tag):
"""Handle closing tags."""
if tag == "script":
self._in_oauth_script = False
3 changes: 1 addition & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ requests>=2.24.0
python-slugify>=4.0.1
sortedcontainers~=2.4.0
aiohttp>=3.8.4
aiofiles>=23.1.0
beautifulsoup4>=4.12.0
aiofiles>=23.1.0
Loading