Ejemplo n.º 1
0
 def CreateFeedVerificationHash(self, req, context):
     self._logger.info(
         "Request to create a verification hash by user id %s for %s",
         req.user_id, req.feed_url)
     user_find_resp = self._db.Users(database_pb2.UsersRequest(
         request_type=database_pb2.RequestType.FIND,
         match=database_pb2.UsersEntry(
             global_id=req.user_id,
         )
     ))
     if user_find_resp.result_type != general_pb2.ResultType.OK:
         self._logger.error("Error getting CSS: %s", user_find_resp.error)
         return users_pb2.CreateFeedVerificationHashResponse(
             result=general_pb2.ResultType.ERROR,
             error=user_find_resp.error,
         )
     elif len(user_find_resp.results) != 1:
         self._logger.error(
             "Got wrong number of results for user find. Expected 1 got %d",
             len(user_find_resp.results))
         return users_pb2.GetCssResponse(
             result=general_pb2.ResultType.ERROR,
             error="Got wrong number of results during user find",
         )
     hash = self._generate_hash(user_find_resp.results[0], req.feed_url)
     return users_pb2.CreateFeedVerificationHashResponse(
         result=general_pb2.ResultType.OK,
         verification_hash=hash,
     )
Ejemplo n.º 2
0
    def SendCreate(self, req, context):
        self._logger.debug("Recieved a new create action.")

        author = self._users_util.get_user_from_db(global_id=req.author_id)
        # Insert ActivityPub ID into database.
        # build author entry from scratch to add host into call
        ue = database_pb2.UsersEntry(handle=author.handle,
                                     host=self._host_name)
        pe = database_pb2.PostsEntry(global_id=req.global_id)
        ap_id = self._activ_util.build_article_ap_id(ue, pe)
        article_url = self._activ_util.build_local_article_url(ue, pe)
        err = self._add_ap_id(req.global_id, ap_id)
        if err is not None:
            self._logger.error("Continuing through error: %s", err)

        # list of follow objects
        follow_list = self._users_util.get_follower_list(author.global_id)
        # remove local users
        foreign_follows = self._users_util.remove_local_users(follow_list)

        # go through follow send create activity
        # TODO (sailslick) make async/ parallel in the future
        for follower in foreign_follows:
            self._post_create_req(follower, req, ap_id, author, article_url)

        resp = general_pb2.GeneralResponse()
        resp.result_type = general_pb2.ResultType.OK
        return resp
Ejemplo n.º 3
0
 def Create(self, request, context):
     public_key, private_key = self._create_public_and_private_key()
     insert_request = database_pb2.UsersRequest(
         request_type=database_pb2.RequestType.INSERT,
         entry=database_pb2.UsersEntry(
             handle=request.handle,
             display_name=request.display_name,
             password=self._hash_password(request.password),
             bio=request.bio,
             host_is_null=True,
             public_key=public_key,
             private_key=private_key,
         ),
     )
     db_resp = self._db_stub.Users(insert_request)
     if db_resp.result_type != general_pb2.ResultType.OK:
         self._logger.warning("Error inserting user into db: %s",
                              db_resp.error)
         return users_pb2.CreateUserResponse(
             result_type=general_pb2.ResultType.ERROR,
             error=db_resp.error,
         )
     return users_pb2.CreateUserResponse(
         result_type=general_pb2.ResultType.OK,
         global_id=db_resp.global_id,
     )
Ejemplo n.º 4
0
    def get_or_create_user_from_db(self,
                                   handle=None,
                                   host=None,
                                   global_id=None,
                                   host_is_null=False,
                                   attempt_number=0,
                                   bio=None):
        if attempt_number > MAX_FIND_RETRIES:
            self._logger.error('Retried query too many times.')
            return None

        host = self._activ_util.normalise_hostname(host) if host else host
        user = self.get_user_from_db(handle, host, global_id, host_is_null)

        if user is not None:
            return user

        if global_id is not None or handle is None:
            # Should not try to create a user and hope it has this ID.
            # Also shouldn't create a user with no handle.
            return None

        user_entry = database_pb2.UsersEntry(
            handle=handle,
            host=host,
            bio=bio,
            host_is_null=host_is_null
        )
        new_global_id = self._create_user_in_db(user_entry)
        if new_global_id is not None and host:
            self.download_profile_pic(host, handle, new_global_id)
        return self.get_or_create_user_from_db(handle,
                                               host,
                                               attempt_number=attempt_number + 1)
