Exemple #1
0
def receive_mail(request):
    try:
        msg = base64.b64decode(request.raw_post_data)
    except TypeError:
        return forbidden(request)

    msg = email.message_from_string(msg)
    addr = msg.get("To")
    if not addr:
        return forbidden(request)

    try:
        values, tamper_check = base64.b64decode(addr).split("\0")
    except TypeError:
        return forbidden(request)

    if hash_val(values) != tamper_check:
        return forbidden(request)
    try:
        values = json.loads(values)
    except ValueError:
        return forbidden(request)

    # The Discussion Form wants this hashed value as a tamper-proof check
    values['parent_id_sig'] = hash_val(values['parent_id'])

    try:
        user = User.objects.get(email=values.pop("user"))
        group = Group.objects.get(slug=values.pop("group"))
        parent_disc = Discussion.objects.get(group=group, id=values['parent_id'])
    except (User.DoesNotExist, Group.DoesNotExist, Discussion.DoesNotExist), e:
        return forbidden(request)
Exemple #2
0
 def __init__(self, *args, **kwargs):
     super(DiscussionCreateForm, self).__init__(*args, **kwargs)
     # If a parent_id was passed in, sign it
     if 'parent_id' in self.initial:
         self.fields['parent_id_sig'].initial = hash_val(
             self.initial.get('parent_id'))
         self.fields['subject'].widget = forms.HiddenInput()
Exemple #3
0
 def __init__(self, sender, *args, **kwargs):
     forms.Form.__init__(self, *args, **kwargs)
     # If a parent_id was passed in, sign it
     if 'parent_id' in self.initial:
         self.fields['parent_id_sig'].initial = hash_val(self.initial.get('parent_id'))
         self.fields['subject'].widget = forms.HiddenInput()
     self.sender = sender
Exemple #4
0
    def email_extra_headers(self, user_object):
        """
        The Messaging system will look for this method to call
        while constructing emails to send; we build a custom
        Reply-To header that encodes the discussion's group
        and thread ID, and the email address of the recipient 
        we're sending to, so that email replies can use the
        address to find what discussion to try to append to.
        We encode the recipient's email address so that we can
        allow users to send email replies from an address other
        than the one that received it -- e.g. if I have multiple
        addresses going to the same email account and prefer to
        send with a specific one.

        A secret-key-hash of the JSONified data is joined to the
        data itself, and the resulting string (base64-encoded)
        is used as the Reply-To value.  This way, when receiving
        email responses, we can use the hashed value to confirm
        that the user did not tamper with or manually construct
        the address to send to.  This is important because we
        will need to trust the inbound email as coming from the
        user it claims to be coming from.
        """
        if self.disallow_replies:
            # If we're not allowing replies, just use the system defaults
            # and don't build a magic reply-to header.
            return None

        value = json.dumps(dict(parent_id=self.thread_id,
                                user=user_object.email,
                                group=self.group.slug))
        value = "%s\0%s" % (value, hash_val(value))
        value = base64.b64encode(value)
        return {"Reply-To": "%s@%s" %
                (value, settings.SMTP_HTTP_RELAY_DOMAIN)}
Exemple #5
0
    def render_message(self, content_object, email, user_object, extra_params=None):
        recipient_message = RecipientMessage.objects.create(message=self, recipient=email,
            token=hash_val([email, datetime.datetime.now()]))
        domain = Site.objects.get_current().domain
        params = {"content_object": content_object, "domain": domain, "recipient":
            user_object if user_object else email }
        if extra_params:
            params.update(extra_params)

        extra_headers = self.extra_headers(content_object, user_object)

        context = template.Context(params)
        # render the body and subject template with the given, template
        subject = template.Template(self.subject).render(context)
        body = template.Template(self.body).render(context)
        replacer = LinkReplacer(recipient_message=recipient_message)
        body = re.sub(URL_REGEX, replacer.replace_link, body)
        open_link = '<img src="http://%s%s"></img>' % (domain, reverse("message_open",
            args=[recipient_message.token]))
        # insert an open tracking image into the body
        body += open_link
        msg = EmailMessage(subject, body, from_email=None, to=[email],
                           headers=extra_headers)
        msg.content_subtype = "html"
        return msg
