]> git.ipfire.org Git - ipfire.org.git/blob - src/web/people.py
people: Use SHA256 to identify an SSH key
[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 SearchHandler(base.BaseHandler):
92 @tornado.web.authenticated
93 def get(self):
94 q = self.get_argument("q")
95
96 # Perform the search
97 accounts = self.backend.accounts.search(q)
98
99 # Redirect when only one result was found
100 if len(accounts) == 1:
101 self.redirect("/users/%s" % accounts[0].uid)
102 return
103
104 self.render("people/search.html", q=q, accounts=accounts)
105
106
107 class SSHKeysIndexHandler(base.BaseHandler):
108 @tornado.web.authenticated
109 def get(self, uid):
110 account = self.backend.accounts.get_by_uid(uid)
111 if not account:
112 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
113
114 self.render("people/ssh-keys/index.html", account=account)
115
116
117 class SSHKeysDownloadHandler(base.BaseHandler):
118 @tornado.web.authenticated
119 def get(self, uid, hash_sha256):
120 account = self.backend.accounts.get_by_uid(uid)
121 if not account:
122 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
123
124 # Get SSH key
125 key = account.get_ssh_key_by_hash_sha256(hash_sha256)
126 if not key:
127 raise tornado.web.HTTPError(404, "Could not find key: %s" % hash_sha256)
128
129 # Set HTTP Headers
130 self.add_header("Content-Type", "text/plain")
131
132 self.finish(key.keydata)
133
134
135 class SSHKeysUploadHandler(base.BaseHandler):
136 @tornado.web.authenticated
137 def get(self, uid):
138 account = self.backend.accounts.get_by_uid(uid)
139 if not account:
140 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
141
142 # Check for permissions
143 if not account.can_be_managed_by(self.current_user):
144 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
145
146 self.render("people/ssh-keys/upload.html", account=account)
147
148 @tornado.web.authenticated
149 def post(self, uid):
150 account = self.backend.accounts.get_by_uid(uid)
151 if not account:
152 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
153
154 # Check for permissions
155 if not account.can_be_managed_by(self.current_user):
156 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
157
158 key = self.get_argument("key")
159
160 # Verify password
161 password = self.get_argument("password")
162 if not account.check_password(password):
163 raise tornado.web.HTTPError(403, "Incorrect password for %s" % account)
164
165 # Try to add new SSH key
166 try:
167 account.add_ssh_key(key)
168
169 except sshpubkeys.InvalidKeyException as e:
170 self.render("people/ssh-keys/error-invalid-key.html", account=account, exception=e)
171 return
172
173 self.redirect("/users/%s/ssh-keys" % account.uid)
174
175
176 class SSHKeysDeleteHandler(base.BaseHandler):
177 @tornado.web.authenticated
178 def get(self, uid, hash_sha256):
179 account = self.backend.accounts.get_by_uid(uid)
180 if not account:
181 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
182
183 # Get SSH key
184 key = account.get_ssh_key_by_hash_sha256(hash_sha256)
185 if not key:
186 raise tornado.web.HTTPError(404, "Could not find key: %s" % hash_sha256)
187
188 self.render("people/ssh-keys/delete.html", account=account, key=key)
189
190 @tornado.web.authenticated
191 def post(self, uid, hash_sha256):
192 account = self.backend.accounts.get_by_uid(uid)
193 if not account:
194 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
195
196 # Get SSH key
197 key = account.get_ssh_key_by_hash_sha256(hash_sha256)
198 if not key:
199 raise tornado.web.HTTPError(404, "Could not find key: %s" % hash_sha256)
200
201 # Verify password
202 password = self.get_argument("password")
203 if not account.check_password(password):
204 raise tornado.web.HTTPError(403, "Incorrect password for %s" % account)
205
206 # Delete the key
207 account.delete_ssh_key(key.keydata)
208
209 self.redirect("/users/%s/ssh-keys" % account.uid)
210
211
212 class SIPHandler(base.BaseHandler):
213 @tornado.web.authenticated
214 def get(self, uid):
215 account = self.backend.accounts.get_by_uid(uid)
216 if not account:
217 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
218
219 # Check for permissions
220 if not account.can_be_managed_by(self.current_user):
221 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
222
223 self.render("people/sip.html", account=account)
224
225
226 class UsersHandler(base.BaseHandler):
227 @tornado.web.authenticated
228 def get(self):
229 self.render("people/users.html")
230
231
232 class UserHandler(base.BaseHandler):
233 @tornado.web.authenticated
234 def get(self, uid):
235 account = self.backend.accounts.get_by_uid(uid)
236 if not account:
237 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
238
239 self.render("people/user.html", account=account)
240
241
242 class UserEditHandler(base.BaseHandler):
243 @tornado.web.authenticated
244 def get(self, uid):
245 account = self.backend.accounts.get_by_uid(uid)
246 if not account:
247 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
248
249 # Check for permissions
250 if not account.can_be_managed_by(self.current_user):
251 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
252
253 self.render("people/user-edit.html", account=account)
254
255 @tornado.web.authenticated
256 def post(self, uid):
257 account = self.backend.accounts.get_by_uid(uid)
258 if not account:
259 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
260
261 # Check for permissions
262 if not account.can_be_managed_by(self.current_user):
263 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
264
265 # Unfortunately this cannot be wrapped into a transaction
266 try:
267 account.first_name = self.get_argument("first_name")
268 account.last_name = self.get_argument("last_name")
269 account.address = self.get_argument("address")
270
271 # Avatar
272 try:
273 filename, data, mimetype = self.get_file("avatar")
274
275 if not mimetype.startswith("image/"):
276 raise tornado.web.HTTPError(400, "Avatar is not an image file: %s" % mimetype)
277
278 account.upload_avatar(data)
279 except TypeError:
280 pass
281
282 # Email
283 account.mail_routing_address = self.get_argument("mail_routing_address", None)
284
285 # Telephone
286 account.phone_numbers = self.get_argument("phone_numbers", "").splitlines()
287 account.sip_routing_address = self.get_argument("sip_routing_address", None)
288 except ldap.STRONG_AUTH_REQUIRED as e:
289 raise tornado.web.HTTPError(403, "%s" % e) from e
290
291 # Redirect back to user page
292 self.redirect("/users/%s" % account.uid)
293
294
295 class UserPasswdHandler(base.BaseHandler):
296 @tornado.web.authenticated
297 def get(self, uid):
298 account = self.backend.accounts.get_by_uid(uid)
299 if not account:
300 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
301
302 # Check for permissions
303 if not account.can_be_managed_by(self.current_user):
304 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
305
306 self.render("people/passwd.html", account=account)
307
308 @tornado.web.authenticated
309 def post(self, uid):
310 account = self.backend.accounts.get_by_uid(uid)
311 if not account:
312 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
313
314 # Check for permissions
315 if not account.can_be_managed_by(self.current_user):
316 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
317
318 # Get current password
319 password = self.get_argument("password")
320
321 # Get new password
322 password1 = self.get_argument("password1")
323 password2 = self.get_argument("password2")
324
325 # Passwords must match
326 if not password1 == password2:
327 raise tornado.web.HTTPError(400, "Passwords do not match")
328
329 # XXX Check password complexity
330
331 # Check if old password matches
332 if not account.check_password(password):
333 raise tornado.web.HTTPError(403, "Incorrect password for %s" % account)
334
335 # Save new password
336 account.passwd(password1)
337
338 # Redirect back to user's page
339 self.redirect("/users/%s" % account.uid)
340
341
342 class AccountsListModule(ui_modules.UIModule):
343 def render(self, accounts=None):
344 if accounts is None:
345 accounts = self.backend.accounts
346
347 return self.render_string("people/modules/accounts-list.html", accounts=accounts)
348
349
350 class CDRModule(ui_modules.UIModule):
351 def render(self, account, date=None, limit=None):
352 cdr = account.get_cdr(date=date, limit=limit)
353
354 return self.render_string("people/modules/cdr.html", account=account, cdr=cdr)
355
356
357 class ChannelsModule(ui_modules.UIModule):
358 def render(self, account):
359 return self.render_string("people/modules/channels.html",
360 account=account, channels=account.sip_channels)
361
362
363 class MOSModule(ui_modules.UIModule):
364 def render(self, call):
365 return self.render_string("people/modules/mos.html", call=call)
366
367
368 class RegistrationsModule(ui_modules.UIModule):
369 def render(self, account):
370 return self.render_string("people/modules/registrations.html", account=account)
371
372
373 class SIPStatusModule(ui_modules.UIModule):
374 def render(self, account):
375 return self.render_string("people/modules/sip-status.html", account=account)