def __init__( self, *args, client_name, instance_host_backend=None, instance_credentials_backend=None, session_class=None, **kwargs ): if session_class is None: session_class = MastodonSession OAuth2ConsumerBlueprint.__init__(self, *args, session_class=session_class, **kwargs) self.client_name = client_name if instance_host_backend is None: self.instance_host_backend = SessionBackend(key="{bp.name}_instance_host") elif callable(instance_host_backend): self.instance_host_backend = instance_host_backend() else: self.instance_host_backend = instance_host_backend if instance_credentials_backend is None: self.instance_credentials_backend = InMemoryBackend() elif callable(instance_credentials_backend): self.instance_credentials_backend = instance_credentials_backend() else: self.instance_credentials_backend = instance_credentials_backend
def __init__(self, name, import_name, static_folder=None, static_url_path=None, template_folder=None, url_prefix=None, subdomain=None, url_defaults=None, root_path=None, login_url=None, authorized_url=None, backend=None): bp_kwargs = dict( name=name, import_name=import_name, static_folder=static_folder, static_url_path=static_url_path, template_folder=template_folder, url_prefix=url_prefix, subdomain=subdomain, url_defaults=url_defaults, root_path=root_path, ) # `root_path` didn't exist in 0.10, and will cause an error if it's # passed in that version. Only pass `root_path` if it's set. if bp_kwargs["root_path"] is None: del bp_kwargs["root_path"] flask.Blueprint.__init__(self, **bp_kwargs) login_url = login_url or "/{bp.name}" authorized_url = authorized_url or "/{bp.name}/authorized" self.add_url_rule( rule=login_url.format(bp=self), endpoint="login", view_func=self.login, ) self.add_url_rule( rule=authorized_url.format(bp=self), endpoint="authorized", view_func=self.authorized, ) if backend is None: self.backend = SessionBackend() elif callable(backend): self.backend = backend() else: self.backend = backend self.logged_in_funcs = [] self.from_config = {} invalidate_token = lambda d: lazy.invalidate(self.session, "token") self.config = CallbackDict(on_update=invalidate_token) self.before_app_request(self.load_config)
def __init__(self, name, import_name, static_folder=None, static_url_path=None, template_folder=None, url_prefix=None, subdomain=None, url_defaults=None, root_path=None, login_url=None, authorized_url=None, backend=None): bp_kwargs = dict( name=name, import_name=import_name, static_folder=static_folder, static_url_path=static_url_path, template_folder=template_folder, url_prefix=url_prefix, subdomain=subdomain, url_defaults=url_defaults, root_path=root_path, ) # `root_path` didn't exist until 1.0 if StrictVersion(flask.__version__) < StrictVersion('1.0'): del bp_kwargs["root_path"] flask.Blueprint.__init__(self, **bp_kwargs) login_url = login_url or "/{bp.name}" authorized_url = authorized_url or "/{bp.name}/authorized" self.add_url_rule( rule=login_url.format(bp=self), endpoint="login", view_func=self.login, ) self.add_url_rule( rule=authorized_url.format(bp=self), endpoint="authorized", view_func=self.authorized, ) if backend is None: self.backend = SessionBackend() elif callable(backend): self.backend = backend() else: self.backend = backend self.logged_in_funcs = [] self.from_config = {} self.config = Dictective( lambda d: lazy.invalidate(self.session, "token")) self.before_app_request(self.load_config)
def __init__(self, name, import_name, static_folder=None, static_url_path=None, template_folder=None, url_prefix=None, subdomain=None, url_defaults=None, root_path=None, login_url=None, authorized_url=None, backend=None): bp_kwargs = dict( name=name, import_name=import_name, static_folder=static_folder, static_url_path=static_url_path, template_folder=template_folder, url_prefix=url_prefix, subdomain=subdomain, url_defaults=url_defaults, root_path=root_path, ) # `root_path` didn't exist until 1.0 if StrictVersion(flask.__version__) < StrictVersion('1.0'): del bp_kwargs["root_path"] flask.Blueprint.__init__(self, **bp_kwargs) login_url = login_url or "/{bp.name}" authorized_url = authorized_url or "/{bp.name}/authorized" self.add_url_rule( rule=login_url.format(bp=self), endpoint="login", view_func=self.login, ) self.add_url_rule( rule=authorized_url.format(bp=self), endpoint="authorized", view_func=self.authorized, ) if backend is None: self.backend = SessionBackend() elif callable(backend): self.backend = backend() else: self.backend = backend self.logged_in_funcs = [] self.from_config = {} self.config = Dictective(lambda d: lazy.invalidate(self.session, "token")) self.before_app_request(self.load_config)
def make_mastodon_blueprint( client_name, backend=None, instance_host_backend=None, instance_credentials_backend=None, scope="read", ): if backend is None: backend = SessionBackend(key="{bp.name}_{bp.instance_host}_oauth_token") mastodon_bp = MastodonConsumerBlueprint( "mastodon", __name__, client_name=client_name, scope=scope, backend=backend ) @mastodon_bp.before_app_request def set_applocal_session(): ctx = stack.top ctx.mastodon_oauth = mastodon_bp.session return mastodon_bp
class BaseOAuthConsumerBlueprint(six.with_metaclass(ABCMeta, flask.Blueprint)): def __init__(self, name, import_name, static_folder=None, static_url_path=None, template_folder=None, url_prefix=None, subdomain=None, url_defaults=None, root_path=None, login_url=None, authorized_url=None, backend=None): bp_kwargs = dict( name=name, import_name=import_name, static_folder=static_folder, static_url_path=static_url_path, template_folder=template_folder, url_prefix=url_prefix, subdomain=subdomain, url_defaults=url_defaults, root_path=root_path, ) # `root_path` didn't exist until 1.0 if StrictVersion(flask.__version__) < StrictVersion('1.0'): del bp_kwargs["root_path"] flask.Blueprint.__init__(self, **bp_kwargs) login_url = login_url or "/{bp.name}" authorized_url = authorized_url or "/{bp.name}/authorized" self.add_url_rule( rule=login_url.format(bp=self), endpoint="login", view_func=self.login, ) self.add_url_rule( rule=authorized_url.format(bp=self), endpoint="authorized", view_func=self.authorized, ) if backend is None: self.backend = SessionBackend() elif callable(backend): self.backend = backend() else: self.backend = backend self.logged_in_funcs = [] self.from_config = {} self.config = Dictective(lambda d: lazy.invalidate(self.session, "token")) self.before_app_request(self.load_config) def load_config(self): """ Used to dynamically load variables from the Flask application config into the blueprint. To tell this blueprint to pull configuration from the app, just set key-value pairs in the ``from_config`` dict. Keys are the name of the local variable to set on the blueprint object, and values are the variable name in the Flask application config. For example: blueprint.from_config["session.client_id"] = "GITHUB_OAUTH_CLIENT_ID" """ for local_var, config_var in self.from_config.items(): value = flask.current_app.config.get(config_var) if value: if "." in local_var: # this is a dotpath -- needs special handling body, tail = local_var.rsplit(".", 1) obj = getattrd(self, body) setattr(obj, tail, value) else: # just use a normal setattr call setattr(self, local_var, value) @property def token(self): return self.backend.get(self) @token.setter def token(self, value): self.backend.set(self, value) lazy.invalidate(self.session, "token") @token.deleter def token(self): self.backend.delete(self) lazy.invalidate(self.session, "token") @abstractproperty def session(self): raise NotImplementedError() @abstractmethod def login(self): raise NotImplementedError() @abstractmethod def authorized(self): raise NotImplementedError()
class BaseOAuthConsumerBlueprint(six.with_metaclass(ABCMeta, flask.Blueprint)): def __init__(self, name, import_name, static_folder=None, static_url_path=None, template_folder=None, url_prefix=None, subdomain=None, url_defaults=None, root_path=None, login_url=None, authorized_url=None, backend=None): bp_kwargs = dict( name=name, import_name=import_name, static_folder=static_folder, static_url_path=static_url_path, template_folder=template_folder, url_prefix=url_prefix, subdomain=subdomain, url_defaults=url_defaults, root_path=root_path, ) # `root_path` didn't exist in 0.10, and will cause an error if it's # passed in that version. Only pass `root_path` if it's set. if bp_kwargs["root_path"] is None: del bp_kwargs["root_path"] flask.Blueprint.__init__(self, **bp_kwargs) login_url = login_url or "/{bp.name}" authorized_url = authorized_url or "/{bp.name}/authorized" self.add_url_rule( rule=login_url.format(bp=self), endpoint="login", view_func=self.login, ) self.add_url_rule( rule=authorized_url.format(bp=self), endpoint="authorized", view_func=self.authorized, ) if backend is None: self.backend = SessionBackend() elif callable(backend): self.backend = backend() else: self.backend = backend self.logged_in_funcs = [] self.from_config = {} invalidate_token = lambda d: lazy.invalidate(self.session, "token") self.config = CallbackDict(on_update=invalidate_token) self.before_app_request(self.load_config) def load_config(self): """ Used to dynamically load variables from the Flask application config into the blueprint. To tell this blueprint to pull configuration from the app, just set key-value pairs in the ``from_config`` dict. Keys are the name of the local variable to set on the blueprint object, and values are the variable name in the Flask application config. For example: blueprint.from_config["session.client_id"] = "GITHUB_OAUTH_CLIENT_ID" """ for local_var, config_var in self.from_config.items(): value = flask.current_app.config.get(config_var) if value: if "." in local_var: # this is a dotpath -- needs special handling body, tail = local_var.rsplit(".", 1) obj = getattrd(self, body) setattr(obj, tail, value) else: # just use a normal setattr call setattr(self, local_var, value) @property def token(self): _token = self.backend.get(self) if _token and _token.get("expires_in") and _token.get("expires_at"): # Update the `expires_in` value, so that requests-oauthlib # can handle automatic token refreshing. Assume that # `expires_at` is a valid Unix timestamp. expires_at = datetime.utcfromtimestamp(_token["expires_at"]) expires_in = expires_at - datetime.utcnow() _token["expires_in"] = expires_in.total_seconds() return _token @token.setter def token(self, value): _token = value if _token and _token.get("expires_in"): # Set the `expires_at` value, overwriting any value # that may already be there. delta = timedelta(seconds=_token["expires_in"]) expires_at = datetime.utcnow() + delta _token["expires_at"] = timestamp_from_datetime(expires_at) self.backend.set(self, _token) lazy.invalidate(self.session, "token") @token.deleter def token(self): self.backend.delete(self) lazy.invalidate(self.session, "token") @abstractproperty def session(self): """ This is a session between the consumer (your website) and the provider (e.g. Twitter). It is *not* a session between a user of your website and your website. """ raise NotImplementedError() @abstractmethod def login(self): raise NotImplementedError() @abstractmethod def authorized(self): """ This is the route/function that the user will be redirected to by the provider (e.g. Twitter) after the user has logged into the provider's website and authorized your app to access their account. """ raise NotImplementedError()
class MastodonConsumerBlueprint(OAuth2ConsumerBlueprint): def __init__( self, *args, client_name, instance_host_backend=None, instance_credentials_backend=None, session_class=None, **kwargs ): if session_class is None: session_class = MastodonSession OAuth2ConsumerBlueprint.__init__(self, *args, session_class=session_class, **kwargs) self.client_name = client_name if instance_host_backend is None: self.instance_host_backend = SessionBackend(key="{bp.name}_instance_host") elif callable(instance_host_backend): self.instance_host_backend = instance_host_backend() else: self.instance_host_backend = instance_host_backend if instance_credentials_backend is None: self.instance_credentials_backend = InMemoryBackend() elif callable(instance_credentials_backend): self.instance_credentials_backend = instance_credentials_backend() else: self.instance_credentials_backend = instance_credentials_backend def _get_instance_credentials(self, host): url = "https://{instance}/api/v1/apps".format(instance=host) try: response = requests.post( url, data=dict( client_name=self.client_name, redirect_uris=url_for(".authorized", _external=True), scopes=self.scope, ), ).json() if "error" in response: return None return dict(client_id=response["client_id"], client_secret=response["client_secret"]) except Exception: return None @property def credentials(self): if not self.instance_host: return {} cached = self.instance_credentials_backend.get(self) if cached: return cached retrieved = self._get_instance_credentials(self.instance_host) if not retrieved: return {} self.instance_credentials_backend.set(self, retrieved) return retrieved @property def instance_host(self): return self.instance_host_backend.get(self) @instance_host.setter def instance_host(self, value): self.instance_host_backend.set(self, value) instance_config = self.credentials self.client_id = instance_config.get("client_id") lazy.invalidate(self.session, "token") @instance_host.deleter def instance_host(self): self.instance_host_backend.delete(self) lazy.invalidate(self.session, "token") @property def client_secret(self): return self.credentials.get("client_secret") @client_secret.setter def client_secret(self, value): pass @property def authorization_url(self): instance = self.instance_host return "https://{instance}/oauth/authorize".format(instance=instance) @authorization_url.setter def authorization_url(self, value): pass @property def token_url(self): instance = self.instance_host return "https://{instance}/oauth/token".format(instance=instance) @token_url.setter def token_url(self, value): pass @lazy def session(self): """ This is a session between the consumer (your website) and the provider (e.g. Twitter). It is *not* a session between a user of your website and your website. :return: """ instance = self.instance_host ret = self.session_class( client_id=self.credentials.get("client_id"), client=self.client, auto_refresh_url=self.auto_refresh_url, auto_refresh_kwargs=self.auto_refresh_kwargs, scope=self.scope, state=self.state, blueprint=self, base_url="https://{instance}".format(instance=instance), **self.kwargs ) def token_updater(token): self.token = token ret.token_updater = token_updater return self.session_created(ret) def login(self): if "instance_host" in request.args: self.instance_host = request.args["instance_host"] return super().login()
class BaseOAuthConsumerBlueprint(six.with_metaclass(ABCMeta, flask.Blueprint)): def __init__(self, name, import_name, static_folder=None, static_url_path=None, template_folder=None, url_prefix=None, subdomain=None, url_defaults=None, root_path=None, login_url=None, authorized_url=None, backend=None): bp_kwargs = dict( name=name, import_name=import_name, static_folder=static_folder, static_url_path=static_url_path, template_folder=template_folder, url_prefix=url_prefix, subdomain=subdomain, url_defaults=url_defaults, root_path=root_path, ) # `root_path` didn't exist in 0.10, and will cause an error if it's # passed in that version. Only pass `root_path` if it's set. if bp_kwargs["root_path"] is None: del bp_kwargs["root_path"] flask.Blueprint.__init__(self, **bp_kwargs) login_url = login_url or "/{bp.name}" authorized_url = authorized_url or "/{bp.name}/authorized" self.add_url_rule( rule=login_url.format(bp=self), endpoint="login", view_func=self.login, ) self.add_url_rule( rule=authorized_url.format(bp=self), endpoint="authorized", view_func=self.authorized, ) if backend is None: self.backend = SessionBackend() elif callable(backend): self.backend = backend() else: self.backend = backend self.logged_in_funcs = [] self.from_config = {} invalidate_token = lambda d: lazy.invalidate(self.session, "token") self.config = CallbackDict(on_update=invalidate_token) self.before_app_request(self.load_config) def load_config(self): """ Used to dynamically load variables from the Flask application config into the blueprint. To tell this blueprint to pull configuration from the app, just set key-value pairs in the ``from_config`` dict. Keys are the name of the local variable to set on the blueprint object, and values are the variable name in the Flask application config. For example: blueprint.from_config["session.client_id"] = "GITHUB_OAUTH_CLIENT_ID" """ for local_var, config_var in self.from_config.items(): value = flask.current_app.config.get(config_var) if value: if "." in local_var: # this is a dotpath -- needs special handling body, tail = local_var.rsplit(".", 1) obj = getattrd(self, body) setattr(obj, tail, value) else: # just use a normal setattr call setattr(self, local_var, value) @property def token(self): _token = self.backend.get(self) if _token and _token.get("expires_in") and _token.get("expires_at"): # Update the `expires_in` value, so that requests-oauthlib # can handle automatic token refreshing. Assume that # `expires_at` is a valid Unix timestamp. expires_at = datetime.utcfromtimestamp(_token["expires_at"]) expires_in = expires_at - datetime.utcnow() _token["expires_in"] = expires_in.total_seconds() return _token @token.setter def token(self, value): _token = value if _token and _token.get("expires_in"): # Set the `expires_at` value, overwriting any value # that may already be there. delta = timedelta(seconds=_token["expires_in"]) expires_at = datetime.utcnow() + delta _token["expires_at"] = timestamp_from_datetime(expires_at) self.backend.set(self, _token) lazy.invalidate(self.session, "token") @token.deleter def token(self): self.backend.delete(self) lazy.invalidate(self.session, "token") @abstractproperty def session(self): raise NotImplementedError() @abstractmethod def login(self): raise NotImplementedError() @abstractmethod def authorized(self): raise NotImplementedError()
class BaseOAuthConsumerBlueprint(six.with_metaclass(ABCMeta, flask.Blueprint)): def __init__(self, name, import_name, static_folder=None, static_url_path=None, template_folder=None, url_prefix=None, subdomain=None, url_defaults=None, root_path=None, login_url=None, authorized_url=None, backend=None): bp_kwargs = dict( name=name, import_name=import_name, static_folder=static_folder, static_url_path=static_url_path, template_folder=template_folder, url_prefix=url_prefix, subdomain=subdomain, url_defaults=url_defaults, root_path=root_path, ) # `root_path` didn't exist until 1.0 if StrictVersion(flask.__version__) < StrictVersion('1.0'): del bp_kwargs["root_path"] flask.Blueprint.__init__(self, **bp_kwargs) login_url = login_url or "/{bp.name}" authorized_url = authorized_url or "/{bp.name}/authorized" self.add_url_rule( rule=login_url.format(bp=self), endpoint="login", view_func=self.login, ) self.add_url_rule( rule=authorized_url.format(bp=self), endpoint="authorized", view_func=self.authorized, ) if backend is None: self.backend = SessionBackend() elif callable(backend): self.backend = backend() else: self.backend = backend self.logged_in_funcs = [] self.from_config = {} invalidate_token = lambda d: lazy.invalidate(self.session, "token") self.config = CallbackDict(on_update=invalidate_token) self.before_app_request(self.load_config) def load_config(self): """ Used to dynamically load variables from the Flask application config into the blueprint. To tell this blueprint to pull configuration from the app, just set key-value pairs in the ``from_config`` dict. Keys are the name of the local variable to set on the blueprint object, and values are the variable name in the Flask application config. For example: blueprint.from_config["session.client_id"] = "GITHUB_OAUTH_CLIENT_ID" """ for local_var, config_var in self.from_config.items(): value = flask.current_app.config.get(config_var) if value: if "." in local_var: # this is a dotpath -- needs special handling body, tail = local_var.rsplit(".", 1) obj = getattrd(self, body) setattr(obj, tail, value) else: # just use a normal setattr call setattr(self, local_var, value) @property def token(self): return self.backend.get(self) @token.setter def token(self, value): self.backend.set(self, value) lazy.invalidate(self.session, "token") @token.deleter def token(self): self.backend.delete(self) lazy.invalidate(self.session, "token") @abstractproperty def session(self): raise NotImplementedError() @abstractmethod def login(self): raise NotImplementedError() @abstractmethod def authorized(self): raise NotImplementedError()