Ejemplo n.º 5
0
 def get_user_from_db(self, handle=None, host=None, global_id=None, host_is_null=False):
     self._logger.debug('User %s@%s (id %s) host_is_null: %s requested from database',
                        handle, host, global_id, host_is_null)
     host = self._activ_util.normalise_hostname(host) if host else host
     user_entry = database_pb2.UsersEntry(
         handle=handle,
         host=host,
         host_is_null=host_is_null,
         global_id=global_id
     )
     find_req = database_pb2.UsersRequest(
         request_type=database_pb2.UsersRequest.FIND,
         match=user_entry
     )
     find_resp = self._db.Users(find_req)
     if len(find_resp.results) == 0:
         self._logger.warning('No user %s@%s (id %s) found',
                              handle, host, global_id)
         return None
     elif len(find_resp.results) == 1:
         self._logger.debug('Found user %s@%s (id %s) from database',
                            handle, host, global_id)
         return find_resp.results[0]
     else:
         self._logger.error('> 1 user found in database for %s@%s (id %s)'
                            + ', returning first one.',
                            handle, host, global_id)
         return find_resp.results[0]
Ejemplo n.º 6
0
 def GetCss(self, request, context):
     self._logger.info("Request to get the CSS for user id %s",
                       request.user_id)
     resp = self._db.Users(
         database_pb2.UsersRequest(
             request_type=database_pb2.RequestType.FIND,
             match=database_pb2.UsersEntry(global_id=request.user_id, )))
     if resp.result_type != general_pb2.ResultType.OK:
         self._logger.error("Error getting CSS: %s", resp.error)
         return users_pb2.GetCssResponse(
             result=general_pb2.ResultType.ERROR,
             error=resp.error,
         )
     elif len(resp.results) != 1:
         self._logger.error(
             "Got wrong number of results, expected 1 got %d",
             len(resp.results))
         return users_pb2.GetCssResponse(
             result=general_pb2.ResultType.ERROR,
             error="Got wrong number of results",
         )
     return users_pb2.GetCssResponse(
         result=general_pb2.ResultType.OK,
         css=resp.results[0].custom_css,
     )
Ejemplo n.º 7
0
 def _make_user(self, pw=None):
     pw = self._pw_hash if pw is None else pw
     return database_pb2.UsersEntry(
         handle="CianLR",
         global_id=1,
         display_name="Cian Ruane",
         password=pw,
         bio="A sound lad",
     )
Ejemplo n.º 8
0
 def delete_user_from_db(self, global_id):
     self._logger.debug("Deleteing user with global_id %d", global_id)
     resp = self._db.Users(
         database_pb2.UsersRequest(
             request_type=database_pb2.RequestType.DELETE,
             entry=database_pb2.UsersEntry(global_id=global_id),
         ))
     if resp.result_type != general_pb2.ResultType.OK:
         self._logger.error("Error deleting from db: %s", resp.error)
         return False
     return True
Ejemplo n.º 9
0
 def _get_local_user_id(self, handle):
     user = database_pb2.UsersEntry(handle=handle, host_is_null=True)
     req = database_pb2.UsersRequest(request_type=database_pb2.UsersRequest.FIND,
                                     match=user)
     resp = self._db.Users(req)
     if resp.result_type != database_pb2.UsersResponse.OK:
         self._logger.warning('Error getting user: {}'.format(resp.error))
         return None
     if not len(resp.results):
         self._logger.warning('Could not find user.')
         return None
     return resp.results[0].global_id
