Exemple #1
0
 def dispatch(self, request, token):
     try:
         signing.loads(token, max_age=20*60, salt='delete_account')
         self.token = token
     except signing.BadSignature:
         return redirect(reverse('destroy_account'))
     return super(DestroyConfirm, self).dispatch(request, token)
Exemple #2
0
def openvas_details(request):
    with open(openvas_data, 'r+') as f:
        data = json.load(f)
        ov_user = data['open_vas_user']
        ov_pass = data['open_vas_pass']
        ov_ip = data['open_vas_ip']

        lod_ov_user = signing.loads(ov_user)
        lod_ov_pass = signing.loads(ov_pass)
        lod_ov_ip = signing.loads(ov_ip)

    if request.method == 'POST':
        scan_host = request.POST.get("scan_host", )
        openvas_user = request.POST.get("openvas_user", )
        openvas_password = request.POST.get("openvas_password", )
    else:
        scan_host = lod_ov_user
        openvas_user = lod_ov_pass
        openvas_password = lod_ov_ip

    with open(openvas_data, 'r+') as f:
        sig_ov_user = signing.dumps(openvas_user)
        sig_ov_pass = signing.dumps(openvas_password)
        sig_ov_ip = signing.dumps(scan_host)
        data = json.load(f)
        data['open_vas_user'] = sig_ov_user
        data['open_vas_pass'] = sig_ov_pass
        data['open_vas_ip'] = sig_ov_ip
        f.seek(0)
        json.dump(data, f, indent=4)
        f.truncate()

    messages.add_message(request, messages.SUCCESS, 'Openvas Setting Updated ')

    return render(request, 'setting_form.html', )
def loads_with_timestamp(value, salt):
    """Returns the unsigned value along with its timestamp, the time when it
    got dumped."""
    try:
        signing.loads(value, salt=salt, max_age=-1)
    except signing.SignatureExpired as e:
        age = float(str(e).split('Signature age ')[1].split(' >')[0])
        timestamp = timezone.now() - datetime.timedelta(seconds=age)
        return timestamp, signing.loads(value, salt=salt)
Exemple #4
0
 def test_dumps_loads(self):
     "dumps and loads be reversible for any JSON serializable object"
     objects = [["a", "list"], "a unicode string \u2019", {"a": "dictionary"}]
     if six.PY2:
         objects.append(b"a byte string")
     for o in objects:
         self.assertNotEqual(o, signing.dumps(o))
         self.assertEqual(o, signing.loads(signing.dumps(o)))
         self.assertNotEqual(o, signing.dumps(o, compress=True))
         self.assertEqual(o, signing.loads(signing.dumps(o, compress=True)))
Exemple #5
0
    def get(self, request):
        signed_data = request.GET.get('data', None)

        if request.user.is_authenticated() and signed_data:
            assign_invitation(request.user, signing.loads(signed_data))
            return HttpResponseRedirect(reverse('portal:frontpage'))

        elif signed_data:
            request.session['invite_data'] = signing.loads(signed_data)

        return super(SignInView, self).get(request)
Exemple #6
0
 def test_dumps_loads(self):
     "dumps and loads be reversible for any JSON serializable object"
     objects = [
         ['a', 'list'],
         'a unicode string \u2019',
         {'a': 'dictionary'},
     ]
     for o in objects:
         self.assertNotEqual(o, signing.dumps(o))
         self.assertEqual(o, signing.loads(signing.dumps(o)))
         self.assertNotEqual(o, signing.dumps(o, compress=True))
         self.assertEqual(o, signing.loads(signing.dumps(o, compress=True)))
Exemple #7
0
def check_token(token):
    """Check whether the one-time token is valid."""
    if token is None:
        return False, 'Missing one-time token'

    try:
        signing.loads(token, max_age=settings.TOKEN_EXPIRES)
        return True, ''
    except signing.SignatureExpired:
        return False, 'Expired one-time token'
    except signing.BadSignature:
        return False, 'Invalid one-time token'
