1# Copyright (c) 2012-2016 Seafile Ltd.
2from seahub.two_factor.models.base import Device, get_available_methods
3from seahub.two_factor.models.totp import TOTPDevice
4from seahub.two_factor.models.phone import PhoneDevice
5from seahub.two_factor.models.static import StaticDevice, StaticToken
6
7def devices_for_user(user):
8    """
9    Return an iterable of all devices registered to the given user.
10
11    Returns an empty iterable for anonymous users.
12
13    :param user: standard or custom user object.
14    :type user: :class:`~seahub.auth.models.User`
15
16    :rtype: iterable
17    """
18    if user.is_anonymous:
19        return
20
21    for model in TOTPDevice, PhoneDevice, StaticDevice:
22        device = model.objects.device_for_user(user.username)
23        if device:
24            yield device
25
26def user_has_device(user):
27    """
28    Return ``True`` if the user has at least one device.
29
30    Returns ``False`` for anonymous users.
31
32    :param user: standard or custom user object.
33    :type user: :class:`~seahub.auth.models.User`
34
35    """
36    try:
37        next(devices_for_user(user))
38    except StopIteration:
39        has_device = False
40    else:
41        has_device = True
42
43    return has_device
44
45def default_device(user):
46    if not user or user.is_anonymous:
47        return
48
49    for device in devices_for_user(user):
50        if device:
51            return device
52
53def match_token(user, token):
54    """
55    Attempts to verify a :term:`token` on every device attached to the given
56    user until one of them succeeds. When possible, you should prefer to verify
57    tokens against specific devices.
58
59    :param user: The user supplying the token.
60    :type user: :class:`~django.contrib.auth.models.User`
61
62    :param string token: An OTP token to verify.
63
64    :returns: The device that accepted ``token``, if any.
65    :rtype: :class:`~django_otp.models.Device` or ``None``
66    """
67    matches = (d for d in devices_for_user(user) if d.verify_token(token))
68
69    return next(matches, None)
70
71########## handle signals
72from django.dispatch import receiver
73from seahub.auth.signals import user_logged_in
74from seahub.two_factor import login
75
76@receiver(user_logged_in)
77def _handle_auth_login(sender, request, user, **kwargs):
78    """
79    Automatically persists an OTP device that was set by an OTP-aware
80    AuthenticationForm.
81    """
82    if hasattr(user, 'otp_device'):
83        login(request, user.otp_device)
84