Ejemplo n.º 10
0
 def _fetch_public_key_from_database(self, handle):
     user = database_pb2.UsersEntry(
         handle=handle,
         host_is_null=True,
     )
     req = database_pb2.UsersRequest(
         match=user, request_type=database_pb2.UsersRequest.FIND)
     resp = self._db_stub.Users(req)
     if (resp.result_type != database_pb2.UsersResponse.OK
             or len(resp.results) == 0):
         self._logger.error('No user found in database')
         return None
     return resp.results[0].public_key
Ejemplo n.º 11
0
    def add_user(self, handle=None, host=None):
        user_entry = database_pb2.UsersEntry(
            handle=handle,
            host=host,
            host_is_null=host is None,
        )

        req = database_pb2.UsersRequest(
            request_type=database_pb2.RequestType.INSERT,
            entry=user_entry,
        )
        add_res = self.users.Users(req, self.ctx)
        self.assertNotEqual(add_res.result_type, general_pb2.ResultType.ERROR)
        return add_res
Ejemplo n.º 12
0
def get_user_and_check_pw(logger, db_stub, handle, pw):
    """
    get_user_and_check finds a user and checks their password.

    Raises:
        On a database lookup failure, raises a ValueError.

    Returns:
        Returns a tuple: (Result, Error)
        Error is a string containing details a login error.

        if their password is incorrect: returns None, Error
        if their password is correct: returns UserEntry, None
    """
    if not handle:
        err = "Received blank username"
        logger.warning(err)
        raise ValueError(err)
    if not pw:
        err = "Received blank password"
        logger.warning(err)
        raise ValueError(err)
    find_request = database_pb2.UsersRequest(
        request_type=database_pb2.RequestType.FIND,
        match=database_pb2.UsersEntry(
            handle=handle,
            host_is_null=True,
        ),
    )
    db_resp = db_stub.Users(find_request)
    if db_resp.result_type != general_pb2.ResultType.OK:
        err = "Error getting user from DB: " + db_resp.error
        logger.warning(err)
        raise ValueError(db_resp.error)

    elif len(db_resp.results) != 1:
        err = "Got {} users matching handle {}, expecting 1".format(
              len(db_resp.results), handle)
        logger.warning(err)
        raise ValueError("Got wrong number of users matching query")

    user = db_resp.results[0]
    if not check_password(logger, pw, user.password):
        err = "ACCESS DENIED for user %s", handle
        logger.info(err)
        return None, err

    logger.info("*hacker voice* I'm in (%s)", handle)
    return user, None
Ejemplo n.º 13
0
 def _get_user_by_id(self, _id):
     """
     Get the user object for the given user global_id. If the user could not
     be retrieved, return None.
     """
     user_resp = self._db.Users(
         database_pb2.UsersRequest(
             request_type=database_pb2.UsersRequest.FIND,
             match=database_pb2.UsersEntry(global_id=_id)))
     if user_resp.result_type != database_pb2.UsersResponse.OK:
         self._logger.warning('Could not find user: {}'.format(
             user_resp.error))
         return None
     if not len(user_resp.results):
         self._logger.warning('Could not find user.')
         return None
     return user_resp.results[0]