def forming_data(data):
    """
    Some actions with data.
    :param data: [{'data': data, ...},...{...}]
    :return: data
    """
    for instance in data:
        if instance.get('ssh_key_pub'):
            instance['ssh_key_pub'] = signing.loads(instance['ssh_key_pub'], key=settings.SECRET_KEY,
                                                    salt=instance['user_salt'])[0]
        if instance.get('ssh_key_privat'):
            instance['ssh_key_privat'] = signing.loads(instance['ssh_key_privat'], key=settings.SECRET_KEY,
                                                       salt=instance['user_salt'])[0]
    return data
    def loads(key, max_age=None):
        try:
            signing.loads(key)
        except signing.BadSignature:
            # log.warning("Tampering detected for conversion key: %s", key)
            raise ValueError

        try:
            data = signing.loads(key, max_age=max_age)
        except signing.BadSignature:
            # log.warning("Signature expired: %s", key)
            raise KeyError

        return data
Exemple #10
0
def verify_email(request, token):
    try:
        signing.loads(token)
        activation = Activation.objects.get(token=token)
    except:
        messages.warning(request, u'Неверный код.Возможно, это старое письмо.')
        context = {'form': None}
        return render(request, 'reg.html', context)
    if activation.status == Activation.EMAIL_SENT:
        activation.status = Activation.EMAIL_VERIFIED
        activation.save()
    elif activation.status == Activation.REGISTERED:
        return redirect('login', token=token)
    return redirect('reg', token=token)
Exemple #11
0
def log_into_subdomain(request: HttpRequest, token: Text) -> HttpResponse:
    try:
        data = signing.loads(token, salt=_subdomain_token_salt, max_age=15)
    except signing.SignatureExpired as e:
        logging.warning('Subdomain cookie: {}'.format(e))
        return HttpResponse(status=400)
    except signing.BadSignature:
        logging.warning('Subdomain cookie: Bad signature.')
        return HttpResponse(status=400)

    subdomain = get_subdomain(request)
    if data['subdomain'] != subdomain:
        logging.warning('Login attempt on invalid subdomain')
        return HttpResponse(status=400)

    email_address = data['email']
    full_name = data['name']
    is_signup = data['is_signup']
    if is_signup:
        # If we are signing up, user_profile should be None. In case
        # email_address already exists, user will get an error message.
        user_profile = None
        return_data = {}  # type: Dict[str, Any]
    else:
        # We can be reasonably confident that this subdomain actually
        # has a corresponding realm, since it was referenced in a
        # signed cookie.  But we probably should add some error
        # handling for the case where the realm disappeared in the
        # meantime.
        realm = get_realm(subdomain)
        user_profile, return_data = authenticate_remote_user(realm, email_address)
    invalid_subdomain = bool(return_data.get('invalid_subdomain'))
    return login_or_register_remote_user(request, email_address, user_profile,
                                         full_name, invalid_subdomain=invalid_subdomain,
                                         is_signup=is_signup)
Exemple #12
0
    def get_widget_or_404(self):
        """
        Get and return widget from cache.

        Raises:
            Http404: If if the widget can not be found or no id is provided.

        Returns:
            ModelSelect2Mixin: Widget from cache.

        """
        field_id = self.kwargs.get('field_id', self.request.GET.get('field_id', None))
        if not field_id:
            raise Http404('No "field_id" provided.')
        try:
            key = signing.loads(field_id)
        except BadSignature:
            raise Http404('Invalid "field_id".')
        else:
            cache_key = '%s%s' % (settings.SELECT2_CACHE_PREFIX, key)
            widget_dict = cache.get(cache_key)
            if widget_dict is None:
                raise Http404('field_id not found')
            if widget_dict.pop('url') != self.request.path:
                raise Http404('field_id was issued for the view.')
        qs, qs.query = widget_dict.pop('queryset')
        self.queryset = qs.all()
        widget_dict['queryset'] = self.queryset
        widget_cls = widget_dict.pop('cls')
        return widget_cls(**widget_dict)
Exemple #13
0
 def get(self, request, *args, **kwargs):
     if 'token' in request.GET:
         User = compat.get_user_model()
         try:
             token = signing.loads(request.GET['token'], max_age=7200)
             user_pk = token['user_pk']
             email = token['email']
             user = User.objects.get(pk=user_pk)
             old_email = user.email
             user.email = email
             user.save()
             messages.info(request, _('your request for changing your email for {0} '
                 'is successful').format(email))
             logging.getLogger(__name__).info('user %s changed its email '
                                              'from %s to %s', user,
                                              old_email, email)
         except signing.SignatureExpired:
             messages.error(request, _('your request for changing your email is too '
                 'old, try again'))
         except signing.BadSignature:
             messages.error(request, _('your request for changing your email is '
                 'invalid, try again'))
         except ValueError:
             messages.error(request, _('your request for changing your email was not '
                 'on this site, try again'))
         except User.DoesNotExist:
             messages.error(request, _('your request for changing your email is for '
                 'an unknown user, try again'))
         else:
             return shortcuts.redirect('account_management')
     return shortcuts.redirect('email-change')
