def create_and_login_user(client):
    username = ''.join(random.choice(string.ascii_uppercase) for _ in range(5))
    user = User.objects.create_user(username=username,
                                    email="{}@example.com".format(username))
    client.force_login(user)
    return user class Notification(models.Model):
    """ These notifications are emails sent to all users (or some subset)
        by an Administrator. Just once.
    """

    subject = models.CharField(
        null=False, blank=False, max_length=150, verbose_name=_('Subject'))
    body = models.TextField(null=False, blank=False, verbose_name=_('Body'))

    created_at = models.DateTimeField(
        auto_now_add=True, verbose_name=_('Created at'))
    updated_at = models.DateTimeField(
        auto_now=True, verbose_name=_('Updated at'))

    sent_at = models.DateTimeField(null=True, verbose_name=_('Sent at'))
    send_to = models.ForeignKey(
        Group, null=True, blank=True, on_delete=models.CASCADE, verbose_name=_('Send to'))

    class Meta:
        verbose_name = _('Notification')
        verbose_name_plural = _('Notifications')

    def __str__(self):
        return self.subject

    def delete(self):
        return super().delete() if not self.sent_at else False class User(AbstractUser):
    """
        Project's base user model
    """
    LANGUAGE_CHOICES = (
        ('en-us', 'English'),
        ('pt-pt', _('Portuguese')),
    )

    organization = models.CharField(
        null=True, blank=True, max_length=80, verbose_name=_('Organization'))
    public_key = models.TextField(
        blank=True, null=True, verbose_name=_('Public key'))
    fingerprint = models.CharField(
        null=True, blank=True, max_length=50, verbose_name=_('Fingerprint'))
    keyserver_url = models.URLField(
        null=True, blank=True, verbose_name=_('Key server URL'))
    timezone = TimeZoneField(default='UTC', verbose_name=_('Timezone'))
    language = models.CharField(
        default="en-us", max_length=16, choices=LANGUAGE_CHOICES, verbose_name=_('Language'))

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.base_fingerprint = self.fingerprint

    def save(self, *args, **kwargs):
        ip = kwargs.pop('ip', None)
        agent = kwargs.pop('agent', '')
        with transaction.atomic():
            super().save(*args, **kwargs)
            if self.base_fingerprint != self.fingerprint:
                self.keychanges.create(user=self,
                                       prev_fingerprint=self.base_fingerprint,
                                       to_fingerprint=self.fingerprint,
                                       ip_address=ip,
                                       agent=agent)
                self.base_fingerprint = self.fingerprint

    def has_setup_complete(self):
        if self.public_key and self.fingerprint:
            return True
        return False

    @property
    def has_github_login(self):
        return self.socialaccount_set.filter(provider='github').count() >= 1

    @property
    def has_public_key(self):
        return True if self.public_key else False

    @property
    def has_keyserver_url(self):
        return True if self.keyserver_url else False class UpdateUserInfoForm(ModelForm):

    class Meta:
        model = User
        fields = [
            "first_name",
            "last_name",
            "organization",
            "keyserver_url",
            "public_key",
            "fingerprint",
            "timezone",
            "language"
        ]

        widgets = {
            'keyserver_url': forms.TextInput(attrs={'placeholder': _("https://example.com/key.asc")}),
            'public_key': forms.Textarea(attrs={'placeholder': _("-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: SKS 1.1.1\n<PGP KEY>\n-----END PGP PUBLIC KEY BLOCK-----")})
        }

    current_password = forms.CharField(label=_('Current password'),
                                       required=False,
                                       widget=forms.PasswordInput)
    new_password1 = forms.CharField(label=_('New password'),
                                    required=False,
                                    widget=forms.PasswordInput)
    new_password2 = forms.CharField(label=_('New password confirmation'),
                                    required=False,
                                    widget=forms.PasswordInput)

    def __init__(self, *args, **kwargs):
        # Flag to let the save method know when to call set_password
        self.change_password = False
        self.pub_key = None
        return super().__init__(*args, **kwargs)

    def save(self, commit=True, **kwargs):
        new_password = self.cleaned_data.get('new_password2')
        if self.change_password:
            self.instance.set_password(new_password)
        self.instance.save(**kwargs)
        return self.instance

    def clean_current_password(self):
        """
        Validates that the current_password field is correct.
        """
        current_password = self.cleaned_data.get('current_password')
        if len(current_password) > 0:
            if not self.instance.check_password(current_password):
                self.add_error('current_password',
                               _('Your current password was entered incorrectly.'))
        return current_password

    def clean_new_password2(self):
        """
        Validates that both new password entries are equal.
        """
        password1 = self.cleaned_data.get('new_password1')
        password2 = self.cleaned_data.get('new_password2')
        if password1 and password2:
            validate_password(password1, self.instance)
            if password1 != password2:
                self.add_error('new_password2',
                               _("The two password fields didn't match."))
            else:
                self.change_password = True
        return password2

    def clean_public_key(self):
        # Validate the public key
        if self.pub_key:
            pub_key = self.pub_key
        else:
            pub_key = self.cleaned_data.get("public_key", "")

        if pub_key:
            fingerprint, *state = key_state(pub_key)
            # Check if has valid format
            if state[0] == "invalid":
                self.add_error('public_key', _('This key is not valid'))
            # Check if it is not expired
            elif state[0] == "revoked":
                self.add_error('public_key', _('This key is revoked'))
            # Check if is was not revoked
            elif state[0] == "expired":
                self.add_error('public_key', _('This key is expired'))
        return pub_key

    def clean_fingerprint(self):
        # Fingerprint provided must match with one provided
        pub_key = self.cleaned_data.get("public_key", "")
        fingerprint = self.cleaned_data.get("fingerprint", "")
        if fingerprint:
            fingerprint = fingerprint.replace(" ", "")
        if pub_key:
            key_fingerprint, *state = key_state(pub_key)
            if fingerprint != key_fingerprint:
                self.add_error('fingerprint', _('Fingerprint does not match'))
        return fingerprint

    def clean_keyserver_url(self):
        url = self.cleaned_data.get("keyserver_url", "")
        if url:
            try:
                res = requests.get(url)
            except:
                self.add_error("keyserver_url",
                               _("Could not access the specified url"))
                return url
            begin = res.text.find("-----BEGIN PGP PUBLIC KEY BLOCK-----")
            end = res.text.find("-----END PGP PUBLIC KEY BLOCK-----")
            if 200 <= res.status_code < 300 and begin >= 0 and end > begin:
                self.pub_key = res.text[begin:end + 34]
            else:
                self.add_error("keyserver_url",
                               _('This url does not have a pgp key'))
        return url @shared_task
