mirror of
https://github.com/yawaflua/Flask-Discord.git
synced 2025-12-10 12:29:30 +02:00
Params rework. requirements.txt updated
This commit is contained in:
@@ -1,7 +1,11 @@
|
|||||||
|
from typing import Union
|
||||||
|
|
||||||
from . import configs, _http, models
|
from . import configs, _http, models
|
||||||
|
|
||||||
from flask import request, session, redirect
|
from flask import request, session, redirect
|
||||||
from oauthlib.common import add_params_to_uri
|
from oauthlib.common import add_params_to_uri, generate_token
|
||||||
|
import discord
|
||||||
|
import jwt
|
||||||
|
|
||||||
|
|
||||||
class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
||||||
@@ -12,40 +16,43 @@ class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
app : Flask
|
`app` : Flask
|
||||||
An instance of your `flask application <http://flask.pocoo.org/docs/1.0/api/#flask.Flask>`_.
|
An instance of your `flask application <http://flask.pocoo.org/docs/1.0/api/#flask.Flask>`_.
|
||||||
client_id : int, optional
|
`client_id` : int, optional
|
||||||
The client ID of discord application provided. Can be also set to flask config
|
The client ID of discord application provided. Can be also set to flask config
|
||||||
with key ``DISCORD_CLIENT_ID``.
|
with key ``DISCORD_CLIENT_ID``.
|
||||||
client_secret : str, optional
|
`client_secret` : str, optional
|
||||||
The client secret of discord application provided. Can be also set to flask config
|
The client secret of discord application provided. Can be also set to flask config
|
||||||
with key ``DISCORD_CLIENT_SECRET``.
|
with key ``DISCORD_CLIENT_SECRET``.
|
||||||
redirect_uri : str, optional
|
`redirect_uri` : str, optional
|
||||||
The default URL to use to redirect user to after authorization. Can be also set to flask config
|
The default URL to use to redirect user to after authorization. Can be also set to flask config
|
||||||
with key ``DISCORD_REDIRECT_URI``.
|
with key ``DISCORD_REDIRECT_URI``.
|
||||||
bot_token : str, optional
|
`bot_token` : str, optional
|
||||||
The bot token of the application. This is required when you also need to access bot scope resources
|
The bot token of the application. This is required when you also need to access bot scope resources
|
||||||
beyond the normal resources provided by the OAuth. Can be also set to flask config with
|
beyond the normal resources provided by the OAuth. Can be also set to flask config with
|
||||||
key ``DISCORD_BOT_TOKEN``.
|
key ``DISCORD_BOT_TOKEN``.
|
||||||
users_cache : cachetools.LFUCache, optional
|
`users_cache` : cachetools.LFUCache, optional
|
||||||
Any dict like mapping to internally cache the authorized users. Preferably an instance of
|
Any dict like mapping to internally cache the authorized users. Preferably an instance of
|
||||||
cachetools.LFUCache or cachetools.TTLCache. If not specified, default cachetools.LFUCache is used.
|
cachetools.LFUCache or cachetools.TTLCache. If not specified, default cachetools.LFUCache is used.
|
||||||
Uses the default max limit for cache if ``DISCORD_USERS_CACHE_MAX_LIMIT`` isn't specified in app config.
|
Uses the default max limit for cache if ``DISCORD_USERS_CACHE_MAX_LIMIT`` isn't specified in app config.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
client_id : int
|
`client_id` : int
|
||||||
The client ID of discord application provided.
|
The client ID of discord application provided.
|
||||||
redirect_uri : str
|
`redirect_uri` : str
|
||||||
The default URL to use to redirect user to after authorization.
|
The default URL to use to redirect user to after authorization.
|
||||||
users_cache : cachetools.LFUCache
|
`users_cache` : cachetools.LFUCache
|
||||||
A dict like mapping to internally cache the authorized users. Preferably an instance of
|
A dict like mapping to internally cache the authorized users. Preferably an instance of
|
||||||
cachetools.LFUCache or cachetools.TTLCache. If not specified, default cachetools.LFUCache is used.
|
cachetools.LFUCache or cachetools.TTLCache. If not specified, default cachetools.LFUCache is used.
|
||||||
Uses the default max limit for cache if ``DISCORD_USERS_CACHE_MAX_LIMIT`` isn't specified in app config.
|
Uses the default max limit for cache if ``DISCORD_USERS_CACHE_MAX_LIMIT`` isn't specified in app config.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def create_session(self, scope: list = None, prompt: bool = True, params: dict = None):
|
def create_session(self, scope: list = None, prompt: str = "consent",
|
||||||
|
permissions: Union[discord.Permissions, int] = None,
|
||||||
|
guild_id: int = None, disable_guild_select: bool = None,
|
||||||
|
**params):
|
||||||
"""Primary method used to create OAuth2 session and redirect users for
|
"""Primary method used to create OAuth2 session and redirect users for
|
||||||
authorization code grant.
|
authorization code grant.
|
||||||
|
|
||||||
@@ -54,11 +61,18 @@ class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
|||||||
scope : list, optional
|
scope : list, optional
|
||||||
An optional list of valid `Discord OAuth2 Scopes
|
An optional list of valid `Discord OAuth2 Scopes
|
||||||
<https://discordapp.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes>`_.
|
<https://discordapp.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes>`_.
|
||||||
prompt : bool, optional
|
prompt : str, optional
|
||||||
Determines if the OAuth2 grant should be explicitly prompted and re-approved. Defaults to True.
|
permissions: discord.Permissions object or int, optional
|
||||||
Specify False for implicit grant which will skip the authorization screen and redirect to redirect URI.
|
guild_id : int, optional
|
||||||
params : dict, optional
|
disable_guild_select : bool, optional
|
||||||
|
params : kwargs, optional
|
||||||
An optional mapping of query parameters to supply to the authorization URL.
|
An optional mapping of query parameters to supply to the authorization URL.
|
||||||
|
Since query parameters aren't passed through Discord Oauth2, these get added to the state.
|
||||||
|
Use `:py:meth:`flask_discord.DiscordOAuth2Session.callback()` to retrieve the params passed in.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
`prompt` has been changed. You must specify the raw value ('consent' or 'none'). Defaults to 'consent'.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@@ -68,17 +82,39 @@ class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
|||||||
"""
|
"""
|
||||||
scope = scope or request.args.get("scope", str()).split() or configs.DISCORD_OAUTH_DEFAULT_SCOPES
|
scope = scope or request.args.get("scope", str()).split() or configs.DISCORD_OAUTH_DEFAULT_SCOPES
|
||||||
|
|
||||||
if not prompt and set(scope) & set(configs.DISCORD_PASSTHROUGH_SCOPES):
|
if prompt != "consent" and set(scope) & set(configs.DISCORD_PASSTHROUGH_SCOPES):
|
||||||
raise ValueError("You should use explicit OAuth grant for passthrough scopes like bot.")
|
raise ValueError("You should use explicit OAuth grant for passthrough scopes like bot.")
|
||||||
|
|
||||||
discord_session = self._make_session(scope=scope)
|
if permissions is not None and not (isinstance(permissions, discord.Permissions)
|
||||||
authorization_url, state = discord_session.authorization_url(configs.DISCORD_AUTHORIZATION_BASE_URL)
|
or isinstance(permissions, int)):
|
||||||
session["DISCORD_OAUTH2_STATE"] = state
|
raise ValueError(f"permissions must be an int or discord.Permissions, not {type(permissions)}.")
|
||||||
|
|
||||||
prompt = "consent" if prompt else "none"
|
if isinstance(permissions, discord.Permissions):
|
||||||
params = params or dict()
|
permissions = permissions.value
|
||||||
params.update(prompt=prompt)
|
|
||||||
authorization_url = add_params_to_uri(authorization_url, params)
|
# Encode any params into a jwt with the state as the key
|
||||||
|
# Use generate_token in case state is None
|
||||||
|
session['DISCORD_RAW_OAUTH2_STATE'] = session.get("DISCORD_OAUTH2_STATE", generate_token())
|
||||||
|
state = jwt.encode(params, session.get("DISCORD_RAW_OAUTH2_STATE"))
|
||||||
|
|
||||||
|
discord_session = self._make_session(scope=scope, state=state)
|
||||||
|
authorization_url, state = discord_session.authorization_url(configs.DISCORD_AUTHORIZATION_BASE_URL)
|
||||||
|
|
||||||
|
# Save the encoded state as that's what Oauth2 lib is expecting
|
||||||
|
session["DISCORD_OAUTH2_STATE"] = state.decode("utf-8")
|
||||||
|
|
||||||
|
# Add special parameters to uri instead of state
|
||||||
|
uri_params = {'prompt': prompt}
|
||||||
|
if permissions:
|
||||||
|
uri_params.update(permissions=permissions)
|
||||||
|
if guild_id:
|
||||||
|
uri_params.update(guild_id=guild_id)
|
||||||
|
if disable_guild_select is not None:
|
||||||
|
uri_params.update(disable_guild_select=disable_guild_select)
|
||||||
|
|
||||||
|
authorization_url = add_params_to_uri(authorization_url, uri_params)
|
||||||
|
if permissions:
|
||||||
|
authorization_url = add_params_to_uri(authorization_url, {'permissions': permissions})
|
||||||
|
|
||||||
return redirect(authorization_url)
|
return redirect(authorization_url)
|
||||||
|
|
||||||
@@ -115,6 +151,11 @@ class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
|||||||
token = self._fetch_token()
|
token = self._fetch_token()
|
||||||
self.save_authorization_token(token)
|
self.save_authorization_token(token)
|
||||||
|
|
||||||
|
# Decode any parameters passed through state variable
|
||||||
|
raw_oauth_state = session.get("DISCORD_RAW_OAUTH2_STATE")
|
||||||
|
passed_state = request.args.get("state")
|
||||||
|
return jwt.decode(passed_state, raw_oauth_state)
|
||||||
|
|
||||||
def revoke(self):
|
def revoke(self):
|
||||||
"""This method clears current discord token, state and all session data from flask
|
"""This method clears current discord token, state and all session data from flask
|
||||||
`session <http://flask.pocoo.org/docs/1.0/api/#flask.session>`_. Which means user will have
|
`session <http://flask.pocoo.org/docs/1.0/api/#flask.session>`_. Which means user will have
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
Flask
|
Flask~=1.1.2
|
||||||
cachetools
|
cachetools~=4.1.1
|
||||||
setuptools
|
setuptools~=49.2.1
|
||||||
requests
|
requests~=2.24.0
|
||||||
oauthlib
|
oauthlib~=3.1.0
|
||||||
discord.py
|
discord.py~=1.4.0
|
||||||
requests_oauthlib
|
requests_oauthlib
|
||||||
|
PyJWT~=1.7.1
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from flask import Flask, redirect, url_for
|
from flask import Flask, redirect, url_for, session
|
||||||
from flask_discord import DiscordOAuth2Session, requires_authorization
|
from flask_discord import DiscordOAuth2Session, requires_authorization
|
||||||
|
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ app = Flask(__name__)
|
|||||||
|
|
||||||
app.secret_key = b"%\xe0'\x01\xdeH\x8e\x85m|\xb3\xffCN\xc9g"
|
app.secret_key = b"%\xe0'\x01\xdeH\x8e\x85m|\xb3\xffCN\xc9g"
|
||||||
|
|
||||||
app.config["DISCORD_CLIENT_ID"] = 490732332240863233
|
app.config["DISCORD_CLIENT_ID"] = 732337836619202590
|
||||||
app.config["DISCORD_CLIENT_SECRET"] = os.getenv("DISCORD_CLIENT_SECRET")
|
app.config["DISCORD_CLIENT_SECRET"] = os.getenv("DISCORD_CLIENT_SECRET")
|
||||||
app.config["DISCORD_BOT_TOKEN"] = os.getenv("DISCORD_BOT_TOKEN")
|
app.config["DISCORD_BOT_TOKEN"] = os.getenv("DISCORD_BOT_TOKEN")
|
||||||
app.config["DISCORD_REDIRECT_URI"] = "http://127.0.0.1:5000/callback"
|
app.config["DISCORD_REDIRECT_URI"] = "http://127.0.0.1:5000/callback"
|
||||||
@@ -22,7 +22,13 @@ HYPERLINK = '<a href="{}">{}</a>'
|
|||||||
@app.route("/")
|
@app.route("/")
|
||||||
def index():
|
def index():
|
||||||
if not discord.authorized:
|
if not discord.authorized:
|
||||||
return HYPERLINK.format(url_for(".login"), "Login")
|
return f"""
|
||||||
|
{HYPERLINK.format(url_for(".login"), "Login")} <br />
|
||||||
|
{HYPERLINK.format(url_for(".login_with_params"), "Login with params")} <br />
|
||||||
|
{HYPERLINK.format(url_for(".invite"), "Invite Bot")} <br />
|
||||||
|
{HYPERLINK.format(url_for(".invite_oauth"), "Authorize with oauth and bot invite")}
|
||||||
|
"""
|
||||||
|
|
||||||
return f"""
|
return f"""
|
||||||
{HYPERLINK.format(url_for(".me"), "@ME")}<br />
|
{HYPERLINK.format(url_for(".me"), "@ME")}<br />
|
||||||
{HYPERLINK.format(url_for(".logout"), "Logout")}<br />
|
{HYPERLINK.format(url_for(".logout"), "Logout")}<br />
|
||||||
@@ -36,10 +42,26 @@ def login():
|
|||||||
return discord.create_session()
|
return discord.create_session()
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/login-params/")
|
||||||
|
def login_with_params():
|
||||||
|
return discord.create_session(redirect="/me/", coupon="15off", number=15, zero=0, status=False)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/invite/")
|
||||||
|
def invite():
|
||||||
|
return discord.create_session(scope=['bot'], permissions=8)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/invite_oauth/")
|
||||||
|
def invite_oauth():
|
||||||
|
return discord.create_session(scope=['bot', 'identify'], permissions=8)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/callback/")
|
@app.route("/callback/")
|
||||||
def callback():
|
def callback():
|
||||||
discord.callback()
|
params = discord.callback()
|
||||||
return redirect(url_for(".index"))
|
redirect_to = params.get("redirect", "/")
|
||||||
|
return redirect(redirect_to)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/me/")
|
@app.route("/me/")
|
||||||
|
|||||||
Reference in New Issue
Block a user