Exemple #14
0
def load_login_token(site, site_url, token):
    """Verifies the login token.

    Returns email encoded in the token if the token is valid, None
    otherwise.
    """
    try:
        token_data = signing.loads(
            token, salt=site_url, max_age=settings.AUTH_TOKEN_SECONDS_VALID)
        # site_url in the token seems like an overkill. site_url is
        # already used as salt which should give adequate protection
        # against using a token for sites different than the one for
        # which the token was generated.
        if token_data['site'] != site_url:
            return None
        email = token_data['email']
        timestamp = token_data['timestamp']
        user = site.users.find_item_by_email(email)
        if user is not None and user.last_login is not None:
            if _datetime_to_timestamp(user.last_login) != timestamp:
                return None
        elif timestamp != 0:
            return None
        return email
    except signing.BadSignature:
        return None
    def verify_token(self, request, *args, **kwargs):
        """
        Use `token` to allow one-time access to a view.

        Set the user as a class attribute or raise an `InvalidExpiredToken`.

        Token expiry can be set in `settings` with `VERIFY_ACCOUNT_EXPIRY` and is
        set in seconds.
        """
        User = get_user_model()

        try:
            max_age = settings.VERIFY_ACCOUNT_EXPIRY
        except AttributeError:
            max_age = self.DEFAULT_VERIFY_ACCOUNT_EXPIRY

        try:
            email_data = signing.loads(kwargs['token'], max_age=max_age)
        except signing.BadSignature:
            raise self.invalid_exception_class

        email = email_data['email']

        try:
            self.user = User.objects.get_by_natural_key(email)
        except User.DoesNotExist:
            raise self.invalid_exception_class

        if self.user.email_verified:
            raise self.permission_denied_class
def forgot_password_confirm(request, token):
    # check token
    try:
        token_object = signing.loads(token, max_age=settings.FORGOT_PASSWORD_MAX_AGE)
        email = token_object['email']
        forgot_password = token_object['forgot-password']
    except:
        messages.error(request, u'Link inválido.')
        return redirect('accounts_forgot_password')

    # check for registered user
    try:
        user = User.objects.get(email=email)
    except:
        messages.error(request, u'E-mail não cadastrado.')
        return redirect('accounts_forgot_password')

    # process form
    if request.method == 'POST':
        form = ForgotPasswordConfirmForm(request.POST, user=user)
        if form.is_valid():
            form.save()
            messages.success(request, u'Senha alterada com sucesso.')
            return redirect('accounts_login')
    else:
        form = ForgotPasswordConfirmForm(user=user)
    return render(request, 'accounts/forgot_password_confirm.html', {'form': form})
def register(request, token):
    # check token
    try:
        token_object = signing.loads(token, max_age=settings.REGISTER_MAX_AGE)
        email = token_object['email']
        register = token_object['register']
    except:
        messages.error(request, u'Link de ativação inválido.')
        return redirect('accounts_register_confirm_email')

    # check for registered user
    if User.objects.filter(email=email):
        messages.error(request, u'E-mail já cadastrado.')
        return redirect('accounts_register_confirm_email')

    # process form
    if request.method == 'POST':
        form = RegisterForm(request.POST)
        if form.is_valid():
            # get new user
            new_user = form.save(email=email)

            # login new user
            auth_login(request, new_user)

            # make message
            messages.success(request, u'Conta criada com sucesso.')

            # redirect to index
            return redirect('staticpages_index')
    else:
        form = RegisterForm()
    return render(request, 'accounts/register.html', {'form': form})
