예제 #1
0
class TestCommenting(AndreasTestCaseWithKeyPair):
    def setUpSafe(self):
        super().setUpSafe()

        self.post = Post()
        self.post.server = self.server
        self.post.path = '/post1'
        self.post.data = {
            'body': 'How are you?',
        }
        self.post.save()
        UserPostRelation.create(source=self.abraham,
                                type='wrote',
                                target=self.post)

        event = Event()
        event.server = 'aaa'
        event.authors = ['bernard@aaa']
        event.parent = 'aaa/post1'
        event.path = '/post1#c1'
        event.data = {'body': 'Good!'}
        event.signatures = {
            'bernard@aaa': sign_post(event, self.bernard_keypair).hex(),
        }
        event.save()
        process_event(event)

    def test_comment_created(self):
        comment = Post.select().join(Server).where(
            Server.name == 'aaa', Post.path == '/post1#c1').get()
        PostPostRelation.get(PostPostRelation.source == comment,
                             PostPostRelation.type == 'comments',
                             PostPostRelation.target == self.post)
예제 #2
0
class TestModifyPost(AndreasTestCaseWithKeyPair):
    """
    With a pre-existing post, try to create/modify/remove three different fields in ``data``.
    Check that each field was processed correctly and that the fourth field wasn't affected.
    """
    def setUpSafe(self):
        super().setUpSafe()

        self.post = Post()
        self.post.server = self.server
        self.post.authors = [self.abraham]
        self.post.path = '/post1'
        self.post.data = {
            'title': 'Hello',
            'subtitle': 'A hello world post',
            'body': 'Hello, World!',
        }
        self.post.save()

        event = Event()
        event.server = 'aaa'
        event.authors = ['abraham@aaa']
        event.path = '/post1'
        event.diff = {
            'title': 'Hello (updated)',
            'subtitle': None,
            'tags': ['Aaa', 'Bbb', 'Ccc'],
        }
        event.signatures = {
            'abraham@aaa':
            sign_post(event,
                      self.abraham_keypair,
                      data={
                          'title': 'Hello (updated)',
                          'body': 'Hello, World!',
                          'tags': ['Aaa', 'Bbb', 'Ccc'],
                      }).hex(),
        }
        event.save()
        process_event(event)

        self.post.reload()

    def test_title_updated(self):
        self.assertEqual('Hello (updated)', self.post.data['title'])

    def test_subtitle_removed(self):
        self.assertFalse('subtitle' in self.post.data)

    def test_body_untouched(self):
        self.assertEqual('Hello, World!', self.post.data['body'])

    def test_tags_added(self):
        self.assertEqual(['Aaa', 'Bbb', 'Ccc'], self.post.data['tags'])
예제 #3
0
class TestSigningPost(_TestSigning):
    def setUpSafe(self):
        super().setUpSafe()

        self.post = Post()
        self.post.server = self.server
        self.post.path = '/post1'
        self.post.data = {'foo': 'bar', 'bar': 'baz'}
        self.post.save()

        UserPostRelation.create(source=self.abraham,
                                type='wrote',
                                target=self.post)

    def test_sign(self):
        self.assertEqual(sign_post(self.post, self.abraham_keypair),
                         self.expected)

    def test_verify(self):
        verify_post(self.post, 'abraham@aaa', self.expected)
예제 #4
0
def process_event(event: Event):
    # Users whose approvals we need for this post
    required_users: Set[User] = set()

    # Create or update the post with data provided in this event
    if event.path:
        server: Server = Server.get(Server.name == event.server)
        try:
            post = Post.get(Post.server == server, Post.path == event.path)
        except Post.DoesNotExist:
            post = Post(server=server, path=event.path)

        # Add/replace elements from the event,
        # remove elements which are nulls in the information provided by event
        for key, value in event.diff.items():
            if value is not None:
                post.data[key] = value
            elif key in post.data:
                del post.data[key]

        # Save relations
        for user_string in event.authors:
            user = User.from_string(user_string)
            UserPostRelation.create_after(post,
                                          source=user,
                                          type='wrote',
                                          target=post)
            required_users.add(user)
        if event.parent:
            parent = get_post_by_identifier(event.parent)
            PostPostRelation.create_after(post,
                                          source=post,
                                          type='comments',
                                          target=parent)

        verified_signatures: List[Dict] = []
        unverified_signatures: List[Dict] = []
        verified_users: Set[User] = set()
        unverified_usernames: Set[str] = set()

        # Try to verify and save as many signatures as possible
        for user_string, signature_hex in event.signatures.items():
            signature_data = bytes.fromhex(signature_hex)
            try:
                keypair = verify_post(post,
                                      user_string,
                                      signature_data,
                                      authors=event.authors)
                verified_signatures.append(
                    dict(event=event, data=signature_data, keypair=keypair))
                verified_users.add(keypair.user)
            except rsa.VerificationError:
                unverified_signatures.append(
                    dict(event=event, data=signature_data, user=user_string))
                unverified_usernames.add(user_string)

        # If we got all approvals, then we save post and fill post_id in all the signatures
        success = False
        if verified_users >= required_users:
            success = True

            post.save()
            for signature_data in chain(verified_signatures,
                                        unverified_signatures):
                signature_data['post'] = post

            # If we have already analyzed this event in the past
            # but had some user's signatures unverified and now some of them became verified,
            # delete the old unverified instances
            (UnverifiedSignature.delete().where(
                UnverifiedSignature.event == event).where(
                    UnverifiedSignature.user <<
                    [repr(u) for u in verified_users]).execute())

        # Save the signatures
        # We need them no matter what, even if we are going to raise the exception
        if verified_signatures:
            Signature.insert_many(verified_signatures).execute()
        if unverified_signatures:
            UnverifiedSignature.insert_many(unverified_signatures).execute()

        # Raise exception if post was not verified and therefore created/updated
        if not success:
            raise UnauthorizedAction(required_users, verified_users,
                                     unverified_usernames)