Ejemplo n.º 14
0
 def forward_activity_to_followers(self, user_id, activity):
     """
     Sends an activity to all of the hosts with a follower of a given user.
     Some things to note about the behaviour:
      - Local users do not receive the activity
      - An arbitrary user from each host is selected to receive the activity
      - Any followers or hosts not found are skipped with a warning.
     """
     self._logger.info("Sending activity to followers")
     resp = self._db.Follow(
         database_pb2.DbFollowRequest(
             request_type=database_pb2.DbFollowRequest.FIND,
             match=database_pb2.Follow(followed=user_id),
         ))
     if resp.result_type != database_pb2.DbFollowResponse.OK:
         return resp.error
     self._logger.info("Have %d users to notify", len(resp.results))
     # Gather up the users, filter local and non-unique hosts.
     hosts_to_users = {}
     for follow in resp.results:
         user_resp = self._db.Users(
             database_pb2.UsersRequest(
                 request_type=database_pb2.UsersRequest.FIND,
                 match=database_pb2.UsersEntry(global_id=follow.follower)))
         if user_resp.result_type != database_pb2.UsersResponse.OK:
             self._logger.warning("Error finding user %d, skipping",
                                  follow.follower)
             continue
         if len(user_resp.results) != 1:
             self._logger.warning("Couldn't find user %d, skipping",
                                  follow.follower)
             continue
         user = user_resp.results[0]
         if not user.host or user.host_is_null:
             continue  # Local user, skip.
         hosts_to_users[user.host] = user
     # Send the activities off.
     for host, user in hosts_to_users.items():
         inbox = self.build_inbox_url(user.handle, host)
         resp, err = self.send_activity(activity, inbox)
         if err:
             self._logger.warning(
                 "Error sending activity to '%s' at '%s': %s", user.handle,
                 host, str(err))
     return None
Ejemplo n.º 15
0
    def Update(self, request, context):
        try:
            user, err = get_user_and_check_pw(self._logger,
                                              self._db_stub,
                                              request.handle,
                                              request.current_password)
        except ValueError as e:
            return users_pb2.UpdateUserResponse(
                result=general_pb2.ResultType.ERROR,
                error=str(e),
            )

        if err is not None:
            return users_pb2.UpdateUserResponse(
                result=general_pb2.ResultType.ERROR_401,
            )

        pw = None
        if request.new_password:
            pw = self._hash_password(request.new_password)

        update_request = database_pb2.UsersRequest(
            request_type=database_pb2.RequestType.UPDATE,
            match=user,
            entry=database_pb2.UsersEntry(
                display_name=request.display_name,
                password=pw,
                bio=request.bio,
                private=request.private,
                custom_css=request.custom_css,
            ),
        )

        db_resp = self._db_stub.Users(update_request)
        if db_resp.result_type != general_pb2.ResultType.OK:
            self._logger.warning("Error update user: %s", db_resp.error)
            return users_pb2.CreateUserResponse(
                result_type=general_pb2.ResultType.ERROR,
                error=db_resp.error,
            )

        return users_pb2.UpdateUserResponse(
            result=general_pb2.ResultType.OK,
        )
Ejemplo n.º 16
0
 def __init__(self):
     self.posts_response = database_pb2.PostsResponse(
         result_type=general_pb2.ResultType.OK,
         results=[
             database_pb2.PostsEntry(
                 global_id=123,
                 author_id=456,
                 title="Minecraft Farming 101",
                 body="Don't bother",
                 ap_id="https://rabble.mojang.com/ap/@minecraft4ever/666",
             )
         ])
     self.users_response = database_pb2.UsersResponse(
         result_type=general_pb2.ResultType.OK,
         results=[
             database_pb2.UsersEntry(
                 global_id=456,
                 handle="minecraft4ever",
                 host="rabble.mojang.com",
                 display_name="Minecraft4Ever",
             )
         ],
     )
Ejemplo n.º 17
0
 def __init__(self):
     self.posts_response = dbpb.PostsResponse(
         result_type=dbpb.PostsResponse.OK,
         results=[
             dbpb.PostsEntry(
                 global_id=3,
                 author_id=123,
                 title="Test",
                 body="Test body",
                 ap_id="https://rabble.cian.com/@cian/3",
             ),
         ],
     )
     self.users_response = dbpb.UsersResponse(
         result_type=dbpb.UsersResponse.OK,
         results=[
             dbpb.UsersEntry(
                 global_id=123,
                 handle="cian",
                 host="rabble.cian.com",
                 display_name="Cian",
             ),
         ],
     )
Ejemplo n.º 18
0
 def lookup_user(self, user):
     if user not in self.users_dict:
         return None
     return database_pb2.UsersEntry(global_id=self.users_dict[user])