Exemple #18
0
 def process_data(self, payment, request):
     xid = request.POST.get('MD')
     if xid != payment.attrs.xid:
         return redirect(payment.get_failure_url())
     if payment.status in [PaymentStatus.CONFIRMED, PaymentStatus.PREAUTH]:
         return redirect(payment.get_success_url())
     cc_data = request.GET.get('token')
     try:
         cc_data = signing.loads(cc_data)
     except:
         return redirect(payment.get_failure_url())
     else:
         expiration = cc_data['expiration']
         cc_data['expiration'] = datetime.date(
             expiration['year'], expiration['month'], 1)
     params = self._prepare_payer_auth_validation_check(
         payment, cc_data, request.POST.get('PaRes'))
     response = self._make_request(payment, params)
     payment.transaction_id = response.requestID
     try:
         self._set_proper_payment_status_from_reason_code(
             payment, response.reasonCode)
     except PaymentError as e:
         pass
     if payment.status in [PaymentStatus.CONFIRMED, PaymentStatus.PREAUTH]:
         return redirect(payment.get_success_url())
     else:
         return redirect(payment.get_failure_url())
Exemple #19
0
    def list(self, request):
        # Check that the user in the requested URL matches the current user
        # (or that the signed url matches)
        requested_uri = request.headers.get('X-Original-URI')
        requested_method = request.headers.get('X-Original-METHOD')

        if requested_uri is None:
            raise PermissionDenied("Missing X-Original-URI header")

        path_regex = r'^/webdav/([^/]+)/'
        m = re.match(path_regex, requested_uri)

        if m is None:
            raise PermissionDenied("Unrecognized URL pattern")

        if m.group(1) == self.request.user.username:
            r = Response({})
            r['X-Real-User'] = m.group(1)
            return r
        else:
            try:
                real_username = signing.loads(m.group(1))['username']
            except (KeyError, signing.BadSignature):
                raise PermissionDenied("User does not have access to this resource")
            else:
                r = Response({})
                r['X-Real-User'] = real_username
                return r
Exemple #20
0
    def confirm_link(self, request, **kwargs):
        try:
            state = signing.loads(request.GET['state'])
            pk = state['pk']
        except (KeyError, signing.BadSignature):
            raise ValidationError('Corrupted or missing state')

        try:
            code = request.GET['code']
        except KeyError:
            raise ValidationError('Bad or missing code')

        try:
            # We can't use self.get_queryset() here because are in an anonymous request, so self.request.user is
            # not defined
            gdrive_provider = GDriveProvider.objects.get(pk=pk)
        except:
            raise ValidationError('Corrupted or missing state')

        try:
            credentials_json = gdrive.step2_redeem_code_for_credentials(code)
        except:
            raise ValidationError('Invalid code')

        gdrive_provider.credentials = credentials_json
        gdrive_provider.save()

        provider_pk = gdrive_provider.userstorageaccount_ptr_id
        (check_credentials.si(provider_pk) | resync.si(provider_pk))()

        return HttpResponseRedirect('/home/#/storage_providers')
def confirm_email_address(request, token):
    """Confirms user's email address"""
    success_url = getattr(settings, 'BASE_ACCOUNTS_CONFIRM_EMAIL_REDIRECT_URL', '/')
    try:
        pk = signing.loads(token, max_age=3600 * 48, salt='resend_email_confirmation')
    except signing.BadSignature:
        raise Http404
    user = get_object_or_404(get_user_model(), pk=pk)

    if user.confirmed:
        raise Http404

    user.confirmed = now()
    user.save()

    if request.user != user:
        logout(request)

    if not request.user.is_authenticated():
        user.backend = 'django.contrib.auth.backends.ModelBackend'
        login(request, user)

    if user.is_active:
        messages.success(request, _('You have confirmed your email address'))
        return redirect(success_url)
    else:
        messages.success(request, _('Please confirm your email address'))
        return redirect('password_reset_recover')
Exemple #22
0
 def process_data(self, request):
     xid = request.POST.get('MD')
     if xid != self.payment.attrs.xid:
         return redirect(self.payment.get_failure_url())
     if self.payment.status in ['confirmed', 'preauth']:
         return redirect(self.payment.get_success_url())
     cc_data = request.GET.get('token')
     try:
         cc_data = signing.loads(cc_data)
     except:
         return redirect(self.payment.get_failure_url())
     else:
         expiration = cc_data['expiration']
         cc_data['expiration'] = datetime.date(
             expiration['year'], expiration['month'], 1)
     params = self._prepare_payer_auth_validation_check(
         cc_data, request.POST.get('PaRes'))
     response = self._make_request(params)
     self.payment.transaction_id = response.requestID
     self._set_proper_payment_status_from_reason_code(
         response.reasonCode)
     if self.payment.status in ['confirmed', 'preauth']:
         return redirect(self.payment.get_success_url())
     else:
         return redirect(self.payment.get_failure_url())