Exemple #6
0
 def parse_arg(self, code, parser):
     tmp_dir = make_tmp_dir(self._data_dir)
     js_path = hash_val(code) + '.js'
     js_path = os.path.join(tmp_dir, js_path)
     write(js_path, code)
     ast_path = parser.parse(js_path)
     return tmp_dir, ast_path
 def render_message(self,
                    content_object,
                    email,
                    user_object,
                    extra_params=None):
     recipient_message = RecipientMessage.objects.create(
         message=self,
         recipient=email,
         token=hash_val([email, datetime.datetime.now()]))
     domain = Site.objects.get_current().domain
     params = {
         "content_object": content_object,
         "domain": domain,
         "recipient": user_object if user_object else email
     }
     if extra_params:
         params.update(extra_params)
     context = template.Context(params)
     # render the body and subject template with the given, template
     subject = template.Template(self.subject).render(context)
     body = template.Template(self.body).render(context)
     replacer = LinkReplacer(recipient_message=recipient_message)
     body = re.sub(URL_REGEX, replacer.replace_link, body)
     open_link = '<img src="http://%s%s"></img>' % (
         domain, reverse("message_open", args=[recipient_message.token]))
     # insert an open tracking image into the body
     body += open_link
     msg = EmailMessage(subject, body, None, [email])
     msg.content_subtype = "html"
     return msg
Exemple #8
0
 def clean_parent_id(self):
     """Verify the parent_id_sig"""
     parent_id = self.cleaned_data['parent_id']
     if parent_id:
         sig_check = hash_val(parent_id)
         if parent_id and sig_check <> self.data['parent_id_sig']:
             raise forms.ValidationError('Parent ID is currupted')
     return parent_id
Exemple #9
0
 def clean_parent_id(self):
     """Verify the parent_id_sig"""
     parent_id = self.cleaned_data["parent_id"]
     if parent_id:
         sig_check = hash_val(parent_id)
         if parent_id and sig_check <> self.data["parent_id_sig"]:
             raise forms.ValidationError(_("Parent ID is currupted"))
     return parent_id
Exemple #10
0
 def test_invalid_email(self):
     self.client.login(username="******", password="******")
     response = self.client.post(self.url, {"emails": "invalid_email", "content_type": self.post_content_type.pk,
         "object_pk": self.post.pk, "signature": hash_val((self.post_content_type, self.post.pk,)),
         "token": "81yuksdfkq2ro2i", "next": "/login/"}, follow=True)
     self.failUnlessEqual(response.template[0].name, "registration/login.html")
     message = iter(response.context["messages"]).next()
     self.failUnless("error" in message.tags)
 def replace_link(self, match_obj):
     # for each unique link in the body, create a Message link to track the clicks
     ml = MessageLink.objects.create(
         recipient_message=self.recipient_message,
         link=match_obj.group(0),
         token=hash_val([self.count, datetime.datetime.now()]))
     self.count += 1
     return "http://%s%s" % (Site.objects.get_current().domain,
                             reverse("message_click", args=[ml.token]))
Exemple #12
0
 def test_invalid_email_list(self):
     self.client.login(username="******", password="******")
     response = self.client.post(self.event_guests_invite_url, {"emails": "[email protected] [email protected]",
         "note": "", "rsvp_notification": "", "copy_me": "",
         "signature": hash_val((self.event_content_type, self.event.pk,)),}, follow=True)
     self.failUnlessEqual(response.template[0].name, "events/guests_invite.html")
     errors = response.context["form"].errors
     self.failUnlessEqual(len(errors), 1)
     self.failUnless("emails" in errors)
