]> git.ipfire.org Git - ipfire.org.git/blob - src/web/people.py
people: Check password quality before submitting to server
[ipfire.org.git] / src / web / people.py
1 #!/usr/bin/python
2
3 import datetime
4 import ldap
5 import logging
6 import sshpubkeys
7 import tornado.web
8
9 from . import handlers_base as base
10 from . import ui_modules
11
12 class IndexHandler(base.BaseHandler):
13 @tornado.web.authenticated
14 def get(self):
15 self.render("people/index.html")
16
17
18 class AvatarHandler(base.BaseHandler):
19 always_cache = True
20
21 def get(self, uid):
22 # Get the desired size of the avatar file
23 size = self.get_argument("size", 0)
24
25 try:
26 size = int(size)
27 except (TypeError, ValueError):
28 size = None
29
30 logging.debug("Querying for avatar of %s" % uid)
31
32 # Fetch user account
33 account = self.backend.accounts.get_by_uid(uid)
34 if not account:
35 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
36
37 # Allow downstream to cache this for 60 minutes
38 self.set_expires(3600)
39
40 # Resize avatar
41 avatar = account.get_avatar(size)
42
43 # If there is no avatar, we serve a default image
44 if not avatar:
45 logging.debug("No avatar uploaded for %s" % account)
46
47 return self.redirect(self.static_url("img/default-avatar.jpg"))
48
49 # Set headers about content
50 self.set_header("Content-Disposition", "inline; filename=\"%s.jpg\"" % account.uid)
51 self.set_header("Content-Type", "image/jpeg")
52
53 # Deliver payload
54 self.finish(avatar)
55
56
57 class CallsHandler(base.BaseHandler):
58 @tornado.web.authenticated
59 def get(self, uid, date=None):
60 account = self.backend.accounts.get_by_uid(uid)
61 if not account:
62 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
63
64 if date:
65 try:
66 date = datetime.datetime.strptime(date, "%Y-%m-%d").date()
67 except ValueError:
68 raise tornado.web.HTTPError(400, "Invalid date: %s" % date)
69 else:
70 date = datetime.date.today()
71
72 self.render("people/calls.html", account=account, date=date)
73
74
75 class CallHandler(base.BaseHandler):
76 @tornado.web.authenticated
77 def get(self, uid, uuid):
78 account = self.backend.accounts.get_by_uid(uid)
79 if not account:
80 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
81
82 call = self.backend.talk.freeswitch.get_call_by_uuid(uuid)
83 if not call:
84 raise tornado.web.HTTPError(404, "Could not find call %s" % uuid)
85
86 # XXX limit
87
88 self.render("people/call.html", account=account, call=call)
89
90
91 class ConferencesHandler(base.BaseHandler):
92 @tornado.web.authenticated
93 def get(self):
94 self.render("people/conferences.html", conferences=self.backend.talk.conferences)
95
96
97 class SearchHandler(base.BaseHandler):
98 @tornado.web.authenticated
99 def get(self):
100 q = self.get_argument("q")
101
102 # Perform the search
103 accounts = self.backend.accounts.search(q)
104
105 # Redirect when only one result was found
106 if len(accounts) == 1:
107 self.redirect("/users/%s" % accounts[0].uid)
108 return
109
110 self.render("people/search.html", q=q, accounts=accounts)
111
112
113 class SSHKeysIndexHandler(base.BaseHandler):
114 @tornado.web.authenticated
115 def get(self, uid):
116 account = self.backend.accounts.get_by_uid(uid)
117 if not account:
118 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
119
120 self.render("people/ssh-keys/index.html", account=account)
121
122
123 class SSHKeysDownloadHandler(base.BaseHandler):
124 @tornado.web.authenticated
125 def get(self, uid, hash_sha256):
126 account = self.backend.accounts.get_by_uid(uid)
127 if not account:
128 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
129
130 # Get SSH key
131 key = account.get_ssh_key_by_hash_sha256(hash_sha256)
132 if not key:
133 raise tornado.web.HTTPError(404, "Could not find key: %s" % hash_sha256)
134
135 # Set HTTP Headers
136 self.add_header("Content-Type", "text/plain")
137
138 self.finish(key.keydata)
139
140
141 class SSHKeysUploadHandler(base.BaseHandler):
142 @tornado.web.authenticated
143 def get(self, uid):
144 account = self.backend.accounts.get_by_uid(uid)
145 if not account:
146 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
147
148 # Check for permissions
149 if not account.can_be_managed_by(self.current_user):
150 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
151
152 self.render("people/ssh-keys/upload.html", account=account)
153
154 @tornado.web.authenticated
155 def post(self, uid):
156 account = self.backend.accounts.get_by_uid(uid)
157 if not account:
158 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
159
160 # Check for permissions
161 if not account.can_be_managed_by(self.current_user):
162 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
163
164 key = self.get_argument("key")
165
166 # Verify password
167 password = self.get_argument("password")
168 if not account.check_password(password):
169 raise tornado.web.HTTPError(403, "Incorrect password for %s" % account)
170
171 # Try to add new SSH key
172 try:
173 account.add_ssh_key(key)
174
175 except sshpubkeys.InvalidKeyException as e:
176 self.render("people/ssh-keys/error-invalid-key.html", account=account, exception=e)
177 return
178
179 self.redirect("/users/%s/ssh-keys" % account.uid)
180
181
182 class SSHKeysDeleteHandler(base.BaseHandler):
183 @tornado.web.authenticated
184 def get(self, uid, hash_sha256):
185 account = self.backend.accounts.get_by_uid(uid)
186 if not account:
187 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
188
189 # Get SSH key
190 key = account.get_ssh_key_by_hash_sha256(hash_sha256)
191 if not key:
192 raise tornado.web.HTTPError(404, "Could not find key: %s" % hash_sha256)
193
194 self.render("people/ssh-keys/delete.html", account=account, key=key)
195
196 @tornado.web.authenticated
197 def post(self, uid, hash_sha256):
198 account = self.backend.accounts.get_by_uid(uid)
199 if not account:
200 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
201
202 # Get SSH key
203 key = account.get_ssh_key_by_hash_sha256(hash_sha256)
204 if not key:
205 raise tornado.web.HTTPError(404, "Could not find key: %s" % hash_sha256)
206
207 # Verify password
208 password = self.get_argument("password")
209 if not account.check_password(password):
210 raise tornado.web.HTTPError(403, "Incorrect password for %s" % account)
211
212 # Delete the key
213 account.delete_ssh_key(key.keydata)
214
215 self.redirect("/users/%s/ssh-keys" % account.uid)
216
217
218 class SIPHandler(base.BaseHandler):
219 @tornado.web.authenticated
220 def get(self, uid):
221 account = self.backend.accounts.get_by_uid(uid)
222 if not account:
223 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
224
225 # Check for permissions
226 if not account.can_be_managed_by(self.current_user):
227 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
228
229 self.render("people/sip.html", account=account)
230
231
232 class UsersHandler(base.BaseHandler):
233 @tornado.web.authenticated
234 def get(self):
235 self.render("people/users.html")
236
237
238 class UserHandler(base.BaseHandler):
239 @tornado.web.authenticated
240 def get(self, uid):
241 account = self.backend.accounts.get_by_uid(uid)
242 if not account:
243 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
244
245 self.render("people/user.html", account=account)
246
247
248 class UserEditHandler(base.BaseHandler):
249 @tornado.web.authenticated
250 def get(self, uid):
251 account = self.backend.accounts.get_by_uid(uid)
252 if not account:
253 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
254
255 # Check for permissions
256 if not account.can_be_managed_by(self.current_user):
257 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
258
259 self.render("people/user-edit.html", account=account)
260
261 @tornado.web.authenticated
262 def post(self, uid):
263 account = self.backend.accounts.get_by_uid(uid)
264 if not account:
265 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
266
267 # Check for permissions
268 if not account.can_be_managed_by(self.current_user):
269 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
270
271 # Unfortunately this cannot be wrapped into a transaction
272 try:
273 account.first_name = self.get_argument("first_name")
274 account.last_name = self.get_argument("last_name")
275 account.address = self.get_argument("address")
276
277 # Avatar
278 try:
279 filename, data, mimetype = self.get_file("avatar")
280
281 if not mimetype.startswith("image/"):
282 raise tornado.web.HTTPError(400, "Avatar is not an image file: %s" % mimetype)
283
284 account.upload_avatar(data)
285 except TypeError:
286 pass
287
288 # Email
289 account.mail_routing_address = self.get_argument("mail_routing_address", None)
290
291 # Telephone
292 account.phone_numbers = self.get_argument("phone_numbers", "").splitlines()
293 account.sip_routing_address = self.get_argument("sip_routing_address", None)
294 except ldap.STRONG_AUTH_REQUIRED as e:
295 raise tornado.web.HTTPError(403, "%s" % e) from e
296
297 # Redirect back to user page
298 self.redirect("/users/%s" % account.uid)
299
300
301 class UserPasswdHandler(base.BaseHandler):
302 @tornado.web.authenticated
303 def get(self, uid):
304 account = self.backend.accounts.get_by_uid(uid)
305 if not account:
306 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
307
308 # Check for permissions
309 if not account.can_be_managed_by(self.current_user):
310 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
311
312 self.render("people/passwd.html", account=account)
313
314 @tornado.web.authenticated
315 def post(self, uid):
316 account = self.backend.accounts.get_by_uid(uid)
317 if not account:
318 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
319
320 # Check for permissions
321 if not account.can_be_managed_by(self.current_user):
322 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
323
324 # Get current password
325 password = self.get_argument("password")
326
327 # Get new password
328 password1 = self.get_argument("password1")
329 password2 = self.get_argument("password2")
330
331 # Passwords must match
332 if not password1 == password2:
333 raise tornado.web.HTTPError(400, "Passwords do not match")
334
335 # XXX Check password complexity
336
337 # Check if old password matches
338 if not account.check_password(password):
339 raise tornado.web.HTTPError(403, "Incorrect password for %s" % account)
340
341 # Save new password
342 account.passwd(password1)
343
344 # Redirect back to user's page
345 self.redirect("/users/%s" % account.uid)
346
347
348 class AccountsListModule(ui_modules.UIModule):
349 def render(self, accounts=None):
350 if accounts is None:
351 accounts = self.backend.accounts
352
353 return self.render_string("people/modules/accounts-list.html", accounts=accounts)
354
355
356 class CDRModule(ui_modules.UIModule):
357 def render(self, account, date=None, limit=None):
358 cdr = account.get_cdr(date=date, limit=limit)
359
360 return self.render_string("people/modules/cdr.html", account=account, cdr=cdr)
361
362
363 class ChannelsModule(ui_modules.UIModule):
364 def render(self, account):
365 return self.render_string("people/modules/channels.html",
366 account=account, channels=account.sip_channels)
367
368
369 class MOSModule(ui_modules.UIModule):
370 def render(self, call):
371 return self.render_string("people/modules/mos.html", call=call)
372
373
374 class PasswordModule(ui_modules.UIModule):
375 def render(self, account):
376 return self.render_string("people/modules/password.html", account=account)
377
378 def javascript_files(self):
379 return "js/zxcvbn.js"
380
381 def embedded_javascript(self):
382 return self.render_string("people/modules/password.js")
383
384
385 class RegistrationsModule(ui_modules.UIModule):
386 def render(self, account):
387 return self.render_string("people/modules/registrations.html", account=account)
388
389
390 class SIPStatusModule(ui_modules.UIModule):
391 def render(self, account):
392 return self.render_string("people/modules/sip-status.html", account=account)