Exemple #23
0
 def get(self, request, *args, **kwargs):
     if 'token' in request.GET:
         User = get_user_model()
         try:
             token = signing.loads(request.GET['token'], max_age=7200)
             user_pk = token['user_pk']
             email = token['email']
             site_pk = token['site_pk']
             site = get_current_site(request)
             if site.pk != site_pk:
                 raise ValueError
             user = User.objects.get(pk=user_pk)
             user.email = email
             user.save()
             messages.info(request, _('your request for changing your email for {0} '
                 'is successful').format(email))
         except signing.SignatureExpired:
             messages.error(request, _('your request for changing your email is too '
                 'old, try again'))
         except signing.BadSignature:
             messages.error(request, _('your request for changing your email is '
                 'invalid, try again'))
         except ValueError:
             messages.error(request, _('your request for changing your email was not '
                 'on this site, try again'))
         except User.DoesNotExist:
             messages.error(request, _('your request for changing your email is for '
                 'an unknown user, try again'))
     return shortcuts.redirect(settings.LOGIN_REDIRECT_URL)
Exemple #24
0
    def validate(self, data):
        if self.instance is None:
            raise serializers.ValidationError("Cannot verify without a user instance")

        if self.instance.keybase_username:
            raise serializers.ValidationError("Cannot override existing keybase username")

        public_key_provider = get_provider()
        public_key_pem = public_key_provider.get_public_key(data["keybase_username"])
        signed_message = data['signed_message']

        with gpg_keyring(public_key_pem) as gpg:
            verification = gpg.verify(signed_message)
            validate_signature(verification)

            message = gpg.decrypt(signed_message).data.strip()

        try:
            user_id = signing.loads(message, max_age=datetime.timedelta(minutes=10))
        except signing.SignatureExpired:
            raise serializers.ValidationError(
                "Token expired. Please refresh and generate a new one."
            )
        except signing.BadSignature:
            raise serializers.ValidationError(
                "Could not validate token. Make sure you copied "
                "the full token or refresh and try again."
            )

        if user_id != self.instance.id:
            raise serializers.ValidationError("Mismatched user ID")

        return data
Exemple #25
0
def export_view(request, signature):
    # Must have a valid signature that hasn't expired
    try:
        signed_value = signing.loads(signature, max_age=settings.SIGNED_URL_LIFETIME)
    except BadSignature:
        logger.exception("export signature validation failure")
        return HttpResponseForbidden('this signature is not valid')

    # what does this signature allow them to do?
    if signed_value.get('what', None) != 'export':
        return HttpResponseForbidden('this signature does not allow exports')

    # The signature's data contains the userid of the authenticated user
    # that the signature was given to
    user_id = signed_value.get('u', -1)
    User = get_user_model()
    try:
        user = User.objects.get(id=user_id)
    except User.DoesNotExist:
        logger.error("User in export URL does not exist")
        return HttpResponseForbidden('this signature is not valid')

    response = HttpResponse(status=OK, content_type='application/vnd.ms-excel')
    response['Content-Disposition'] = 'attachment; filename="service_info.xls"'

    book = get_export_workbook_for_user(user)
    book.save(response)

    return response
Exemple #26
0
def unsubscribe(request, code):
    """unsubscribe"""
    try:
        medium_id, user_id, notice_type_label = signing.loads(code, max_age=UNSUBSCRIBE_TIMEOUT)
        user = User.objects.get(pk=user_id)
        medium_label = dict(NOTICE_MEDIA)[str(medium_id)]
    except (signing.BadSignature, User.DoesNotExist, ValueError, KeyError):
        raise Http404

    notice_settings = NoticeSetting.objects.filter(
        user=user,
        medium=medium_id
    )
    if notice_type_label:
        notice_settings = notice_settings.filter(notice_type__label=notice_type_label)
    for ns in notice_settings:
        ns.send = False
        ns.save()

    return render(request, 'notification/unsubscribed.html', {
        'notice_settings': notice_settings,
        'medium_id': medium_id,
        'medium_label': medium_label,
        'user': user,
    })