Exemple #13
0
    def render_message(self, content_object, email, user_object, extra_params=None):
        recipient_message = RecipientMessage.objects.create(message=self, recipient=email,
            token=hash_val([email, datetime.datetime.now()]))
        domain = Site.objects.get_current().domain
        params = {"content_object": content_object, "domain": domain, "recipient":
            user_object if user_object else email }
        if extra_params:
            params.update(extra_params)

        extra_headers = self.extra_headers(content_object, user_object)
        from_email = None
        if extra_headers:
            from_email = extra_headers.pop('From', None)
        
        context = template.Context(params)

        # decide what language to try to use for localized emails
        language = None
        subject = self.subject
        body = self.body

        if user_object:
            if hasattr(user_object, 'user') and user_object.user is not None:
                _user = user_object.user
            else:
                _user = user_object
            if _user and hasattr(_user, 'get_profile'):
                _profile = _user.get_profile()
                language = _profile.language
        if language is not None:
            from rah_locale.models import TranslatedMessage
            try:
                _localized = TranslatedMessage.objects.get(
                    message=self, language=language)
            except TranslatedMessage.DoesNotExist:
                pass
            else:
                subject = _localized.subject
                body = _localized.body

        # render the body and subject template with the given, template
        subject = template.Template(subject).render(context)
        subject = html_unescape(subject)

        body = template.Template(body).render(context)
        replacer = LinkReplacer(recipient_message=recipient_message)
        body = re.sub(URL_REGEX, replacer.replace_link, body)
        open_link = '<img src="http://%s%s"></img>' % (domain, reverse("message_open",
            args=[recipient_message.token]))
        # insert an open tracking image into the body
        body += open_link
        msg = EmailMessage(subject, body, from_email=from_email, to=[email],
                           headers=extra_headers)
        msg.content_subtype = "html"
        return msg
Exemple #14
0
 def test_valid_default_invite(self):
     self.client.login(username="******", password="******")
     response = self.client.post(self.url, {"emails": "*****@*****.**", "content_type": "",
         "object_pk": "", "signature": hash_val((self.post_content_type, self.post.pk,)),
         "token": "81yuksdfkq2ro2i", "next": "/login/"}, follow=True)
     email = mail.outbox.pop()
     self.failUnlessEqual(email.to, ["*****@*****.**"])
     self.failUnlessEqual(len(email.subject), 35)
     self.failUnlessEqual(response.template[0].name, "registration/login.html")
     message = iter(response.context["messages"]).next()
     self.failUnless("success" in message.tags)
Exemple #15
0
 def test_duplicate_email(self):
     self.client.login(username="******", password="******")
     self.failUnlessEqual(self.event.guest_set.all().count(), 7)
     response = self.client.post(self.event_guests_invite_url, {"emails": "*****@*****.**",
         "note": "", "content_type": self.event_content_type.pk, "object_pk": self.event.pk,
         "signature": hash_val((self.event_content_type, self.event.pk,)),}, follow=True)
     self.failUnlessEqual(response.template[0].name, "events/detail.html")
     email = mail.outbox.pop()
     self.failUnlessEqual(email.to, ["*****@*****.**"])
     self.failUnlessEqual(len(email.subject), 35)
     event = response.context["event"]
     guests = event.guest_set.all()
     self.failUnlessEqual(len(guests), 7)
Exemple #16
0
 def clean(self):
     if "content_type" in self.cleaned_data and "object_pk" in self.cleaned_data and "signature" in self.cleaned_data:
         content_type = self.cleaned_data["content_type"]
         object_pk = self.cleaned_data["object_pk"]
         if content_type or object_pk:
             try:
                 target = content_type.get_object_for_this_type(pk=object_pk)
             except ObjectDoesNotExist:
                 raise forms.ValidationError("No object found matching %s" % object_pk)
             except ValueError:
                 raise forms.ValidationError("Invalid parameters %s, %s" % (content_type, object_pk))
             if hash_val((content_type, object_pk,)) != self.cleaned_data["signature"]:
                 raise forms.ValidationError("Signature has been currupted")
     return self.cleaned_data
