1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 from sqlalchemy
import or_
22 from mediagoblin
import mg_globals
23 from mediagoblin
.db
.models
import User
24 from mediagoblin
.tools
.mail
import (normalize_email
, send_email
,
26 from mediagoblin
.tools
.translate
import lazy_pass_to_ugettext
as _
27 from mediagoblin
.tools
.template
import render_template
28 from mediagoblin
.tools
.pluginapi
import hook_handle
29 from mediagoblin
import auth
31 _log
= logging
.getLogger(__name__
)
33 _log
= logging
.getLogger(__name__
)
35 _log
= logging
.getLogger(__name__
)
37 _log
= logging
.getLogger(__name__
)
40 def normalize_user_or_email_field(allow_email
=True, allow_user
=True):
42 Check if we were passed a field that matches a username and/or email
45 This is useful for fields that can take either a username or email
46 address. Use the parameters if you want to only allow a username for
48 message
= _(u
'Invalid User name or email address.')
49 nomail_msg
= _(u
"This field does not take email addresses.")
50 nouser_msg
= _(u
"This field requires an email address.")
52 def _normalize_field(form
, field
):
53 email
= u
'@' in field
.data
54 if email
: # normalize email address casing
56 raise wtforms
.ValidationError(nomail_msg
)
57 wtforms
.validators
.Email()(form
, field
)
58 field
.data
= normalize_email(field
.data
)
59 else: # lower case user names
61 raise wtforms
.ValidationError(nouser_msg
)
62 wtforms
.validators
.Length(min=3, max=30)(form
, field
)
63 wtforms
.validators
.Regexp(r
'^\w+$')(form
, field
)
64 field
.data
= field
.data
.lower()
65 if field
.data
is None: # should not happen, but be cautious anyway
66 raise wtforms
.ValidationError(message
)
67 return _normalize_field
70 class AuthError(Exception):
72 self
.value
= 'No Authentication Plugin is enabled and no_auth = false'\
76 return repr(self
.value
)
79 def check_auth_enabled():
80 no_auth
= mg_globals
.app_config
['no_auth']
81 auth_plugin
= hook_handle('authentication')
83 if no_auth
== 'false' and not auth_plugin
:
86 if no_auth
== 'true' and not auth_plugin
:
87 _log
.warning('No authentication is enabled')
93 def no_auth_logout(request
):
94 """Log out the user if in no_auth mode"""
95 if not mg_globals
.app
.auth
:
96 request
.session
.delete()
99 EMAIL_VERIFICATION_TEMPLATE
= (
100 u
"http://{host}{uri}?"
101 u
"userid={userid}&token={verification_key}")
104 def send_verification_email(user
, request
):
106 Send the verification email to users to activate their accounts.
109 - user: a user object
110 - request: the request
112 rendered_email
= render_template(
113 request
, 'mediagoblin/auth/verification_email.txt',
114 {'username': user
.username
,
115 'verification_url': EMAIL_VERIFICATION_TEMPLATE
.format(
117 uri
=request
.urlgen('mediagoblin.auth.verify_email'),
118 userid
=unicode(user
.id),
119 verification_key
=user
.verification_key
)})
121 # TODO: There is no error handling in place
123 mg_globals
.app_config
['email_sender_address'],
126 # Due to the distributed nature of GNU MediaGoblin, we should
127 # find a way to send some additional information about the
128 # specific GNU MediaGoblin instance in the subject line. For
129 # example "GNU MediaGoblin @ Wandborg - [...]".
130 'GNU MediaGoblin - Verify your email!',
134 EMAIL_FP_VERIFICATION_TEMPLATE
= (
135 u
"http://{host}{uri}?"
136 u
"userid={userid}&token={fp_verification_key}")
139 def send_fp_verification_email(user
, request
):
141 Send the verification email to users to change their password.
144 - user: a user object
145 - request: the request
147 rendered_email
= render_template(
148 request
, 'mediagoblin/auth/fp_verification_email.txt',
149 {'username': user
.username
,
150 'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE
.format(
152 uri
=request
.urlgen('mediagoblin.auth.verify_forgot_password'),
153 userid
=unicode(user
.id),
154 fp_verification_key
=user
.fp_verification_key
)})
156 # TODO: There is no error handling in place
158 mg_globals
.app_config
['email_sender_address'],
160 'GNU MediaGoblin - Change forgotten password!',
164 def basic_extra_validation(register_form
, *args
):
165 users_with_username
= User
.query
.filter_by(
166 username
=register_form
.username
.data
).count()
167 users_with_email
= User
.query
.filter_by(
168 email
=register_form
.email
.data
).count()
170 extra_validation_passes
= True
172 if users_with_username
:
173 register_form
.username
.errors
.append(
174 _(u
'Sorry, a user with that name already exists.'))
175 extra_validation_passes
= False
177 register_form
.email
.errors
.append(
178 _(u
'Sorry, a user with that email address already exists.'))
179 extra_validation_passes
= False
181 return extra_validation_passes
184 def register_user(request
, register_form
):
185 """ Handle user registration """
186 extra_validation_passes
= auth
.extra_validation(register_form
)
188 if extra_validation_passes
:
190 user
= auth
.create_user(register_form
)
193 request
.session
['user_id'] = unicode(user
.id)
194 request
.session
.save()
196 # send verification email
197 email_debug_message(request
)
198 send_verification_email(user
, request
)
205 def check_login_simple(username
, password
):
206 user
= auth
.get_user(username
=username
)
208 _log
.info("User %r not found", username
)
209 auth
.fake_login_attempt()
211 if not auth
.check_password(password
, user
.pw_hash
):
212 _log
.warn("Wrong password for %r", username
)
214 _log
.info("Logging %r in", username
)