diff options
Diffstat (limited to 'mediagoblin/plugins')
30 files changed, 73 insertions, 1251 deletions
diff --git a/mediagoblin/plugins/api/tools.py b/mediagoblin/plugins/api/tools.py index d1b3ebb1..56256236 100644 --- a/mediagoblin/plugins/api/tools.py +++ b/mediagoblin/plugins/api/tools.py @@ -18,9 +18,11 @@ import logging import json from functools import wraps -from urlparse import urljoin from werkzeug.exceptions import Forbidden from werkzeug.wrappers import Response + +from six.moves.urllib.parse import urljoin + from mediagoblin import mg_globals from mediagoblin.tools.pluginapi import PluginManager from mediagoblin.storage.filestorage import BasicFileStorage diff --git a/mediagoblin/plugins/api/views.py b/mediagoblin/plugins/api/views.py index e8af7988..23341065 100644 --- a/mediagoblin/plugins/api/views.py +++ b/mediagoblin/plugins/api/views.py @@ -17,6 +17,8 @@ import json import logging +import six + from werkzeug.exceptions import BadRequest from werkzeug.wrappers import Response @@ -24,8 +26,7 @@ from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.tools.response import json_response from mediagoblin.decorators import require_active_login from mediagoblin.meddleware.csrf import csrf_exempt -from mediagoblin.media_types import \ - InvalidFileType, FileTypeNotSupported +from mediagoblin.media_types import FileTypeNotSupported from mediagoblin.plugins.api.tools import api_auth, get_entry_serializable from mediagoblin.submit.lib import \ check_file_field, submit_media, get_upload_file_limits, \ @@ -55,16 +56,16 @@ def post_entry(request): callback_url = request.form.get('callback_url') if callback_url: - callback_url = unicode(callback_url) + callback_url = six.text_type(callback_url) try: entry = submit_media( mg_app=request.app, user=request.user, submitted_file=request.files['file'], filename=request.files['file'].filename, - title=unicode(request.form.get('title')), - description=unicode(request.form.get('description')), - license=unicode(request.form.get('license', '')), - tags_string=unicode(request.form.get('tags', '')), + title=six.text_type(request.form.get('title')), + description=six.text_type(request.form.get('description')), + license=six.text_type(request.form.get('license', '')), + tags_string=six.text_type(request.form.get('tags', '')), upload_limit=upload_limit, max_file_size=max_file_size, callback_url=callback_url) @@ -81,17 +82,8 @@ def post_entry(request): except UserPastUploadLimit: raise BadRequest( _('Sorry, you have reached your upload limit.')) - - except Exception as e: - ''' - This section is intended to catch exceptions raised in - mediagoblin.media_types - ''' - if isinstance(e, InvalidFileType) or \ - isinstance(e, FileTypeNotSupported): - raise BadRequest(unicode(e)) - else: - raise + except FileTypeNotSupported as e: + raise BadRequest(e) @api_auth @@ -103,7 +95,7 @@ def api_test(request): # TODO: This is the *only* thing using Response() here, should that # not simply use json_response()? - return Response(json.dumps(user_data)) + return Response(json.dumps(user_data, sort_keys=True)) def get_entries(request): diff --git a/mediagoblin/plugins/archivalook/templates/archivalook/feature_displays/audio_head.html b/mediagoblin/plugins/archivalook/templates/archivalook/feature_displays/audio_head.html index a53694b3..d1ea0b9a 100644 --- a/mediagoblin/plugins/archivalook/templates/archivalook/feature_displays/audio_head.html +++ b/mediagoblin/plugins/archivalook/templates/archivalook/feature_displays/audio_head.html @@ -1,5 +1,3 @@ <link rel="stylesheet" type="text/css" href="{{ request.staticdirect('/css/audio.css') }}" /> <script type="text/javascript" src="{{ request.staticdirect( - '/js/extlib/html5slider.js') }}"></script> - <script type="text/javascript" src="{{ request.staticdirect( '/js/audio.js') }}"></script> diff --git a/mediagoblin/plugins/basic_auth/forms.py b/mediagoblin/plugins/basic_auth/forms.py index 42b84bf3..9a6db226 100644 --- a/mediagoblin/plugins/basic_auth/forms.py +++ b/mediagoblin/plugins/basic_auth/forms.py @@ -20,7 +20,7 @@ from mediagoblin.auth.tools import normalize_user_or_email_field class RegistrationForm(wtforms.Form): - username = wtforms.TextField( + username = wtforms.StringField( _('Username'), [wtforms.validators.InputRequired(), normalize_user_or_email_field(allow_email=False)]) @@ -28,14 +28,14 @@ class RegistrationForm(wtforms.Form): _('Password'), [wtforms.validators.InputRequired(), wtforms.validators.Length(min=5, max=1024)]) - email = wtforms.TextField( + email = wtforms.StringField( _('Email address'), [wtforms.validators.InputRequired(), normalize_user_or_email_field(allow_user=False)]) class LoginForm(wtforms.Form): - username = wtforms.TextField( + username = wtforms.StringField( _('Username or Email'), [wtforms.validators.InputRequired(), normalize_user_or_email_field()]) @@ -47,7 +47,7 @@ class LoginForm(wtforms.Form): class ForgotPassForm(wtforms.Form): - username = wtforms.TextField( + username = wtforms.StringField( _('Username or email'), [wtforms.validators.InputRequired(), normalize_user_or_email_field()]) diff --git a/mediagoblin/plugins/basic_auth/tools.py b/mediagoblin/plugins/basic_auth/tools.py index f943bf39..13f240b2 100644 --- a/mediagoblin/plugins/basic_auth/tools.py +++ b/mediagoblin/plugins/basic_auth/tools.py @@ -16,6 +16,8 @@ import bcrypt import random +import six + from mediagoblin import mg_globals from mediagoblin.tools.crypto import get_timed_signer_url from mediagoblin.tools.mail import send_email @@ -66,7 +68,7 @@ def bcrypt_gen_password_hash(raw_pass, extra_salt=None): if extra_salt: raw_pass = u"%s:%s" % (extra_salt, raw_pass) - return unicode( + return six.text_type( bcrypt.hashpw(raw_pass.encode('utf-8'), bcrypt.gensalt())) diff --git a/mediagoblin/plugins/geolocation/__init__.py b/mediagoblin/plugins/geolocation/__init__.py index 5d14590e..06aab68e 100644 --- a/mediagoblin/plugins/geolocation/__init__.py +++ b/mediagoblin/plugins/geolocation/__init__.py @@ -21,13 +21,13 @@ PLUGIN_DIR = os.path.dirname(__file__) def setup_plugin(): config = pluginapi.get_config('mediagoblin.plugins.geolocation') - + # Register the template path. pluginapi.register_template_path(os.path.join(PLUGIN_DIR, 'templates')) pluginapi.register_template_hooks( - {"image_sideinfo": "mediagoblin/plugins/geolocation/map.html", - "image_head": "mediagoblin/plugins/geolocation/map_js_head.html"}) + {"location_info": "mediagoblin/plugins/geolocation/map.html", + "location_head": "mediagoblin/plugins/geolocation/map_js_head.html"}) hooks = { diff --git a/mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html b/mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html index 70f837ff..87f790d1 100644 --- a/mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html +++ b/mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html @@ -17,14 +17,13 @@ #} {% block geolocation_map %} - {% if media.media_data.gps_latitude is defined - and media.media_data.gps_latitude - and media.media_data.gps_longitude is defined - and media.media_data.gps_longitude %} - <h3>{% trans %}Location{% endtrans %}</h3> + {% if model.location + and model.get_location.position + and "latitude" in model.get_location.position + and "longitude" in model.get_location.position %} <div> - {%- set lon = media.media_data.gps_longitude %} - {%- set lat = media.media_data.gps_latitude %} + {%- set lon = model.get_location.position.longitude %} + {%- set lat = model.get_location.position.latitude %} {%- set osm_url = "http://openstreetmap.org/?mlat={lat}&mlon={lon}".format(lat=lat, lon=lon) %} <div id="tile-map" style="width: 100%; height: 196px;"> <input type="hidden" id="gps-longitude" diff --git a/mediagoblin/plugins/httpapiauth/__init__.py b/mediagoblin/plugins/httpapiauth/__init__.py index 2b2d593c..d7180463 100644 --- a/mediagoblin/plugins/httpapiauth/__init__.py +++ b/mediagoblin/plugins/httpapiauth/__init__.py @@ -16,6 +16,8 @@ import logging +import six + from werkzeug.exceptions import Unauthorized from mediagoblin.auth.tools import check_login_simple @@ -40,7 +42,7 @@ class HTTPAuth(Auth): if not request.authorization: return False - user = check_login_simple(unicode(request.authorization['username']), + user = check_login_simple(six.text_type(request.authorization['username']), request.authorization['password']) if user: diff --git a/mediagoblin/plugins/ldap/forms.py b/mediagoblin/plugins/ldap/forms.py index 1f1439ab..3d966e03 100644 --- a/mediagoblin/plugins/ldap/forms.py +++ b/mediagoblin/plugins/ldap/forms.py @@ -24,14 +24,14 @@ class RegisterForm(wtforms.Form): '', [wtforms.validators.InputRequired(), normalize_user_or_email_field(allow_email=False)]) - email = wtforms.TextField( + email = wtforms.StringField( _('Email address'), [wtforms.validators.InputRequired(), normalize_user_or_email_field(allow_user=False)]) class LoginForm(wtforms.Form): - username = wtforms.TextField( + username = wtforms.StringField( _('Username'), [wtforms.validators.InputRequired(), normalize_user_or_email_field()]) diff --git a/mediagoblin/plugins/ldap/tools.py b/mediagoblin/plugins/ldap/tools.py index 1c436792..2be2dcd7 100644 --- a/mediagoblin/plugins/ldap/tools.py +++ b/mediagoblin/plugins/ldap/tools.py @@ -16,6 +16,8 @@ import ldap import logging +import six + from mediagoblin.tools import pluginapi _log = logging.getLogger(__name__) @@ -47,7 +49,7 @@ class LDAP(object): return email def login(self, username, password): - for k, v in self.ldap_settings.iteritems(): + for k, v in six.iteritems(self.ldap_settings): try: self._connect(v) user_dn = v['LDAP_USER_DN_TEMPLATE'].format(username=username) diff --git a/mediagoblin/plugins/ldap/views.py b/mediagoblin/plugins/ldap/views.py index aef1bf56..be434daf 100644 --- a/mediagoblin/plugins/ldap/views.py +++ b/mediagoblin/plugins/ldap/views.py @@ -13,6 +13,9 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. + +import six + from mediagoblin import mg_globals, messages from mediagoblin.auth.tools import register_user from mediagoblin.db.models import User @@ -40,7 +43,7 @@ def login(request): if user: # set up login in session - request.session['user_id'] = unicode(user.id) + request.session['user_id'] = six.text_type(user.id) request.session.save() if request.form.get('next'): diff --git a/mediagoblin/plugins/oauth/README.rst b/mediagoblin/plugins/oauth/README.rst deleted file mode 100644 index 753b180f..00000000 --- a/mediagoblin/plugins/oauth/README.rst +++ /dev/null @@ -1,148 +0,0 @@ -============== - OAuth plugin -============== - -.. warning:: - In its current state. This plugin has received no security audit. - Development has been entirely focused on Making It Work(TM). Use this - plugin with caution. - - Additionally, this and the API may break... consider it pre-alpha. - There's also a known issue that the OAuth client doesn't do - refresh tokens so this might result in issues for users. - -The OAuth plugin enables third party web applications to authenticate as one or -more GNU MediaGoblin users in a safe way in order retrieve, create and update -content stored on the GNU MediaGoblin instance. - -The OAuth plugin is based on the `oauth v2.25 draft`_ and is pointing by using -the ``oauthlib.oauth2.draft25.WebApplicationClient`` from oauthlib_ to a -mediagoblin instance and building the OAuth 2 provider logic around the client. - -There are surely some aspects of the OAuth v2.25 draft that haven't made it -into this plugin due to the technique used to develop it. - -.. _`oauth v2.25 draft`: http://tools.ietf.org/html/draft-ietf-oauth-v2-25 -.. _oauthlib: http://pypi.python.org/pypi/oauthlib - - -Set up the OAuth plugin -======================= - -1. Add the following to your MediaGoblin .ini file in the ``[plugins]`` section:: - - [[mediagoblin.plugins.oauth]] - -2. Run:: - - gmg dbupdate - - in order to create and apply migrations to any database tables that the - plugin requires. - -.. note:: - This only enables the OAuth plugin. To be able to let clients fetch data - from the MediaGoblin instance you should also enable the API plugin or some - other plugin that supports authenticating with OAuth credentials. - - -Authenticate against GNU MediaGoblin -==================================== - -.. note:: - As mentioned in `capabilities`_ GNU MediaGoblin currently only supports the - `Authorization Code Grant`_ procedure for obtaining an OAuth access token. - -Authorization Code Grant ------------------------- - -.. note:: - As mentioned in `incapabilities`_ GNU MediaGoblin currently does not - support `client registration`_ - -The `authorization code grant`_ works in the following way: - -`Definitions` - - Authorization server - The GNU MediaGoblin instance - Resource server - Also the GNU MediaGoblin instance ;) - Client - The web application intended to use the data - Redirect uri - An URI pointing to a page controlled by the *client* - Resource owner - The GNU MediaGoblin user who's resources the client requests access to - User agent - Commonly the GNU MediaGoblin user's web browser - Authorization code - An intermediate token that is exchanged for an *access token* - Access token - A secret token that the *client* uses to authenticate itself agains the - *resource server* as a specific *resource owner*. - - -Brief description of the procedure -++++++++++++++++++++++++++++++++++ - -1. The *client* requests an *authorization code* from the *authorization - server* by redirecting the *user agent* to the `Authorization Endpoint`_. - Which parameters should be included in the redirect are covered later in - this document. -2. The *authorization server* authenticates the *resource owner* and redirects - the *user agent* back to the *redirect uri* (covered later in this - document). -3. The *client* receives the request from the *user agent*, attached is the - *authorization code*. -4. The *client* requests an *access token* from the *authorization server* -5. \?\?\?\?\? -6. Profit! - - -Detailed description of the procedure -+++++++++++++++++++++++++++++++++++++ - -TBD, in the meantime here is a proof-of-concept GNU MediaGoblin client: - -https://github.com/jwandborg/omgmg/ - -and here are some detailed descriptions from other OAuth 2 -providers: - -- https://developers.google.com/accounts/docs/OAuth2WebServer -- https://developers.facebook.com/docs/authentication/server-side/ - -and if you're unsure about anything, there's the `OAuth v2.25 draft -<http://tools.ietf.org/html/draft-ietf-oauth-v2-25>`_, the `OAuth plugin -source code -<http://gitorious.org/mediagoblin/mediagoblin/trees/master/mediagoblin/plugins/oauth>`_ -and the `#mediagoblin IRC channel <http://mediagoblin.org/pages/join.html#irc>`_. - - -Capabilities -============ - -- `Authorization endpoint`_ - Located at ``/oauth/authorize`` -- `Token endpoint`_ - Located at ``/oauth/access_token`` -- `Authorization Code Grant`_ -- `Client Registration`_ - -.. _`Authorization endpoint`: http://tools.ietf.org/html/draft-ietf-oauth-v2-25#section-3.1 -.. _`Token endpoint`: http://tools.ietf.org/html/draft-ietf-oauth-v2-25#section-3.2 -.. _`Authorization Code Grant`: http://tools.ietf.org/html/draft-ietf-oauth-v2-25#section-4.1 -.. _`Client Registration`: http://tools.ietf.org/html/draft-ietf-oauth-v2-25#section-2 - -Incapabilities -============== - -- Only `bearer tokens`_ are issued. -- `Implicit Grant`_ -- `Force TLS for token endpoint`_ - This one is up the the siteadmin -- Authorization `scope`_ and `state` -- ... - -.. _`bearer tokens`: http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-08 -.. _`scope`: http://tools.ietf.org/html/draft-ietf-oauth-v2-25#section-3.3 -.. _`Implicit Grant`: http://tools.ietf.org/html/draft-ietf-oauth-v2-25#section-4.2 -.. _`Force TLS for token endpoint`: http://tools.ietf.org/html/draft-ietf-oauth-v2-25#section-3.2 diff --git a/mediagoblin/plugins/oauth/__init__.py b/mediagoblin/plugins/oauth/__init__.py deleted file mode 100644 index 82c1f380..00000000 --- a/mediagoblin/plugins/oauth/__init__.py +++ /dev/null @@ -1,109 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import os -import logging - -from mediagoblin.tools import pluginapi -from mediagoblin.plugins.oauth.models import OAuthToken, OAuthClient, \ - OAuthUserClient -from mediagoblin.plugins.api.tools import Auth - -_log = logging.getLogger(__name__) - -PLUGIN_DIR = os.path.dirname(__file__) - - -def setup_plugin(): - config = pluginapi.get_config('mediagoblin.plugins.oauth') - - _log.info('Setting up OAuth...') - _log.debug('OAuth config: {0}'.format(config)) - - routes = [ - ('mediagoblin.plugins.oauth.authorize', - '/oauth-2/authorize', - 'mediagoblin.plugins.oauth.views:authorize'), - ('mediagoblin.plugins.oauth.authorize_client', - '/oauth-2/client/authorize', - 'mediagoblin.plugins.oauth.views:authorize_client'), - ('mediagoblin.plugins.oauth.access_token', - '/oauth-2/access_token', - 'mediagoblin.plugins.oauth.views:access_token'), - ('mediagoblin.plugins.oauth.list_connections', - '/oauth-2/client/connections', - 'mediagoblin.plugins.oauth.views:list_connections'), - ('mediagoblin.plugins.oauth.register_client', - '/oauth-2/client/register', - 'mediagoblin.plugins.oauth.views:register_client'), - ('mediagoblin.plugins.oauth.list_clients', - '/oauth-2/client/list', - 'mediagoblin.plugins.oauth.views:list_clients')] - - pluginapi.register_routes(routes) - pluginapi.register_template_path(os.path.join(PLUGIN_DIR, 'templates')) - - -class OAuthAuth(Auth): - def trigger(self, request): - if 'access_token' in request.GET: - return True - - return False - - def __call__(self, request, *args, **kw): - self.errors = [] - # TODO: Add suport for client credentials authorization - client_id = request.GET.get('client_id') # TODO: Not used - client_secret = request.GET.get('client_secret') # TODO: Not used - access_token = request.GET.get('access_token') - - _log.debug('Authorizing request {0}'.format(request.url)) - - if access_token: - token = OAuthToken.query.filter(OAuthToken.token == access_token)\ - .first() - - if not token: - self.errors.append('Invalid access token') - return False - - _log.debug('Access token: {0}'.format(token)) - _log.debug('Client: {0}'.format(token.client)) - - relation = OAuthUserClient.query.filter( - (OAuthUserClient.user == token.user) - & (OAuthUserClient.client == token.client) - & (OAuthUserClient.state == u'approved')).first() - - _log.debug('Relation: {0}'.format(relation)) - - if not relation: - self.errors.append( - u'Client has not been approved by the resource owner') - return False - - request.user = token.user - return True - - self.errors.append(u'No access_token specified') - - return False - -hooks = { - 'setup': setup_plugin, - 'auth': OAuthAuth() - } diff --git a/mediagoblin/plugins/oauth/forms.py b/mediagoblin/plugins/oauth/forms.py deleted file mode 100644 index ddf4d390..00000000 --- a/mediagoblin/plugins/oauth/forms.py +++ /dev/null @@ -1,69 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import wtforms - -from urlparse import urlparse - -from mediagoblin.tools.extlib.wtf_html5 import URLField -from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ - - -class AuthorizationForm(wtforms.Form): - client_id = wtforms.HiddenField(u'', - validators=[wtforms.validators.InputRequired()]) - next = wtforms.HiddenField(u'', validators=[wtforms.validators.InputRequired()]) - allow = wtforms.SubmitField(_(u'Allow')) - deny = wtforms.SubmitField(_(u'Deny')) - - -class ClientRegistrationForm(wtforms.Form): - name = wtforms.TextField(_('Name'), [wtforms.validators.InputRequired()], - description=_('The name of the OAuth client')) - description = wtforms.TextAreaField(_('Description'), - [wtforms.validators.Length(min=0, max=500)], - description=_('''This will be visible to users allowing your - application to authenticate as them.''')) - type = wtforms.SelectField(_('Type'), - [wtforms.validators.InputRequired()], - choices=[ - ('confidential', 'Confidential'), - ('public', 'Public')], - description=_('''<strong>Confidential</strong> - The client can - make requests to the GNU MediaGoblin instance that can not be - intercepted by the user agent (e.g. server-side client).<br /> - <strong>Public</strong> - The client can't make confidential - requests to the GNU MediaGoblin instance (e.g. client-side - JavaScript client).''')) - - redirect_uri = URLField(_('Redirect URI'), - [wtforms.validators.Optional(), wtforms.validators.URL()], - description=_('''The redirect URI for the applications, this field - is <strong>required</strong> for public clients.''')) - - def __init__(self, *args, **kw): - wtforms.Form.__init__(self, *args, **kw) - - def validate(self): - if not wtforms.Form.validate(self): - return False - - if self.type.data == 'public' and not self.redirect_uri.data: - self.redirect_uri.errors.append( - _('This field is required for public clients')) - return False - - return True diff --git a/mediagoblin/plugins/oauth/migrations.py b/mediagoblin/plugins/oauth/migrations.py deleted file mode 100644 index d7b89da3..00000000 --- a/mediagoblin/plugins/oauth/migrations.py +++ /dev/null @@ -1,158 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -from datetime import datetime, timedelta -from sqlalchemy import (MetaData, Table, Column, - Integer, Unicode, Enum, DateTime, ForeignKey) -from sqlalchemy.ext.declarative import declarative_base - -from mediagoblin.db.migration_tools import RegisterMigration -from mediagoblin.db.models import User - - -MIGRATIONS = {} - - -class OAuthClient_v0(declarative_base()): - __tablename__ = 'oauth__client' - - id = Column(Integer, primary_key=True) - created = Column(DateTime, nullable=False, - default=datetime.now) - - name = Column(Unicode) - description = Column(Unicode) - - identifier = Column(Unicode, unique=True, index=True) - secret = Column(Unicode, index=True) - - owner_id = Column(Integer, ForeignKey(User.id)) - redirect_uri = Column(Unicode) - - type = Column(Enum( - u'confidential', - u'public', - name=u'oauth__client_type')) - - -class OAuthUserClient_v0(declarative_base()): - __tablename__ = 'oauth__user_client' - id = Column(Integer, primary_key=True) - - user_id = Column(Integer, ForeignKey(User.id)) - client_id = Column(Integer, ForeignKey(OAuthClient_v0.id)) - - state = Column(Enum( - u'approved', - u'rejected', - name=u'oauth__relation_state')) - - -class OAuthToken_v0(declarative_base()): - __tablename__ = 'oauth__tokens' - - id = Column(Integer, primary_key=True) - created = Column(DateTime, nullable=False, - default=datetime.now) - expires = Column(DateTime, nullable=False, - default=lambda: datetime.now() + timedelta(days=30)) - token = Column(Unicode, index=True) - refresh_token = Column(Unicode, index=True) - - user_id = Column(Integer, ForeignKey(User.id), nullable=False, - index=True) - - client_id = Column(Integer, ForeignKey(OAuthClient_v0.id), nullable=False) - - def __repr__(self): - return '<{0} #{1} expires {2} [{3}, {4}]>'.format( - self.__class__.__name__, - self.id, - self.expires.isoformat(), - self.user, - self.client) - - -class OAuthCode_v0(declarative_base()): - __tablename__ = 'oauth__codes' - - id = Column(Integer, primary_key=True) - created = Column(DateTime, nullable=False, - default=datetime.now) - expires = Column(DateTime, nullable=False, - default=lambda: datetime.now() + timedelta(minutes=5)) - code = Column(Unicode, index=True) - - user_id = Column(Integer, ForeignKey(User.id), nullable=False, - index=True) - - client_id = Column(Integer, ForeignKey(OAuthClient_v0.id), nullable=False) - - -class OAuthRefreshToken_v0(declarative_base()): - __tablename__ = 'oauth__refresh_tokens' - - id = Column(Integer, primary_key=True) - created = Column(DateTime, nullable=False, - default=datetime.now) - - token = Column(Unicode, index=True) - - user_id = Column(Integer, ForeignKey(User.id), nullable=False) - - # XXX: Is it OK to use OAuthClient_v0.id in this way? - client_id = Column(Integer, ForeignKey(OAuthClient_v0.id), nullable=False) - - -@RegisterMigration(1, MIGRATIONS) -def remove_and_replace_token_and_code(db): - metadata = MetaData(bind=db.bind) - - token_table = Table('oauth__tokens', metadata, autoload=True, - autoload_with=db.bind) - - token_table.drop() - - code_table = Table('oauth__codes', metadata, autoload=True, - autoload_with=db.bind) - - code_table.drop() - - OAuthClient_v0.__table__.create(db.bind) - OAuthUserClient_v0.__table__.create(db.bind) - OAuthToken_v0.__table__.create(db.bind) - OAuthCode_v0.__table__.create(db.bind) - - db.commit() - - -@RegisterMigration(2, MIGRATIONS) -def remove_refresh_token_field(db): - metadata = MetaData(bind=db.bind) - - token_table = Table('oauth__tokens', metadata, autoload=True, - autoload_with=db.bind) - - refresh_token = token_table.columns['refresh_token'] - - refresh_token.drop() - db.commit() - -@RegisterMigration(3, MIGRATIONS) -def create_refresh_token_table(db): - OAuthRefreshToken_v0.__table__.create(db.bind) - - db.commit() diff --git a/mediagoblin/plugins/oauth/models.py b/mediagoblin/plugins/oauth/models.py deleted file mode 100644 index 439424d3..00000000 --- a/mediagoblin/plugins/oauth/models.py +++ /dev/null @@ -1,192 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -from datetime import datetime, timedelta - - -from sqlalchemy import ( - Column, Unicode, Integer, DateTime, ForeignKey, Enum) -from sqlalchemy.orm import relationship, backref -from mediagoblin.db.base import Base -from mediagoblin.db.models import User -from mediagoblin.plugins.oauth.tools import generate_identifier, \ - generate_secret, generate_token, generate_code, generate_refresh_token - -# Don't remove this, I *think* it applies sqlalchemy-migrate functionality onto -# the models. -from migrate import changeset - - -class OAuthClient(Base): - __tablename__ = 'oauth__client' - - id = Column(Integer, primary_key=True) - created = Column(DateTime, nullable=False, - default=datetime.now) - - name = Column(Unicode) - description = Column(Unicode) - - identifier = Column(Unicode, unique=True, index=True, - default=generate_identifier) - secret = Column(Unicode, index=True, default=generate_secret) - - owner_id = Column(Integer, ForeignKey(User.id)) - owner = relationship( - User, - backref=backref('registered_clients', cascade='all, delete-orphan')) - - redirect_uri = Column(Unicode) - - type = Column(Enum( - u'confidential', - u'public', - name=u'oauth__client_type')) - - def update_secret(self): - self.secret = generate_secret() - - def __repr__(self): - return '<{0} {1}:{2} ({3})>'.format( - self.__class__.__name__, - self.id, - self.name.encode('ascii', 'replace'), - self.owner.username.encode('ascii', 'replace')) - - -class OAuthUserClient(Base): - __tablename__ = 'oauth__user_client' - id = Column(Integer, primary_key=True) - - user_id = Column(Integer, ForeignKey(User.id)) - user = relationship( - User, - backref=backref('oauth_client_relations', - cascade='all, delete-orphan')) - - client_id = Column(Integer, ForeignKey(OAuthClient.id)) - client = relationship( - OAuthClient, - backref=backref('oauth_user_relations', cascade='all, delete-orphan')) - - state = Column(Enum( - u'approved', - u'rejected', - name=u'oauth__relation_state')) - - def __repr__(self): - return '<{0} #{1} {2} [{3}, {4}]>'.format( - self.__class__.__name__, - self.id, - self.state.encode('ascii', 'replace'), - self.user, - self.client) - - -class OAuthToken(Base): - __tablename__ = 'oauth__tokens' - - id = Column(Integer, primary_key=True) - created = Column(DateTime, nullable=False, - default=datetime.now) - expires = Column(DateTime, nullable=False, - default=lambda: datetime.now() + timedelta(days=30)) - token = Column(Unicode, index=True, default=generate_token) - - user_id = Column(Integer, ForeignKey(User.id), nullable=False, - index=True) - user = relationship( - User, - backref=backref('oauth_tokens', cascade='all, delete-orphan')) - - client_id = Column(Integer, ForeignKey(OAuthClient.id), nullable=False) - client = relationship( - OAuthClient, - backref=backref('oauth_tokens', cascade='all, delete-orphan')) - - def __repr__(self): - return '<{0} #{1} expires {2} [{3}, {4}]>'.format( - self.__class__.__name__, - self.id, - self.expires.isoformat(), - self.user, - self.client) - -class OAuthRefreshToken(Base): - __tablename__ = 'oauth__refresh_tokens' - - id = Column(Integer, primary_key=True) - created = Column(DateTime, nullable=False, - default=datetime.now) - - token = Column(Unicode, index=True, - default=generate_refresh_token) - - user_id = Column(Integer, ForeignKey(User.id), nullable=False) - - user = relationship(User, backref=backref('oauth_refresh_tokens', - cascade='all, delete-orphan')) - - client_id = Column(Integer, ForeignKey(OAuthClient.id), nullable=False) - client = relationship(OAuthClient, - backref=backref( - 'oauth_refresh_tokens', - cascade='all, delete-orphan')) - - def __repr__(self): - return '<{0} #{1} [{3}, {4}]>'.format( - self.__class__.__name__, - self.id, - self.user, - self.client) - - -class OAuthCode(Base): - __tablename__ = 'oauth__codes' - - id = Column(Integer, primary_key=True) - created = Column(DateTime, nullable=False, - default=datetime.now) - expires = Column(DateTime, nullable=False, - default=lambda: datetime.now() + timedelta(minutes=5)) - code = Column(Unicode, index=True, default=generate_code) - - user_id = Column(Integer, ForeignKey(User.id), nullable=False, - index=True) - user = relationship(User, backref=backref('oauth_codes', - cascade='all, delete-orphan')) - - client_id = Column(Integer, ForeignKey(OAuthClient.id), nullable=False) - client = relationship(OAuthClient, backref=backref( - 'oauth_codes', - cascade='all, delete-orphan')) - - def __repr__(self): - return '<{0} #{1} expires {2} [{3}, {4}]>'.format( - self.__class__.__name__, - self.id, - self.expires.isoformat(), - self.user, - self.client) - - -MODELS = [ - OAuthToken, - OAuthRefreshToken, - OAuthCode, - OAuthClient, - OAuthUserClient] diff --git a/mediagoblin/plugins/oauth/templates/oauth/authorize.html b/mediagoblin/plugins/oauth/templates/oauth/authorize.html deleted file mode 100644 index 8a00c925..00000000 --- a/mediagoblin/plugins/oauth/templates/oauth/authorize.html +++ /dev/null @@ -1,31 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -#, se, seee -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. --#} -{% extends "mediagoblin/base.html" %} -{% import "mediagoblin/utils/wtforms.html" as wtforms_util %} - -{% block mediagoblin_content %} -<form action="{{ request.urlgen('mediagoblin.plugins.oauth.authorize_client') }}" - method="POST"> - <div class="form_box_xl"> - {{ csrf_token }} - <h2>Authorize {{ client.name }}?</h2> - <p class="client-description">{{ client.description }}</p> - {{ wtforms_util.render_divs(form) }} - </div> -</form> -{% endblock %} diff --git a/mediagoblin/plugins/oauth/templates/oauth/client/connections.html b/mediagoblin/plugins/oauth/templates/oauth/client/connections.html deleted file mode 100644 index 63b0230a..00000000 --- a/mediagoblin/plugins/oauth/templates/oauth/client/connections.html +++ /dev/null @@ -1,34 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. --#} -{% extends "mediagoblin/base.html" %} -{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} - -{% block mediagoblin_content %} -<h1>{% trans %}OAuth client connections{% endtrans %}</h1> -{% if connections %} -<ul> - {% for connection in connections %} - <li><span title="{{ connection.client.description }}">{{ - connection.client.name }}</span> - {{ connection.state }} - </li> - {% endfor %} -</ul> -{% else %} -<p>You haven't connected using an OAuth client before.</p> -{% endif %} -{% endblock %} diff --git a/mediagoblin/plugins/oauth/templates/oauth/client/list.html b/mediagoblin/plugins/oauth/templates/oauth/client/list.html deleted file mode 100644 index 21024bb7..00000000 --- a/mediagoblin/plugins/oauth/templates/oauth/client/list.html +++ /dev/null @@ -1,45 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. --#} -{% extends "mediagoblin/base.html" %} -{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} - -{% block mediagoblin_content %} -<h1>{% trans %}Your OAuth clients{% endtrans %}</h1> -{% if clients %} -<ul> - {% for client in clients %} - <li>{{ client.name }} - <dl> - <dt>Type</dt> - <dd>{{ client.type }}</dd> - <dt>Description</dt> - <dd>{{ client.description }}</dd> - <dt>Identifier</dt> - <dd>{{ client.identifier }}</dd> - <dt>Secret</dt> - <dd>{{ client.secret }}</dd> - <dt>Redirect URI<dt> - <dd>{{ client.redirect_uri }}</dd> - </dl> - </li> - {% endfor %} -</ul> -{% else %} -<p>You don't have any clients yet. <a href="{{ request.urlgen('mediagoblin.plugins.oauth.register_client') }}">Add one</a>.</p> -{% endif %} -{% endblock %} diff --git a/mediagoblin/plugins/oauth/templates/oauth/client/register.html b/mediagoblin/plugins/oauth/templates/oauth/client/register.html deleted file mode 100644 index 6fd700d3..00000000 --- a/mediagoblin/plugins/oauth/templates/oauth/client/register.html +++ /dev/null @@ -1,34 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. --#} -{% extends "mediagoblin/base.html" %} -{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} - -{% block mediagoblin_content %} -<form action="{{ request.urlgen('mediagoblin.plugins.oauth.register_client') }}" - method="POST"> - <div class="form_box_xl"> - <h1>Register OAuth client</h1> - {{ wtforms_util.render_divs(form) }} - <div class="form_submit_buttons"> - {{ csrf_token }} - <input type="submit" value="{% trans %}Add{% endtrans %}" - class="button_form" /> - </div> - </div> -</form> -{% endblock %} diff --git a/mediagoblin/plugins/oauth/tools.py b/mediagoblin/plugins/oauth/tools.py deleted file mode 100644 index af0a3305..00000000 --- a/mediagoblin/plugins/oauth/tools.py +++ /dev/null @@ -1,114 +0,0 @@ -# -*- coding: utf-8 -*- -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import uuid - -from random import getrandbits - -from datetime import datetime - -from functools import wraps - -from mediagoblin.tools.response import json_response - - -def require_client_auth(controller): - ''' - View decorator - - - Requires the presence of ``?client_id`` - ''' - # Avoid circular import - from mediagoblin.plugins.oauth.models import OAuthClient - - @wraps(controller) - def wrapper(request, *args, **kw): - if not request.GET.get('client_id'): - return json_response({ - 'status': 400, - 'errors': [u'No client identifier in URL']}, - _disable_cors=True) - - client = OAuthClient.query.filter( - OAuthClient.identifier == request.GET.get('client_id')).first() - - if not client: - return json_response({ - 'status': 400, - 'errors': [u'No such client identifier']}, - _disable_cors=True) - - return controller(request, client) - - return wrapper - - -def create_token(client, user): - ''' - Create an OAuthToken and an OAuthRefreshToken entry in the database - - Returns the data structure expected by the OAuth clients. - ''' - from mediagoblin.plugins.oauth.models import OAuthToken, OAuthRefreshToken - - token = OAuthToken() - token.user = user - token.client = client - token.save() - - refresh_token = OAuthRefreshToken() - refresh_token.user = user - refresh_token.client = client - refresh_token.save() - - # expire time of token in full seconds - # timedelta.total_seconds is python >= 2.7 or we would use that - td = token.expires - datetime.now() - exp_in = 86400*td.days + td.seconds # just ignore µsec - - return {'access_token': token.token, 'token_type': 'bearer', - 'refresh_token': refresh_token.token, 'expires_in': exp_in} - - -def generate_identifier(): - ''' Generates a ``uuid.uuid4()`` ''' - return unicode(uuid.uuid4()) - - -def generate_token(): - ''' Uses generate_identifier ''' - return generate_identifier() - - -def generate_refresh_token(): - ''' Uses generate_identifier ''' - return generate_identifier() - - -def generate_code(): - ''' Uses generate_identifier ''' - return generate_identifier() - - -def generate_secret(): - ''' - Generate a long string of pseudo-random characters - ''' - # XXX: We might not want it to use bcrypt, since bcrypt takes its time to - # generate the result. - return unicode(getrandbits(192)) - diff --git a/mediagoblin/plugins/oauth/views.py b/mediagoblin/plugins/oauth/views.py deleted file mode 100644 index de637d6b..00000000 --- a/mediagoblin/plugins/oauth/views.py +++ /dev/null @@ -1,253 +0,0 @@ -# -*- coding: utf-8 -*- -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import logging - -from urllib import urlencode - -from werkzeug.exceptions import BadRequest - -from mediagoblin.tools.response import render_to_response, redirect, json_response -from mediagoblin.decorators import require_active_login -from mediagoblin.messages import add_message, SUCCESS -from mediagoblin.tools.translate import pass_to_ugettext as _ -from mediagoblin.plugins.oauth.models import OAuthCode, OAuthClient, \ - OAuthUserClient, OAuthRefreshToken -from mediagoblin.plugins.oauth.forms import ClientRegistrationForm, \ - AuthorizationForm -from mediagoblin.plugins.oauth.tools import require_client_auth, \ - create_token - -_log = logging.getLogger(__name__) - - -@require_active_login -def register_client(request): - ''' - Register an OAuth client - ''' - form = ClientRegistrationForm(request.form) - - if request.method == 'POST' and form.validate(): - client = OAuthClient() - client.name = unicode(form.name.data) - client.description = unicode(form.description.data) - client.type = unicode(form.type.data) - client.owner_id = request.user.id - client.redirect_uri = unicode(form.redirect_uri.data) - - client.save() - - add_message(request, SUCCESS, _('The client {0} has been registered!')\ - .format( - client.name)) - - return redirect(request, 'mediagoblin.plugins.oauth.list_clients') - - return render_to_response( - request, - 'oauth/client/register.html', - {'form': form}) - - -@require_active_login -def list_clients(request): - clients = request.db.OAuthClient.query.filter( - OAuthClient.owner_id == request.user.id).all() - return render_to_response(request, 'oauth/client/list.html', - {'clients': clients}) - - -@require_active_login -def list_connections(request): - connections = OAuthUserClient.query.filter( - OAuthUserClient.user == request.user).all() - return render_to_response(request, 'oauth/client/connections.html', - {'connections': connections}) - - -@require_active_login -def authorize_client(request): - form = AuthorizationForm(request.form) - - client = OAuthClient.query.filter(OAuthClient.id == - form.client_id.data).first() - - if not client: - _log.error('No such client id as received from client authorization \ -form.') - raise BadRequest() - - if form.validate(): - relation = OAuthUserClient() - relation.user_id = request.user.id - relation.client_id = form.client_id.data - if form.allow.data: - relation.state = u'approved' - elif form.deny.data: - relation.state = u'rejected' - else: - raise BadRequest() - - relation.save() - - return redirect(request, location=form.next.data) - - return render_to_response( - request, - 'oauth/authorize.html', - {'form': form, - 'client': client}) - - -@require_client_auth -@require_active_login -def authorize(request, client): - # TODO: Get rid of the JSON responses in this view, it's called by the - # user-agent, not the client. - user_client_relation = OAuthUserClient.query.filter( - (OAuthUserClient.user == request.user) - & (OAuthUserClient.client == client)) - - if user_client_relation.filter(OAuthUserClient.state == - u'approved').count(): - redirect_uri = None - - if client.type == u'public': - if not client.redirect_uri: - return json_response({ - 'status': 400, - 'errors': - [u'Public clients should have a redirect_uri pre-set.']}, - _disable_cors=True) - - redirect_uri = client.redirect_uri - - if client.type == u'confidential': - redirect_uri = request.GET.get('redirect_uri', client.redirect_uri) - if not redirect_uri: - return json_response({ - 'status': 400, - 'errors': [u'No redirect_uri supplied!']}, - _disable_cors=True) - - code = OAuthCode() - code.user = request.user - code.client = client - code.save() - - redirect_uri = ''.join([ - redirect_uri, - '?', - urlencode({'code': code.code})]) - - _log.debug('Redirecting to {0}'.format(redirect_uri)) - - return redirect(request, location=redirect_uri) - else: - # Show prompt to allow client to access data - # - on accept: send the user agent back to the redirect_uri with the - # code parameter - # - on deny: send the user agent back to the redirect uri with error - # information - form = AuthorizationForm(request.form) - form.client_id.data = client.id - form.next.data = request.url - return render_to_response( - request, - 'oauth/authorize.html', - {'form': form, - 'client': client}) - - -def access_token(request): - ''' - Access token endpoint provides access tokens to any clients that have the - right grants/credentials - ''' - - client = None - user = None - - if request.GET.get('code'): - # Validate the code arg, then get the client object from the db. - code = OAuthCode.query.filter(OAuthCode.code == - request.GET.get('code')).first() - - if not code: - return json_response({ - 'error': 'invalid_request', - 'error_description': - 'Invalid code.'}) - - client = code.client - user = code.user - - elif request.args.get('refresh_token'): - # Validate a refresh token, then get the client object from the db. - refresh_token = OAuthRefreshToken.query.filter( - OAuthRefreshToken.token == - request.args.get('refresh_token')).first() - - if not refresh_token: - return json_response({ - 'error': 'invalid_request', - 'error_description': - 'Invalid refresh token.'}) - - client = refresh_token.client - user = refresh_token.user - - if client: - client_identifier = request.GET.get('client_id') - - if not client_identifier: - return json_response({ - 'error': 'invalid_request', - 'error_description': - 'Missing client_id in request.'}) - - if not client_identifier == client.identifier: - return json_response({ - 'error': 'invalid_client', - 'error_description': - 'Mismatching client credentials.'}) - - if client.type == u'confidential': - client_secret = request.GET.get('client_secret') - - if not client_secret: - return json_response({ - 'error': 'invalid_request', - 'error_description': - 'Missing client_secret in request.'}) - - if not client_secret == client.secret: - return json_response({ - 'error': 'invalid_client', - 'error_description': - 'Mismatching client credentials.'}) - - - access_token_data = create_token(client, user) - - return json_response(access_token_data, _disable_cors=True) - - return json_response({ - 'error': 'invalid_request', - 'error_description': - 'Missing `code` or `refresh_token` parameter in request.'}) diff --git a/mediagoblin/plugins/openid/forms.py b/mediagoblin/plugins/openid/forms.py index d47369dc..6dfde0c8 100644 --- a/mediagoblin/plugins/openid/forms.py +++ b/mediagoblin/plugins/openid/forms.py @@ -23,18 +23,18 @@ class RegistrationForm(wtforms.Form): openid = wtforms.HiddenField( '', [wtforms.validators.InputRequired()]) - username = wtforms.TextField( + username = wtforms.StringField( _('Username'), [wtforms.validators.InputRequired(), normalize_user_or_email_field(allow_email=False)]) - email = wtforms.TextField( + email = wtforms.StringField( _('Email address'), [wtforms.validators.InputRequired(), normalize_user_or_email_field(allow_user=False)]) class LoginForm(wtforms.Form): - openid = wtforms.TextField( + openid = wtforms.StringField( _('OpenID'), [wtforms.validators.InputRequired(), # Can openid's only be urls? diff --git a/mediagoblin/plugins/openid/store.py b/mediagoblin/plugins/openid/store.py index 8f9a7012..24726814 100644 --- a/mediagoblin/plugins/openid/store.py +++ b/mediagoblin/plugins/openid/store.py @@ -16,6 +16,8 @@ import base64 import time +import six + from openid.association import Association as OIDAssociation from openid.store.interface import OpenIDStore from openid.store import nonce @@ -34,12 +36,12 @@ class SQLAlchemyOpenIDStore(OpenIDStore): if not assoc: assoc = Association() - assoc.server_url = unicode(server_url) + assoc.server_url = six.text_type(server_url) assoc.handle = association.handle # django uses base64 encoding, python-openid uses a blob field for # secret - assoc.secret = unicode(base64.encodestring(association.secret)) + assoc.secret = six.text_type(base64.encodestring(association.secret)) assoc.issued = association.issued assoc.lifetime = association.lifetime assoc.assoc_type = association.assoc_type diff --git a/mediagoblin/plugins/openid/views.py b/mediagoblin/plugins/openid/views.py index bb2de7ab..71f444fa 100644 --- a/mediagoblin/plugins/openid/views.py +++ b/mediagoblin/plugins/openid/views.py @@ -13,6 +13,9 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. + +import six + from openid.consumer import consumer from openid.consumer.discover import DiscoveryFailure from openid.extensions.sreg import SRegRequest, SRegResponse @@ -186,7 +189,7 @@ def finish_login(request): if user: # Set up login in session - request.session['user_id'] = unicode(user.id) + request.session['user_id'] = six.text_type(user.id) request.session.save() if request.session.get('next'): diff --git a/mediagoblin/plugins/persona/forms.py b/mediagoblin/plugins/persona/forms.py index 7d632344..f74d97fa 100644 --- a/mediagoblin/plugins/persona/forms.py +++ b/mediagoblin/plugins/persona/forms.py @@ -20,11 +20,11 @@ from mediagoblin.auth.tools import normalize_user_or_email_field class RegistrationForm(wtforms.Form): - username = wtforms.TextField( + username = wtforms.StringField( _('Username'), [wtforms.validators.InputRequired(), normalize_user_or_email_field(allow_email=False)]) - email = wtforms.TextField( + email = wtforms.StringField( _('Email address'), [wtforms.validators.InputRequired(), normalize_user_or_email_field(allow_user=False)]) @@ -35,7 +35,7 @@ class RegistrationForm(wtforms.Form): class EditForm(wtforms.Form): - email = wtforms.TextField( + email = wtforms.StringField( _('Email address'), [wtforms.validators.InputRequired(), normalize_user_or_email_field(allow_user=False)]) diff --git a/mediagoblin/plugins/persona/views.py b/mediagoblin/plugins/persona/views.py index 1bba3b8c..41d38353 100644 --- a/mediagoblin/plugins/persona/views.py +++ b/mediagoblin/plugins/persona/views.py @@ -17,6 +17,8 @@ import json import logging import requests +import six + from werkzeug.exceptions import BadRequest from mediagoblin import messages, mg_globals @@ -63,7 +65,7 @@ def login(request): user = query.user if query else None if user: - request.session['user_id'] = unicode(user.id) + request.session['user_id'] = six.text_type(user.id) request.session['persona_login_email'] = email request.session.save() diff --git a/mediagoblin/plugins/piwigo/forms.py b/mediagoblin/plugins/piwigo/forms.py index fd545a3e..b501562b 100644 --- a/mediagoblin/plugins/piwigo/forms.py +++ b/mediagoblin/plugins/piwigo/forms.py @@ -20,10 +20,10 @@ import wtforms class AddSimpleForm(wtforms.Form): image = wtforms.FileField() - name = wtforms.TextField( + name = wtforms.StringField( validators=[wtforms.validators.Length(min=0, max=500)]) - comment = wtforms.TextField() - # tags = wtforms.FieldList(wtforms.TextField()) + comment = wtforms.StringField() + # tags = wtforms.FieldList(wtforms.StringField()) category = wtforms.IntegerField() level = wtforms.IntegerField() @@ -32,13 +32,13 @@ _md5_validator = wtforms.validators.Regexp(r"^[0-9a-fA-F]{32}$") class AddForm(wtforms.Form): - original_sum = wtforms.TextField(None, + original_sum = wtforms.StringField(None, [_md5_validator, wtforms.validators.InputRequired()]) - thumbnail_sum = wtforms.TextField(None, + thumbnail_sum = wtforms.StringField(None, [wtforms.validators.Optional(), _md5_validator]) - file_sum = wtforms.TextField(None, [_md5_validator]) - name = wtforms.TextField() - date_creation = wtforms.TextField() - categories = wtforms.TextField() + file_sum = wtforms.StringField(None, [_md5_validator]) + name = wtforms.StringField() + date_creation = wtforms.StringField() + categories = wtforms.StringField() diff --git a/mediagoblin/plugins/piwigo/tools.py b/mediagoblin/plugins/piwigo/tools.py index 484ea531..7b9b7af3 100644 --- a/mediagoblin/plugins/piwigo/tools.py +++ b/mediagoblin/plugins/piwigo/tools.py @@ -47,7 +47,7 @@ class PwgNamedArray(list): def _fill_element_dict(el, data, as_attr=()): - for k, v in data.iteritems(): + for k, v in six.iteritems(data): if k in as_attr: if not isinstance(v, six.string_types): v = str(v) diff --git a/mediagoblin/plugins/piwigo/views.py b/mediagoblin/plugins/piwigo/views.py index f913a730..1fe1e576 100644 --- a/mediagoblin/plugins/piwigo/views.py +++ b/mediagoblin/plugins/piwigo/views.py @@ -17,6 +17,8 @@ import logging import re +import six + from werkzeug.exceptions import MethodNotAllowed, BadRequest, NotImplemented from werkzeug.wrappers import BaseResponse @@ -133,8 +135,8 @@ def pwg_images_addSimple(request): mg_app=request.app, user=request.user, submitted_file=request.files['image'], filename=request.files['image'].filename, - title=unicode(form.name.data), - description=unicode(form.comment.data), + title=six.text_type(form.name.data), + description=six.text_type(form.comment.data), upload_limit=upload_limit, max_file_size=max_file_size) collection_id = form.category.data |