Commit | Line | Data |
---|---|---|
7cb7653c RE |
1 | # GNU MediaGoblin -- federated, autonomous media hosting |
2 | # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. | |
3 | # | |
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. | |
8 | # | |
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. | |
13 | # | |
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/>. | |
16 | ||
744f1c83 | 17 | import logging |
1d321f1c | 18 | |
7cb7653c RE |
19 | import wtforms |
20 | ||
92783bc1 | 21 | from mediagoblin import mg_globals |
310a44d5 RE |
22 | from mediagoblin.db.models import User |
23 | from mediagoblin.tools.mail import (normalize_email, send_email, | |
24 | email_debug_message) | |
7cb7653c | 25 | from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ |
c3e3882e | 26 | from mediagoblin.tools.template import render_template |
744f1c83 | 27 | from mediagoblin.tools.pluginapi import hook_handle |
c3e3882e | 28 | from mediagoblin import auth |
bcd10ad6 RE |
29 | |
30 | _log = logging.getLogger(__name__) | |
744f1c83 RE |
31 | |
32 | _log = logging.getLogger(__name__) | |
7cb7653c | 33 | |
117a27a3 RE |
34 | _log = logging.getLogger(__name__) |
35 | ||
7cb7653c RE |
36 | |
37 | def normalize_user_or_email_field(allow_email=True, allow_user=True): | |
38 | """ | |
39 | Check if we were passed a field that matches a username and/or email | |
40 | pattern. | |
41 | ||
42 | This is useful for fields that can take either a username or email | |
43 | address. Use the parameters if you want to only allow a username for | |
44 | instance""" | |
45 | message = _(u'Invalid User name or email address.') | |
46 | nomail_msg = _(u"This field does not take email addresses.") | |
47 | nouser_msg = _(u"This field requires an email address.") | |
48 | ||
49 | def _normalize_field(form, field): | |
50 | email = u'@' in field.data | |
51 | if email: # normalize email address casing | |
52 | if not allow_email: | |
53 | raise wtforms.ValidationError(nomail_msg) | |
54 | wtforms.validators.Email()(form, field) | |
55 | field.data = normalize_email(field.data) | |
56 | else: # lower case user names | |
57 | if not allow_user: | |
58 | raise wtforms.ValidationError(nouser_msg) | |
59 | wtforms.validators.Length(min=3, max=30)(form, field) | |
60 | wtforms.validators.Regexp(r'^\w+$')(form, field) | |
61 | field.data = field.data.lower() | |
62 | if field.data is None: # should not happen, but be cautious anyway | |
63 | raise wtforms.ValidationError(message) | |
64 | return _normalize_field | |
744f1c83 RE |
65 | |
66 | ||
f644293e RE |
67 | class AuthError(Exception): |
68 | def __init__(self): | |
69 | self.value = 'No Authentication Plugin is enabled and no_auth = false'\ | |
70 | ' in config!' | |
71 | ||
72 | def __str__(self): | |
73 | return repr(self.value) | |
74 | ||
75 | ||
744f1c83 RE |
76 | def check_auth_enabled(): |
77 | no_auth = mg_globals.app_config['no_auth'] | |
c3e3882e | 78 | auth_plugin = hook_handle('authentication') |
744f1c83 RE |
79 | |
80 | if no_auth == 'false' and not auth_plugin: | |
f644293e | 81 | raise AuthError |
744f1c83 RE |
82 | |
83 | if no_auth == 'true' and not auth_plugin: | |
84 | _log.warning('No authentication is enabled') | |
85 | return False | |
86 | else: | |
87 | return True | |
c9dec8b3 RE |
88 | |
89 | ||
90 | def no_auth_logout(request): | |
91 | """Log out the user if in no_auth mode""" | |
92 | if not mg_globals.app.auth: | |
93 | request.session.delete() | |
c3e3882e RE |
94 | |
95 | ||
92783bc1 RE |
96 | EMAIL_VERIFICATION_TEMPLATE = ( |
97 | u"http://{host}{uri}?" | |
98 | u"userid={userid}&token={verification_key}") | |
99 | ||
100 | ||
101 | def send_verification_email(user, request): | |
102 | """ | |
103 | Send the verification email to users to activate their accounts. | |
104 | ||
105 | Args: | |
106 | - user: a user object | |
107 | - request: the request | |
108 | """ | |
109 | rendered_email = render_template( | |
110 | request, 'mediagoblin/auth/verification_email.txt', | |
111 | {'username': user.username, | |
112 | 'verification_url': EMAIL_VERIFICATION_TEMPLATE.format( | |
113 | host=request.host, | |
114 | uri=request.urlgen('mediagoblin.auth.verify_email'), | |
115 | userid=unicode(user.id), | |
116 | verification_key=user.verification_key)}) | |
117 | ||
118 | # TODO: There is no error handling in place | |
119 | send_email( | |
120 | mg_globals.app_config['email_sender_address'], | |
121 | [user.email], | |
122 | # TODO | |
123 | # Due to the distributed nature of GNU MediaGoblin, we should | |
124 | # find a way to send some additional information about the | |
125 | # specific GNU MediaGoblin instance in the subject line. For | |
126 | # example "GNU MediaGoblin @ Wandborg - [...]". | |
127 | 'GNU MediaGoblin - Verify your email!', | |
128 | rendered_email) | |
310a44d5 RE |
129 | |
130 | ||
f855efff RE |
131 | EMAIL_FP_VERIFICATION_TEMPLATE = ( |
132 | u"http://{host}{uri}?" | |
133 | u"userid={userid}&token={fp_verification_key}") | |
134 | ||
135 | ||
136 | def send_fp_verification_email(user, request): | |
137 | """ | |
138 | Send the verification email to users to change their password. | |
139 | ||
140 | Args: | |
141 | - user: a user object | |
142 | - request: the request | |
143 | """ | |
144 | rendered_email = render_template( | |
145 | request, 'mediagoblin/auth/fp_verification_email.txt', | |
146 | {'username': user.username, | |
147 | 'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE.format( | |
148 | host=request.host, | |
149 | uri=request.urlgen('mediagoblin.auth.verify_forgot_password'), | |
150 | userid=unicode(user.id), | |
151 | fp_verification_key=user.fp_verification_key)}) | |
152 | ||
153 | # TODO: There is no error handling in place | |
154 | send_email( | |
155 | mg_globals.app_config['email_sender_address'], | |
156 | [user.email], | |
157 | 'GNU MediaGoblin - Change forgotten password!', | |
158 | rendered_email) | |
159 | ||
160 | ||
c3e3882e RE |
161 | def basic_extra_validation(register_form, *args): |
162 | users_with_username = User.query.filter_by( | |
569873d8 | 163 | username=register_form.username.data).count() |
c3e3882e | 164 | users_with_email = User.query.filter_by( |
569873d8 | 165 | email=register_form.email.data).count() |
c3e3882e RE |
166 | |
167 | extra_validation_passes = True | |
168 | ||
169 | if users_with_username: | |
170 | register_form.username.errors.append( | |
171 | _(u'Sorry, a user with that name already exists.')) | |
172 | extra_validation_passes = False | |
173 | if users_with_email: | |
174 | register_form.email.errors.append( | |
175 | _(u'Sorry, a user with that email address already exists.')) | |
176 | extra_validation_passes = False | |
177 | ||
178 | return extra_validation_passes | |
179 | ||
180 | ||
5784c12d RE |
181 | def register_user(request, register_form): |
182 | """ Handle user registration """ | |
183 | extra_validation_passes = auth.extra_validation(register_form) | |
184 | ||
185 | if extra_validation_passes: | |
186 | # Create the user | |
187 | user = auth.create_user(register_form) | |
188 | ||
189 | # log the user in | |
190 | request.session['user_id'] = unicode(user.id) | |
191 | request.session.save() | |
192 | ||
193 | # send verification email | |
194 | email_debug_message(request) | |
195 | send_verification_email(user, request) | |
196 | return user | |
197 | ||
198 | return None | |
199 | ||
200 | ||
f81206df | 201 | def check_login_simple(username, password): |
cdc6b571 | 202 | user = auth.get_user(username) |
1d321f1c RE |
203 | if not user: |
204 | _log.info("User %r not found", username) | |
cdc6b571 | 205 | auth.fake_login_attempt() |
1d321f1c | 206 | return None |
cdc6b571 | 207 | if not auth.check_password(password, user.pw_hash): |
1d321f1c RE |
208 | _log.warn("Wrong password for %r", username) |
209 | return None | |
210 | _log.info("Logging %r in", username) | |
211 | return user |