8 changed files with 680 additions and 69 deletions
@ -0,0 +1,228 @@ |
|||
""" |
|||
The MIT License (MIT) |
|||
|
|||
Copyright (c) 2021-present Dolfies |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a |
|||
copy of this software and associated documentation files (the "Software"), |
|||
to deal in the Software without restriction, including without limitation |
|||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|||
and/or sell copies of the Software, and to permit persons to whom the |
|||
Software is furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in |
|||
all copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|||
DEALINGS IN THE SOFTWARE. |
|||
""" |
|||
|
|||
from __future__ import annotations |
|||
|
|||
from typing import TYPE_CHECKING, List, Optional |
|||
|
|||
from .application import PartialApplication |
|||
from .guild import UserGuild |
|||
from .mixins import Hashable |
|||
from .utils import MISSING |
|||
|
|||
if TYPE_CHECKING: |
|||
from .abc import Snowflake |
|||
from .permissions import Permissions |
|||
from .state import ConnectionState |
|||
from .user import User |
|||
from .types.oauth2 import OAuth2Authorization as OAuth2AuthorizationPayload, OAuth2Token as OAuth2TokenPayload |
|||
|
|||
__all__ = ( |
|||
'OAuth2Token', |
|||
'OAuth2Authorization', |
|||
) |
|||
|
|||
|
|||
class OAuth2Token(Hashable): |
|||
"""Represents an authorized OAuth2 application for a user. |
|||
|
|||
.. container:: operations |
|||
|
|||
.. describe:: x == y |
|||
|
|||
Checks if two authorizations are equal. |
|||
|
|||
.. describe:: x != y |
|||
|
|||
Checks if two authorizations are not equal. |
|||
|
|||
.. describe:: hash(x) |
|||
|
|||
Return the authorizations's hash. |
|||
|
|||
.. describe:: str(x) |
|||
|
|||
Returns the authorizations's name. |
|||
|
|||
.. versionadded:: 2.1 |
|||
|
|||
Attributes |
|||
----------- |
|||
id: :class:`int` |
|||
The ID of the authorization. |
|||
application: :class:`PartialApplication` |
|||
The application that the authorization is for. |
|||
scopes: List[:class:`str`] |
|||
The scopes that the authorization has. |
|||
""" |
|||
|
|||
__slots__ = ('id', 'application', 'scopes', '_state') |
|||
|
|||
def __init__(self, *, state: ConnectionState, data: OAuth2TokenPayload): |
|||
self._state = state |
|||
self.id: int = int(data['id']) |
|||
self.application: PartialApplication = PartialApplication(state=state, data=data['application']) |
|||
self.scopes: List[str] = data['scopes'] |
|||
|
|||
def __repr__(self): |
|||
return f'<OAuth2Token id={self.id} application={self.application!r} scopes={self.scopes!r}>' |
|||
|
|||
def __str__(self): |
|||
return self.application.name |
|||
|
|||
@property |
|||
def authorized(self) -> bool: |
|||
""":class:`bool`: Whether the user has already authorized the application. |
|||
|
|||
This is here for compatibility purposes and is always ``True``. |
|||
""" |
|||
return True |
|||
|
|||
async def revoke(self): |
|||
"""|coro| |
|||
|
|||
Revokes the application's authorization. |
|||
|
|||
Raises |
|||
------- |
|||
HTTPException |
|||
Deauthorizing the application failed. |
|||
""" |
|||
await self._state.http.revoke_oauth2_token(self.id) |
|||
|
|||
|
|||
class OAuth2Authorization: |
|||
"""Represents a Discord OAuth2 application authorization. |
|||
|
|||
.. versionadded:: 2.1 |
|||
|
|||
Attributes |
|||
----------- |
|||
scopes: List[:class:`str`] |
|||
The scopes that the authorization has. |
|||
response_type: Optional[:class:`str`] |
|||
The response type that will be used for the authorization, if using the full OAuth2 flow. |
|||
code_challenge_method: Optional[:class:`str`] |
|||
The code challenge method that will be used for the PKCE authorization, if using the full OAuth2 flow. |
|||
code_challenge: Optional[:class:`str`] |
|||
The code challenge that will be used for the PKCE authorization, if using the full OAuth2 flow. |
|||
state: Optional[:class:`str`] |
|||
The state that will be used for authorization security. |
|||
authorized: :class:`bool` |
|||
Whether the user has already authorized the application. |
|||
application: :class:`PartialApplication` |
|||
The application that the authorization is for. |
|||
bot: Optional[:class:`User`] |
|||
The bot user associated with the application, provided if authorizing with the ``bot`` scope. |
|||
approximate_guild_count: Optional[:class:`int`] |
|||
The approximate number of guilds the bot is in, provided if authorizing with the ``bot`` scope. |
|||
guilds: List[:class:`UserGuild`] |
|||
The guilds the current user is in, provided if authorizing with the ``bot`` scope. |
|||
redirect_uri: Optional[:class:`str`] |
|||
The redirect URI that will be used for the authorization, if using the full OAuth2 flow and a redirect URI exists. |
|||
""" |
|||
|
|||
__slots__ = ( |
|||
'authorized', |
|||
'application', |
|||
'bot', |
|||
'approximate_guild_count', |
|||
'guilds', |
|||
'redirect_uri', |
|||
'scopes', |
|||
'response_type', |
|||
'code_challenge_method', |
|||
'code_challenge', |
|||
'state', |
|||
'_state', |
|||
) |
|||
|
|||
def __init__( |
|||
self, |
|||
*, |
|||
_state: ConnectionState, |
|||
data: OAuth2AuthorizationPayload, |
|||
scopes: List[str], |
|||
response_type: Optional[str], |
|||
code_challenge_method: Optional[str] = None, |
|||
code_challenge: Optional[str] = None, |
|||
state: Optional[str], |
|||
): |
|||
self._state = _state |
|||
self.scopes: List[str] = scopes |
|||
self.response_type: Optional[str] = response_type |
|||
self.code_challenge_method: Optional[str] = code_challenge_method |
|||
self.code_challenge: Optional[str] = code_challenge |
|||
self.state: Optional[str] = state |
|||
self.authorized: bool = data['authorized'] |
|||
self.application: PartialApplication = PartialApplication(state=_state, data=data['application']) |
|||
self.bot: Optional[User] = _state.store_user(data['bot']) if 'bot' in data else None |
|||
self.approximate_guild_count: Optional[int] = ( |
|||
data['bot'].get('approximate_guild_count', 0) if 'bot' in data else None |
|||
) |
|||
self.guilds: List[UserGuild] = [UserGuild(state=_state, data=g) for g in data.get('guilds', [])] |
|||
self.redirect_uri: Optional[str] = data.get('redirect_uri') |
|||
|
|||
def __repr__(self): |
|||
return f'<OAuth2Authorization authorized={self.authorized} application={self.application!r} scopes={self.scopes!r} response_type={self.response_type!r} redirect_uri={self.redirect_uri}>' |
|||
|
|||
async def authorize( |
|||
self, *, guild: Snowflake = MISSING, channel: Snowflake = MISSING, permissions: Permissions = MISSING |
|||
) -> str: |
|||
"""|coro| |
|||
|
|||
Authorizes the application for the user. A shortcut for :meth:`Client.create_authorization`. |
|||
|
|||
Parameters |
|||
----------- |
|||
guild: :class:`Guild` |
|||
The guild to authorize for, if authorizing with the ``applications.commands`` or ``bot`` scopes. |
|||
channel: Union[:class:`TextChannel`, :class:`VoiceChannel`, :class:`StageChannel`] |
|||
The channel to authorize for, if authorizing with the ``webhooks.incoming`` scope. See :meth:`Guild.webhook_channels`. |
|||
permissions: :class:`Permissions` |
|||
The permissions to grant, if authorizing with the ``bot`` scope. |
|||
|
|||
Raises |
|||
------- |
|||
HTTPException |
|||
Authorizing the application failed. |
|||
|
|||
Returns |
|||
-------- |
|||
:class:`str` |
|||
The URL to redirect the user to. May be an error page. |
|||
""" |
|||
data = await self._state.http.authorize_oauth2( |
|||
self.application.id, |
|||
self.scopes, |
|||
self.response_type, |
|||
self.redirect_uri, |
|||
self.code_challenge_method, |
|||
self.code_challenge, |
|||
self.state, |
|||
guild_id=guild.id if guild else None, |
|||
webhook_channel_id=channel.id if channel else None, |
|||
permissions=permissions.value if permissions else None, |
|||
) |
|||
return data['location'] |
@ -0,0 +1,68 @@ |
|||
""" |
|||
The MIT License (MIT) |
|||
|
|||
Copyright (c) 2021-present Dolfies |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a |
|||
copy of this software and associated documentation files (the "Software"), |
|||
to deal in the Software without restriction, including without limitation |
|||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|||
and/or sell copies of the Software, and to permit persons to whom the |
|||
Software is furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in |
|||
all copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|||
DEALINGS IN THE SOFTWARE. |
|||
""" |
|||
|
|||
from __future__ import annotations |
|||
|
|||
from typing import List, Optional, TypedDict |
|||
from typing_extensions import NotRequired |
|||
|
|||
from .application import PartialApplication |
|||
from .snowflake import Snowflake |
|||
from .user import PartialUser |
|||
|
|||
|
|||
class OAuth2Token(TypedDict): |
|||
id: Snowflake |
|||
application: PartialApplication |
|||
scopes: List[str] |
|||
|
|||
|
|||
class BotUser(PartialUser): |
|||
approximate_guild_count: int |
|||
|
|||
|
|||
class OAuth2Guild(TypedDict): |
|||
id: Snowflake |
|||
name: str |
|||
icon: Optional[str] |
|||
permissions: str |
|||
mfa_level: int |
|||
|
|||
|
|||
class OAuth2Authorization(TypedDict): |
|||
authorized: bool |
|||
user: PartialUser |
|||
application: PartialApplication |
|||
bot: NotRequired[BotUser] |
|||
guilds: NotRequired[List[OAuth2Guild]] |
|||
redirect_uri: NotRequired[Optional[str]] |
|||
|
|||
|
|||
class OAuth2Location(TypedDict): |
|||
location: str |
|||
|
|||
|
|||
class WebhookChannel(TypedDict): |
|||
id: Snowflake |
|||
name: str |
Loading…
Reference in new issue