Implement the auth token invalidation button
This commit is contained in:
1 parent
98f166d94d
commit
38f880efc2
4 files changed
+66
-4
No files matched your search
@@ -256,6 +256,7 @@ class State(Enum):
|
|||||||
CHANNELS_FETCH = auto()
|
CHANNELS_FETCH = auto()
|
||||||
CHANNELS_CLEANUP = auto()
|
CHANNELS_CLEANUP = auto()
|
||||||
CHANNEL_SWITCH = auto()
|
CHANNEL_SWITCH = auto()
|
||||||
|
RESTART = auto()
|
||||||
EXIT = auto()
|
EXIT = auto()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ if sys.platform == "darwin":
|
|||||||
from translate import _
|
from translate import _
|
||||||
from cache import ImageCache
|
from cache import ImageCache
|
||||||
from exceptions import MinerException, ExitRequest
|
from exceptions import MinerException, ExitRequest
|
||||||
from utils import resource_path, set_root_icon, webopen, Game, _T
|
from utils import resource_path, set_root_icon, webopen, task_wrapper, Game, _T
|
||||||
from constants import (
|
from constants import (
|
||||||
MAX_INT,
|
MAX_INT,
|
||||||
SELF_PATH,
|
SELF_PATH,
|
||||||
@@ -61,6 +61,7 @@ if TYPE_CHECKING:
|
|||||||
from inventory import DropsCampaign, TimedDrop
|
from inventory import DropsCampaign, TimedDrop
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger("TwitchDrops")
|
||||||
TK_PADDING = Union[int, Tuple[int, int], Tuple[int, int, int], Tuple[int, int, int, int]]
|
TK_PADDING = Union[int, Tuple[int, int], Tuple[int, int, int], Tuple[int, int, int, int]]
|
||||||
DIGITS = ceil(log10(WS_TOPICS_LIMIT))
|
DIGITS = ceil(log10(WS_TOPICS_LIMIT))
|
||||||
|
|
||||||
@@ -2096,6 +2097,9 @@ class HelpTab:
|
|||||||
# use a frame to center the content within the tab
|
# use a frame to center the content within the tab
|
||||||
center_frame = ttk.Frame(master)
|
center_frame = ttk.Frame(master)
|
||||||
center_frame.grid(column=0, row=0)
|
center_frame.grid(column=0, row=0)
|
||||||
|
# use a frame for the bottom row specifically
|
||||||
|
bottom_frame = ttk.Frame(master)
|
||||||
|
bottom_frame.grid(column=0, row=1, sticky="nsew")
|
||||||
irow = 0
|
irow = 0
|
||||||
# About
|
# About
|
||||||
about = ttk.LabelFrame(center_frame, padding=(4, 0, 4, 4), text="About")
|
about = ttk.LabelFrame(center_frame, padding=(4, 0, 4, 4), text="About")
|
||||||
@@ -2160,6 +2164,41 @@ class HelpTab:
|
|||||||
getstarted, text=_("gui", "help", "getting_started_text"), wraplength=self.WIDTH
|
getstarted, text=_("gui", "help", "getting_started_text"), wraplength=self.WIDTH
|
||||||
).grid(sticky="nsew")
|
).grid(sticky="nsew")
|
||||||
|
|
||||||
|
# Invalidate button
|
||||||
|
invalidate_frame = ttk.Frame(bottom_frame)
|
||||||
|
bottom_frame.columnconfigure(0, weight=1) # center within the column
|
||||||
|
invalidate_frame.grid(column=0, row=0, sticky="nse")
|
||||||
|
ttk.Label(
|
||||||
|
invalidate_frame, text=_("gui", "help", "invalidate", "text")
|
||||||
|
).grid(column=0, row=0)
|
||||||
|
self._invalidate_button: ttk.Button = ttk.Button(
|
||||||
|
invalidate_frame,
|
||||||
|
text=_("gui", "help", "invalidate", "button"),
|
||||||
|
command=self.invalidate_token,
|
||||||
|
state="disabled",
|
||||||
|
)
|
||||||
|
self._invalidate_button.grid(column=1, row=0)
|
||||||
|
|
||||||
|
def invalidate_token(self) -> None:
|
||||||
|
# sync to async bridge
|
||||||
|
asyncio.create_task(task_wrapper(self._invalidate_token)())
|
||||||
|
|
||||||
|
async def _invalidate_token(self) -> None:
|
||||||
|
auth_state = await self._twitch.get_auth()
|
||||||
|
async with self._twitch.request(
|
||||||
|
"POST",
|
||||||
|
"https://id.twitch.tv/oauth2/revoke",
|
||||||
|
data={
|
||||||
|
"client_id": self._twitch._client_type.CLIENT_ID,
|
||||||
|
"token": auth_state.access_token,
|
||||||
|
}
|
||||||
|
) as response:
|
||||||
|
if response.status == 200:
|
||||||
|
auth_state.invalidate(delete_cookies=True)
|
||||||
|
else:
|
||||||
|
logger.error(f"Failed to invalidate the auth token: {response.status}")
|
||||||
|
self._twitch.change_state(State.RESTART)
|
||||||
|
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# GUI DEFINITION END / GUI MANAGER START #
|
# GUI DEFINITION END / GUI MANAGER START #
|
||||||
|
|||||||
@@ -197,12 +197,18 @@ class GUIHelpLinks(TypedDict):
|
|||||||
campaigns: str
|
campaigns: str
|
||||||
|
|
||||||
|
|
||||||
|
class GUIHelpInvalidate(TypedDict):
|
||||||
|
button: str
|
||||||
|
text: str
|
||||||
|
|
||||||
|
|
||||||
class GUIHelp(TypedDict):
|
class GUIHelp(TypedDict):
|
||||||
links: GUIHelpLinks
|
links: GUIHelpLinks
|
||||||
how_it_works: str
|
how_it_works: str
|
||||||
how_it_works_text: str
|
how_it_works_text: str
|
||||||
getting_started: str
|
getting_started: str
|
||||||
getting_started_text: str
|
getting_started_text: str
|
||||||
|
invalidate: GUIHelpInvalidate
|
||||||
|
|
||||||
|
|
||||||
class GUIMessages(TypedDict):
|
class GUIMessages(TypedDict):
|
||||||
@@ -434,6 +440,10 @@ default_translation: Translation = {
|
|||||||
"the \"Priority mode\", requires you to press on \"Reload\" "
|
"the \"Priority mode\", requires you to press on \"Reload\" "
|
||||||
"for the changes to take an effect."
|
"for the changes to take an effect."
|
||||||
),
|
),
|
||||||
|
"invalidate": {
|
||||||
|
"button": "Invalidate",
|
||||||
|
"text": "Invalidate the authentication token (log out):",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,17 @@ class _AuthState:
|
|||||||
if hasattr(self, attr):
|
if hasattr(self, attr):
|
||||||
delattr(self, attr)
|
delattr(self, attr)
|
||||||
|
|
||||||
|
def invalidate(self, *, delete_cookies: bool = False) -> None:
|
||||||
|
self._delattrs("access_token", "user_id")
|
||||||
|
self._logged_in.clear()
|
||||||
|
self._twitch.gui.help._invalidate_button.config(state="disabled")
|
||||||
|
if delete_cookies:
|
||||||
|
session = self._twitch._session
|
||||||
|
if session is not None:
|
||||||
|
jar = cast(aiohttp.CookieJar, session.cookie_jar)
|
||||||
|
jar.clear()
|
||||||
|
COOKIES_PATH.unlink(missing_ok=True)
|
||||||
|
|
||||||
def clear(self) -> None:
|
def clear(self) -> None:
|
||||||
self._delattrs(
|
self._delattrs(
|
||||||
"user_id",
|
"user_id",
|
||||||
@@ -105,6 +116,7 @@ class _AuthState:
|
|||||||
"client_version",
|
"client_version",
|
||||||
)
|
)
|
||||||
self._logged_in.clear()
|
self._logged_in.clear()
|
||||||
|
self._twitch.gui.help._invalidate_button.config(state="disabled")
|
||||||
|
|
||||||
async def _oauth_login(self) -> str:
|
async def _oauth_login(self) -> str:
|
||||||
login_form: LoginForm = self._twitch.gui.login
|
login_form: LoginForm = self._twitch.gui.login
|
||||||
@@ -414,11 +426,9 @@ class _AuthState:
|
|||||||
# update our cookie and save it
|
# update our cookie and save it
|
||||||
jar.update_cookies(cookie, client_info.CLIENT_URL)
|
jar.update_cookies(cookie, client_info.CLIENT_URL)
|
||||||
jar.save(COOKIES_PATH)
|
jar.save(COOKIES_PATH)
|
||||||
|
self._twitch.gui.help._invalidate_button.config(state="normal")
|
||||||
self._logged_in.set()
|
self._logged_in.set()
|
||||||
|
|
||||||
def invalidate(self):
|
|
||||||
self._delattrs("access_token")
|
|
||||||
|
|
||||||
|
|
||||||
class Twitch:
|
class Twitch:
|
||||||
def __init__(self, settings: Settings):
|
def __init__(self, settings: Settings):
|
||||||
@@ -866,6 +876,8 @@ class Twitch:
|
|||||||
self.print(_("status", "no_channel"))
|
self.print(_("status", "no_channel"))
|
||||||
self.change_state(State.IDLE)
|
self.change_state(State.IDLE)
|
||||||
del new_watching, selected_channel, watching_channel
|
del new_watching, selected_channel, watching_channel
|
||||||
|
elif self._state is State.RESTART:
|
||||||
|
raise ReloadRequest()
|
||||||
elif self._state is State.EXIT:
|
elif self._state is State.EXIT:
|
||||||
self.gui.tray.change_icon("pickaxe")
|
self.gui.tray.change_icon("pickaxe")
|
||||||
self.gui.status.update(_("gui", "status", "exiting"))
|
self.gui.status.update(_("gui", "status", "exiting"))
|
||||||
|
|||||||
Reference in new issue
Block a user