def enqueue_email_notifications(notification_id, group_id):
    notification = Notification.objects.get(id=notification_id)
    if group_id:
        users = User.objects.filter(groups__id=group_id)
    else:
        users = User.objects.all()

    for user in users:
        send_email_notification.delay(notification.subject,
                                      notification.body,
                                      user.email) @with_gpg_obj
def key_state(key, gpg):
    INVALID = (None, "invalid", -1)
    if not key:
        return INVALID
    results = gpg.import_keys(key).results
    if not results:
        return INVALID
    # Key data is present in the last element of the list
    key_fingerprint = results[-1].get("fingerprint")
    if not key_fingerprint:
        return INVALID

    # Since the keyring is exclusive for this import
    # only the imported key exists in it.
    key = gpg.list_keys()[0]
    exp_timestamp = int(key["expires"]) if key["expires"] else 0
    expires = datetime.fromtimestamp(exp_timestamp, timezone.utc)
    to_expire = expires - timezone.now()
    days_to_expire = to_expire.days

    if key["trust"] == "r":
        state = "revoked"
    elif exp_timestamp and expires < timezone.now():
        state = "expired"
    else:
        state = "valid"

    return key_fingerprint, state, days_to_expire def with_gpg_obj(func):
    @wraps(func)
    def inner(key):
        # create temp gpg keyring
        temp_dir = tempfile.mkdtemp()
        gpg_obj = gnupg.GPG(homedir=temp_dir,
                            keyring="pub.gpg",
                            secring="sec.gpg")
        gpg_obj.encoding = 'utf-8'
        ret = func(key, gpg_obj)
        # remove the keyring
        rmtree(temp_dir, ignore_errors=True)

        return ret
    return inner VALID_KEY_FINGERPRINT = "3DA4 A7C5 49BF F7EB 17A7 00F8 AD0E 5237 D986 BD75" VALID_KEYSERVER_URL = "http://ha.pool.sks-keyservers.net/pks/lookup?op=get&search=0xAD0E5237D986BD75" EXPIRED_KEY_FINGERPRINT = "84009091C9F92152D34BF0919841A6E703BA514A" REVOKED_KEY = """-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: SKS 1.1.5
Comment: Hostname: pgp.mit.edu

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
=+LpS
-----END PGP PUBLIC KEY BLOCK-----
""" EXPIRED_KEY = """-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: SKS 1.1.5
Comment: Hostname: pgp.mit.edu

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
8e6k2TpLNf1VrR1+IUmD+hbFmeSR
=3qZO
-----END PGP PUBLIC KEY BLOCK-----
""" VALID_KEY = """-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: SKS 1.1.6
Comment: Hostname: keys2.kfwebs.net

mQENBFoUymwBCADE0pq/ZTgyzV2mb/TySnZ2qt/wHqzv8vBrLi4ymqTHtMi/ZIPfcrsisdZE
N3l+hfO6DGkB1r/50IM4CiZB3qAuhRlzfAi3MKygw0dLQjQqlz4pShkdr+wFWSDMfY6uN+sk
Fon8hq5k5v4c7kKUErTKwm9eT19NuKU7DWHvAN7aFtHstN3mUd1hizizyIl7xcxvA01uoMgP
nMw6mqg/DbB7TwQ1E6zdRAnP6qwUyy9dDLO6Pe34uIpsmWr1qgpZQ6jXIRG0K/tHSXBrVwcy
7rEJU01pCUBdZWnQ8WWegjqwPGpOMplqSdIUW3W6MBZ74ly0NPi3mILrW1R3Ahj9SSDZABEB
AAG0ZUhhd2twb3N0IFRlc3QgS2V5IChUaGlzIGtleSBpcyBub3QgdXNlZC4gT25seSBmb3Ig
dGVzdGluZyBwdXJwb3Nlcy4pIDxmYWtlLnRlc3RpbmcuZW1haWxAaGF3a3Bvc3QuY28+iQE3
BBMBCAAhBQJaFMpsAhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEK0OUjfZhr11RZ8H
+wblJeH1cjQpymqW9ml0lVQlhpold6aTecQ5ncMf+Ax1xtexYx6Lm1kbDbKDjVJizccikpiE
rPniLGUJwWp/kvZegpiUv2ha25k2fuWmSPRbT32MKa2pNzzhDqXvOVujytDOAGqWxPaexVak
JTt8mYWrLhTn0DRdX7KK/8y019pfeE/UD0ND3diRFtS/GowFY+KRut5Yl8Fu8hucpSXedeEM
UxRG9AnYxS4oosVwpg8AxyZ+llFhNmth8CEyFXt5RL29F8GkKxz+9wvZNGgwlB/vEkzm2XAJ
ckPVGLSndIClNHLcpGtS+lcw2uJaQllg70W1prFh/EI+tsyMnGV0n4m5AQ0EWhTKbAEIAMoa
vGOmcwcvB8v++3qoj2JqyDcuZp4WgGCxX/wZbo18ICg5FtcweP6Vm9/2sauVHsEyt82Udpf7
B4zCmAHUTI35UQpb2GZq6UoFLXH6QXR5Pooft/rJpgtmMiJlxO4oqErabZwYYK2+5p718dcQ
CexwJxdFuMRMhMGpo7uc/Z/R136lTh2gNNRcfz0X8mFYRe8W3fXl1oWlUo5hkNNPD+05yd9W
++cQ8zvuYNSFuyTfb4cff8E0WGns9zRkJ4ppspVB4pzOIPBoYasswsm7HcXtGQ6c+iYb87YW
uSe24bo/MlQMEsSaIPGZ0oC3IugoMD9u9a2H8j/PKXEK1kp+nlsAEQEAAYkBHwQYAQgACQUC
WhTKbAIbDAAKCRCtDlI32Ya9dSDeCACvnhxY2zesbsJbjeOhBQGmWRYz3UtBT//vuguNcCEI
U10Y8lsjuwmuN9n55d2vKyIAIN1m7Ixt95svHWs51bbZUNjzHB5OMyoVwTY53itbm736dmk4
TVUzKyeCmGxFzipQQHPQljrkEy29hFXhSvRsghrFlYB/liNTWxHYdpaEXzsIOFIOY8rCLqV5
6xu/ngxTQAEPTnJJ0NSJLSVk4vGRo00i/tljvRfTgC2vLOUsnI5/TGVi3QZJOyZsCesNTl9s
cdUsTGXAGrbCtPdqs7qusZGwh9VuePwa+g+mI/vagxNeLQSqB8uqLzQ3YaqkgnH4FR1u+819
f3+dc1sYd68l
=j/j2
-----END PGP PUBLIC KEY BLOCK-----
"""
from django.contrib.auth.models import Group
from django.utils import timezone
from django.test import TestCase
from django.core import mail
from django.urls import reverse
from boxes.tests import create_and_login_user
from hawkpost import celery_app
from .models import Notification, User
from .forms import UpdateUserInfoForm
from .tasks import enqueue_email_notifications
from .utils import key_state, with_gpg_obj
from .test_constants import VALID_KEY_FINGERPRINT, VALID_KEYSERVER_URL
from .test_constants import EXPIRED_KEY_FINGERPRINT
from .test_constants import REVOKED_KEY, EXPIRED_KEY, VALID_KEY
from copy import copy
from shutil import rmtree
from unittest import mock
from collections import namedtuple
import gnupg
import tempfile
import random
import string