Exemple #17
0
 def test_multiple_invite(self):
     self.client.login(username="******", password="******")
     self.failUnlessEqual(self.event.guest_set.all().count(), 7)
     response = self.client.post(self.event_guests_invite_url, {"emails": "[email protected],[email protected]",
         "note": "", "content_type": self.event_content_type.pk, "object_pk": self.event.pk,
         "signature": hash_val((self.event_content_type, self.event.pk,)),}, follow=True)
     self.failUnlessEqual(response.template[0].name, "events/detail.html")
     email = mail.outbox.pop()
     self.failUnlessEqual(email.to, ["*****@*****.**"])
     self.failUnlessEqual(len(email.subject), 35)
     email = mail.outbox.pop()
     self.failUnlessEqual(email.to, ["*****@*****.**"])
     self.failUnlessEqual(len(email.subject), 35)
     event = response.context["event"]
     guests = event.guest_set.all()
     self.failUnlessEqual(len(guests), 9)
     jon = guests[7]
     self.failUnlessEqual(jon.contributor.first_name, "")
     self.failUnlessEqual(jon.contributor.email, "*****@*****.**")
     eric = guests[8]
     self.failUnlessEqual(eric.contributor.first_name, "")
     self.failUnlessEqual(eric.contributor.email, "*****@*****.**")
Exemple #18
0
    def setUp(self):
        self.group_user = User.objects.create_user(username="******", email="*****@*****.**", password="******")
        self.group_manager = User.objects.create_user(username="******", email="*****@*****.**", password="******")
        self.group = Group.objects.get(slug="yankees")
        GroupUsers.objects.create(group=self.group, user=self.group_user)
        GroupUsers.objects.create(group=self.group, user=self.group_manager, is_manager=True)
        from utils import hash_val
        self.discs = {
            'd1': {"subject": "tc1 subject", "body": "tc1 body"},
            'd2': {"subject": "tc2 subject", "body": "tc2 body", "parent_id": 1, "parent_id_sig": hash_val(1)}
        }

        self.urls = {
            'group_disc_create': reverse("group_disc_create", kwargs={"group_slug": self.group.slug}),
            'group_disc_list': reverse("group_disc_list", kwargs={"group_slug": self.group.slug}),
            'd1': reverse("group_disc_detail", kwargs={"group_slug": self.group.slug, "disc_id": 1}),
            'd1_remove': reverse("group_disc_remove", kwargs={"group_slug": self.group.slug, "disc_id": 1}),
            'd1_approve': reverse("group_disc_approve", kwargs={"group_slug": self.group.slug, "disc_id": 1}),
            'd2': reverse("group_disc_detail", kwargs={"group_slug": self.group.slug, "disc_id": 2}),
            'd2_remove': reverse("group_disc_remove", kwargs={"group_slug": self.group.slug, "disc_id": 2}),
        }
Exemple #19
0
 def replace_link(self, match_obj):
     # for each unique link in the body, create a Message link to track the clicks
     ml = MessageLink.objects.create(recipient_message=self.recipient_message,
         link=match_obj.group(0), token=hash_val([self.count, datetime.datetime.now()]))
     self.count += 1
     return "http://%s%s" % (Site.objects.get_current().domain, reverse("message_click", args=[ml.token]))
Exemple #20
0
 def __init__(self, *args, **kwargs):
     form = super(InviteForm, self).__init__(*args, **kwargs)
     self.fields["signature"].initial = hash_val((self.instance.content_type, self.instance.object_pk,))
Exemple #21
0
 def __init__(self, *args, **kwargs):
     super(DiscussionCreateForm, self).__init__(*args, **kwargs)
     # If a parent_id was passed in, sign it
     if "parent_id" in self.initial:
         self.fields["parent_id_sig"].initial = hash_val(self.initial.get("parent_id"))
         self.fields["subject"].widget = forms.HiddenInput()
Exemple #22
0
 def __init__(self, *args, **kwargs):
     form = super(InviteForm, self).__init__(*args, **kwargs)
     self.fields["signature"].initial = hash_val((self.instance.content_type, self.instance.object_pk,))