Ejemplo n.º 1
0
    def test_all(self):
        with self.subTest('Exception raised'):
            with self.assertRaisesRegex(
                    UnauthorizedAction,
                    'Missing authorization by abraham@aaa.'):
                process_event(self.event)

        with self.subTest('Post not created'):
            with self.assertRaises(Post.DoesNotExist):
                Post.select().join(Server).where(Server.name == 'aaa',
                                                 Post.path == '/post1').get()

        with self.subTest('Unverified signature saved'):
            signatures: List[UnverifiedSignature] = list(
                UnverifiedSignature.select().where(
                    UnverifiedSignature.event == self.event))
            self.assertEqual(len(signatures), 1)
            self.assertEqual(signatures[0].user, 'abraham@aaa')
            self.assertIsNone(signatures[0].post)
            self.assertEqual(self.event.signatures['abraham@aaa'],
                             signatures[0].data.hex())

        with self.subTest('Verified signature saved'):
            signatures: List[Signature] = list(
                Signature.select().where(Signature.event == self.event))
            self.assertEqual(len(signatures), 1)
            self.assertEqual(signatures[0].keypair, self.bernard_keypair)
            self.assertIsNone(signatures[0].post)
            self.assertEqual(self.event.signatures['bernard@aaa'],
                             signatures[0].data.hex())
Ejemplo n.º 2
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)
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
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'])
Ejemplo n.º 5
0
def get_post(server: Union[Server, str, int], path: str) -> Post:
    """
    Returns a post with given `path` on given `server`.
    
    :param server: The :class:`Server<andreas.models.core.Server>` object, or its id, or its name.
    :param path: The path to the required :class:`Post<andreas.models.core.Post>` on the server.
    """
    if isinstance(server, str):
        return Post.select(Post, Server).join(Server).where(
            Server.name == server).where(Post.path == path).get()
    else:
        return Post.get(Post.server == server, Post.path == path)
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    def test_all(self):
        with self.subTest('Event is not valid yet'):
            with self.assertRaises(UnauthorizedAction):
                process_event(self.event)

        with self.subTest('Post not created'):
            with self.assertRaises(Post.DoesNotExist):
                Post.select().join(Server).where(Server.name == 'aaa',
                                                 Post.path == '/post1').get()

        with self.subTest('Unverified signature saved'):
            signatures: List[UnverifiedSignature] = list(
                UnverifiedSignature.select().where(
                    UnverifiedSignature.event == self.event))
            self.assertEqual(len(signatures), 1)
            self.assertEqual(signatures[0].user, 'abraham@aaa')
            self.assertIsNone(signatures[0].post)
            self.assertEqual(self.event.signatures['abraham@aaa'],
                             signatures[0].data.hex())

        # And now event becomes valid
        with self.subTest():
            self.load_abraham2()
            process_event(self.event)

            with self.subTest('Post created'):
                post: Post = Post.select().join(Server).where(
                    Server.name == 'aaa', Post.path == '/post1').get()
                self.assertEqual(self.event.diff, post.data)

            with self.subTest('Unverified signature deleted'):
                with self.assertRaises(UnverifiedSignature.DoesNotExist):
                    UnverifiedSignature.select().where(
                        UnverifiedSignature.event == self.event).get()

            with self.subTest('Verified signature saved'):
                signatures: List[Signature] = list(
                    Signature.select().where(Signature.event == self.event))
                self.assertEqual(len(signatures), 1)
                self.assertEqual(signatures[0].keypair, self.abraham_keypair)
                self.assertEqual(signatures[0].post, post)
                self.assertEqual(self.event.signatures['abraham@aaa'],
                                 signatures[0].data.hex())
Ejemplo n.º 8
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)
Ejemplo n.º 9
0
    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()
Ejemplo n.º 10
0
 def setUpSafe(self):
     super().setUpSafe()
     
     self.server_a: Server = Server.create(name='A')
     self.server_b: Server = Server.create(name='B')
     
     self.user_a1: User = User.create(server=self.server_a, name='A1')
     self.user_a2: User = User.create(server=self.server_a, name='A2')
     self.user_b1: User = User.create(server=self.server_b, name='B1')
     self.user_b2: User = User.create(server=self.server_b, name='B2')
     
     self.posts: Iterable[Post] = (
         Post.create(server=self.server_a, user=self.user_a1, path='/post1', data={'body': 'Server A, Post #1'}),
         Post.create(server=self.server_a, user=self.user_a1, path='/post2', data={'body': 'Server A, Post #2'}),
         Post.create(server=self.server_a, user=self.user_a2, path='/post3', data={'body': 'Server A, Post #3'}),
         Post.create(server=self.server_a, user=self.user_a2, path='/post4', data={'body': 'Server A, Post #4'}),
         
         Post.create(server=self.server_b, user=self.user_b1, path='/post1', data={'body': 'Server B, Post #1'}),
         Post.create(server=self.server_b, user=self.user_b1, path='/post2', data={'body': 'Server B, Post #2'}),
         Post.create(server=self.server_b, user=self.user_b2, path='/post3', data={'body': 'Server B, Post #3'}),
         Post.create(server=self.server_b, user=self.user_b2, path='/post4', data={'body': 'Server B, Post #4'}),
     )
Ejemplo n.º 11
0
    def test_post_created(self):
        post: Post = Post.select().join(Server).where(
            Server.name == 'aaa', Post.path == '/post1').get()

        with self.subTest(what='post content'):
            self.assertEqual(self.event.diff, post.data)

        with self.subTest(what='unverified signature'):
            us_list = list(UnverifiedSignature.select().where(
                UnverifiedSignature.post == post))
            self.assertEqual(len(us_list), 1)
            us = us_list[0]

            with self.subTest(field='event'):
                self.assertEqual(us.event_id, self.event.id)
            with self.subTest(field='user'):
                self.assertEqual(us.user, 'bernard@aaa')
            with self.subTest(field='data'):
                self.assertEqual(us.data.hex(),
                                 self.event.signatures['bernard@aaa'])
Ejemplo n.º 12
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)
Ejemplo n.º 13
0
 def test_all(self):
     post: Post = Post.select().join(Server).where(
         Server.name == 'aaa', Post.path == '/post1').get()
     self.assertEqual(self.event.diff, post.data)
Ejemplo n.º 14
0
 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)