DEFAULT_USER_DATA = {
    "first_name": "some name",
    "last_name": "some last name",
    "company": "some company",
    "fingerprint": VALID_KEY_FINGERPRINT,
    "timezone": "UTC",
    "language": "en-us",
    "public_key": VALID_KEY
}


def create_notification(sent=False, group=None):
    sent_at = timezone.now() if sent else None
    return Notification.objects.create(subject="Test subject",
                                       body="Test Body",
                                       sent_at=sent_at,
                                       send_to=group)


@with_gpg_obj
def create_expiring_key(days_to_expire, gpg):
    days_to_expire = str(days_to_expire) + "d"
    # Example values for expire_date: “2009-12-31”, “365d”, “3m”, “6w”, “5y”, “seconds=<epoch>”, 0
    input_data = gpg.gen_key_input(key_type="RSA",
                                   key_length=1024,
                                   expire_date=days_to_expire,
                                   passphrase="secret")
    key_id = gpg.gen_key(input_data)
    # retrieve the key
    key_ascii = gpg.export_keys(key_id)
    # remove the keyring
    return key_ascii


def create_and_login_user(client):
    username = ''.join(random.choice(string.ascii_uppercase) for _ in range(5))
    user = User.objects.create_user(username=username,
                                    email="{}@example.com".format(username))
    client.force_login(user)
    return user


class UpdateUserFormTests(TestCase):

    def setUp(self):
        self.default_data = DEFAULT_USER_DATA

    def test_empty_fingerprint(self):
        data = copy(self.default_data)
        data["fingerprint"] = ""
        form = UpdateUserInfoForm(data)
        self.assertEqual(form.is_valid(), False)

    def test_fingerprint_plus_public_key(self):
        data = copy(self.default_data)
        data["fingerprint"] = VALID_KEY_FINGERPRINT
        data["public_key"] = VALID_KEY
        form = UpdateUserInfoForm(data)
        self.assertEqual(form.is_valid(), True)

    @mock.patch("humans.forms.requests.get")
    def test_fingerprint_plus_keyserver_url(self, get_mock):
        Response = namedtuple("Response", "status_code,text")
        get_mock.return_value = Response(200, VALID_KEY)
        data = copy(self.default_data)
        data["keyserver_url"] = VALID_KEYSERVER_URL
        form = UpdateUserInfoForm(data)
        self.assertEqual(form.is_valid(), True)

    def test_fingerprint_mismatch(self):
        data = copy(self.default_data)
        data["fingerprint"] = EXPIRED_KEY_FINGERPRINT

        form = UpdateUserInfoForm(data)