Exemple #27
0
def template_source(request):
    """
    Return the source of a template, syntax-highlighted by Pygments if
    it's available.
    """
    template_origin_name = request.GET.get('template_origin', None)
    if template_origin_name is None:
        return HttpResponseBadRequest('"template_origin" key is required')
    try:
        template_origin_name = signing.loads(template_origin_name)
    except Exception:
        return HttpResponseBadRequest('"template_origin" is invalid')
    template_name = request.GET.get('template', template_origin_name)

    final_loaders = []
    loaders = Engine.get_default().template_loaders

    for loader in loaders:
        if loader is not None:
            # When the loader has loaders associated with it,
            # append those loaders to the list. This occurs with
            # django.template.loaders.cached.Loader
            if hasattr(loader, 'loaders'):
                final_loaders += loader.loaders
            else:
                final_loaders.append(loader)

    for loader in final_loaders:
        if Origin:  # django>=1.9
            origin = Origin(template_origin_name)
            try:
                source = loader.get_contents(origin)
                break
            except TemplateDoesNotExist:
                pass
        else:  # django<1.9
            try:
                source, _ = loader.load_template_source(template_name)
                break
            except TemplateDoesNotExist:
                pass
    else:
        source = "Template Does Not Exist: %s" % (template_origin_name,)

    try:
        from pygments import highlight
        from pygments.lexers import HtmlDjangoLexer
        from pygments.formatters import HtmlFormatter

        source = highlight(source, HtmlDjangoLexer(), HtmlFormatter())
        source = mark_safe(source)
        source.pygmentized = True
    except ImportError:
        pass

    # Using SimpleTemplateResponse avoids running global context processors.
    return SimpleTemplateResponse('debug_toolbar/panels/template_source.html', {
        'source': source,
        'template_name': template_name
    })
    def dispatch(self, request, *args, **kwargs):
        self.request = request
        self.args = args
        self.kwargs = kwargs

        try:
            unsigned_pk_hash = signing.loads(kwargs['token'],
                                             max_age=self.token_expires,
                                             salt=self.salt)
        except signing.BadSignature:
            return self.invalid()

        try:
            pk = unsigned_pk_hash['pk']
            password = unsigned_pk_hash['psw']
        except KeyError:
            return self.invalid()

        self.user = get_object_or_404(get_user_model(), pk=pk)

        # Ensure the hashed password is same to prevent link to be reused
        # TODO: this is assuming the password is changed
        if password != self.hash_password(self.user.password):
            return self.invalid()

        return super(Reset, self).dispatch(request, *args, **kwargs)
def mail_track(http_meta, encrypted):
    from dbmail.models import MailLogTrack, MailLog

    class Request(object):
        META = http_meta

    try:
        request = Request()

        mail_log_id = signing.loads(encrypted)
        mail_log = MailLog.objects.get(log_id=mail_log_id)

        track_log = MailLogTrack.objects.filter(mail_log=mail_log)
        if not track_log.exists():
            MailLogTrack.objects.create(
                mail_log=mail_log,
                ip=get_ip(request),
                ua=request.META.get('HTTP_USER_AGENT'),
                is_read=True,
            )
        else:
            track_log[0].save()
    except (signing.BadSignature, MailLog.DoesNotExist):
        pass
    except Exception as exc:
        raise mail_track.retry(
            retry=True, max_retries=SEND_RETRY,
            countdown=SEND_RETRY_DELAY, exc=exc,
        )
def test_signup_post(client, parser):
    """Check the verification email has correct format.
    """
    client.post('/en-us/accounts/signup/', {
        'email': '[email protected]',
        'password1': '7K50M',
        'password2': '7K50M',
    }, follow=True)

    user = User.objects.get(email='[email protected]')
    email = mail.outbox[0]

    # The message does contain the activation link
    message_has_verification_link = re.search(
        r'^\s*http://testserver/en-us/accounts/verify/(?P<key>[-:\w]+)/$',
        email.body.strip(),
        re.MULTILINE
    )
    # The message hints the email in use
    message_has_account_email = user.email in email.body

    assert message_has_verification_link, email.body.strip()
    assert message_has_account_email, email.body.strip()
    assert user.email == signing.loads(
        message_has_verification_link.group('key'),
        salt='Footage order-flow long-chain hydrocarbons hacker',
    )
    assert not email.alternatives