Exemplo n.º 1
0
def check_session():
    """
    Check if a session is valid
    :param: session_id
    :return:
    """
    log.info(":API:/api/check_session")
    response = {"type": None, "text": None, "data": {}}
    if request.is_json:
        request_data = request.get_json()
    else:
        request_data = request.form
    try:
        session_id = request_data["session_id"]
        session_valid = (session_id in core.sessions.keys())
        response["data"].update({"valid": session_valid})
        response["type"] = "success"
        if tools.check_string(session_id):
            if session_valid:
                response["text"] = "Session id {0} is valid".format(session_id)
            else:
                response["text"] = "Session id {0} is invalid".format(
                    session_id)
        else:
            response["type"] = "error"
            response["text"] = "Invalid input"
    except KeyError:
        response["type"] = "error"
        response["text"] = "Couldn't find session_id in request data"
        response["data"].update({"valid": False})
    return tools.return_json(response)
Exemplo n.º 2
0
def ask_country(response_value, event):
    """
    The object of a response listener, set the city that the user specified and set another response listener for the country

    :param response_value:
    :param event:
    :return response listender object:
    """
    response = {"type": None, "text": None, "data": {}}
    session_id = event["session"]["id"]
    log.info(":{0}:Setting city to {1}, asking country".format(
        session_id, response_value))
    #Set the city in the database
    if tools.check_string(response_value):
        db = event["db"]
        db.begin()
        try:
            db["users"].update(
                {
                    "city": response_value,
                    "username": event["user_table"]["username"]
                }, ["username"])
            db.commit()
            #Now that the city is set, ask the user for their country and create another response listener
            response["type"] = "success"
            response["text"] = "What country are you in?"
            command_id = event["command_id"]
            tools.set_response(session_id, command_id, event, set_country)
            response["data"] = {"response": command_id}
        except:
            db.rollback()
            user_table = event["user_table"]
            is_admin = user_table["admin"]
            response["type"] = "error"
            exc_type, exc_value, exc_traceback = sys.exc_info()
            error_string = repr(
                traceback.format_exception(exc_type, exc_value, exc_traceback))
            #If the user is an admin, give them the full error. Otherwise, just log the error and tell the user that an error occurred
            if is_admin:
                response["text"] = error_string
            else:
                response["text"] = "An error occurred while trying to set your city. Please contact me at " \
                                   "[email protected] to notify me of the issue."
            log.debug(
                ":{0}:Error occurred while setting city. Error traceback: {1}".
                format(session_id, error_string))
    else:
        response["type"] = "error"
        response["text"] = "City {0} failed string validation".format(
            response_value)
    return response
Exemplo n.º 3
0
def set_country(response_value, event):
    """
    Set the user country and rerun the main weather function with the event

    :param response_value:
    :param event:
    :return:
    """
    response = {"text": None, "type": None, "data": {}}
    session_id = event["session"]["id"]
    log.info(":{0}:Got country {1}, rerunning main weather function".format(
        session_id, response_value))
    db = event["db"]
    db.begin()
    try:
        if tools.check_string(response_value):
            user_table = event["user_table"]
            username = user_table["username"]
            db["users"].update(
                {
                    "country": response_value,
                    "username": username
                }, ["username"])
            db.commit()
            log.info(":{0}:Country {1} set succesfully".format(
                session_id, response_value))
            #Rerun the weather function
            weather_response = weather_main(event)
            return weather_response
        else:
            db.rollback()
            response["text"] = "Country {0} failed string validation".format(
                response_value)
            response["type"] = "error"
    except:
        db.rollback()
        exc_type, exc_value, exc_traceback = sys.exc_info()
        error_string = repr(
            traceback.format_exception(exc_type, exc_value, exc_traceback))
        is_admin = user_table["admin"]
        # If the user is an admin, give them the full error string
        if is_admin:
            response["text"] = error_string
        else:
            response["text"] = "An error occurred while trying to set your country. Please contact me at " \
                                   "[email protected] to notify me of the issue."
    return response
Exemplo n.º 4
0
def login():
    """
    :param username:
    :param password:
    :return Login data:
    """
    response = {"type": None, "text": None, "data": {}}
    try:
        username = str(request.form["username"])
        password = request.form["password"]
        if all(tools.check_string(x) for x in [username, password]):
            user_table = db["users"].find_one(username=username)
            db_hash = user_table["password"]
            if bcrypt.checkpw(password.encode('utf8'), db_hash.encode('utf8')):
                log.info(":{0}:Logged in user".format(username))
                #Generate user token
                session["logged-in"] = True
                session["username"] = username
                user_token = tools.get_user_token(username)
                db['users'].upsert(
                    {
                        "username": username,
                        "user_token": user_token
                    }, ['username'])
                response["type"] = "success"
                response["text"] = "Authentication successful"
                response["data"].update({"user_token": user_token})
            else:
                response["type"] = "error"
                response["text"] = "Invalid username/password"
        else:
            response["type"] = "error"
            response[
                "text"] = "Invalid input, allowed characters are {0}".format(
                    tools.valid_chars)
    except KeyError:
        response["type"] = "error"
        response[
            "text"] = "Couldn't find username and password in request data"
    resp = make_response(redirect("/"))
    if response["type"] == "success":
        log.info(":{0}:Setting cookies for username and user token".format(
            username))
        session["username"] = username
        session["user_token"] = response["data"]["user_token"]
    return resp
Exemplo n.º 5
0
def get_sessions():
    """
    Return list of active sessions for user
    :param: username
    :param: password
    :return: list of sessions
    """
    log.info(":API:/api/get_sessions")
    response = {"type": None, "data": {}, "text": None}
    sessions = core.sessions
    if request.is_json:
        request_data = request.get_json()
    else:
        request_data = request.form
    try:
        username = request_data["username"]
        password = request_data["password"]
        if tools.check_string(request_data.values()):
            db_hash = db['users'].find_one(username=username)["password"]
            user_auth = bcrypt.checkpw(password.encode('utf8'),
                                       db_hash.encode('utf8'))
            if user_auth:
                response["data"].update({"sessions": []})
                for user_session in sessions:
                    if sessions[user_session]["username"] == username:
                        response["data"]["sessions"].append(session)
                response["type"] = "success"
                response["text"] = "Fetched active sessions"
            else:
                response["type"] = "error"
                response["text"] = "Invalid username/password combination"
        else:
            response["type"] = "error"
            response["text"] = "One of the submitted parameters contained an invalid character. " \
                               "Valid characters are {0}".format(tools.valid_chars)
    except KeyError:
        response["type"] = "error"
        response["text"] = "Couldn't find username and password in request"
    return tools.return_json(response)
Exemplo n.º 6
0
def command_response():
    """
    Api path for responding to a command question
    :param session_id:
    :param command_id:
    :return:
    """
    log.info(":API:/api/respond")
    response = {"type": None, "text": None, "data": {}}
    if request.is_json:
        request_data = request.get_json()
        try:
            log.debug(request_data.keys())
            command_id = request_data["command_id"]
            session_id = request_data["session_id"]
            response_value = request_data["value"]
            #Validate the JSON response object
            if tools.check_string([command_id, session_id]):
                if session_id in core.sessions.keys():
                    session_data = core.sessions[session_id]
                    session_commands = session_data["commands"]
                    response_command = None
                    for command_obj in session_commands:
                        if command_obj["id"] == command_id:
                            response_command = command_obj
                    if response_command:
                        if "function" in response_command.keys(
                        ) and "event" in response_command.keys():
                            response_function = response_command["function"]
                            log.info(
                                ":{0}: Executing response function {1} with response {2}"
                                .format(command_id, response_function,
                                        response_value))
                            #Execute the response
                            try:
                                response_result = response_function(
                                    response_value, response_command["event"])
                                log.info(
                                    ":{0}:Successfully executed response, returning {1}"
                                    .format(session_id,
                                            tools.fold(response_result)))
                                response = response_result
                            except Exception:
                                exc_type, exc_value, exc_traceback = sys.exc_info(
                                )
                                error_string = repr(
                                    traceback.format_exception(
                                        exc_type, exc_value, exc_traceback))
                                log.error(error_string)
                                username = session_data["username"]
                                user_table = db["users"].find_one(
                                    username=username)
                                if user_table:
                                    response["type"] = "error"
                                    if user_table["admin"]:
                                        response["text"] = error_string
                                    else:
                                        response["text"] = "An error has occurred while trying to fetch a response." \
                                                           "Please contact [email protected] to report the error and " \
                                                           "get more information"

                                else:
                                    log.error(
                                        "USER {0} NOT FOUND IN DATABASE. WARNING."
                                        .format(username))
                                    response["type"] = "error"
                                    response["text"] = "A database error has occurred. Please contact [email protected]" \
                                                       "to report the error, along with the circumstances under which it" \
                                                       "occurred."
                        else:
                            response["type"] = "error"
                            response["text"] = "Command {0} didn't register for a response or didn't" \
                                               " register the required data for a response.".format(command_id)
                    else:
                        response["type"] = "error"
                        response[
                            "text"] = "Couldn't find a command object in session {0} with command id {1}".format(
                                session_id, command_id)
                else:
                    response["type"] = "error"
                    response["text"] = "Invalid session id {0}".format(
                        session_id)
            else:
                response["type"] = "error"
                response[
                    "text"] = "Submitted response data {0} failed string validation. Valid characters are {0}".format(
                        tools.valid_chars)
        except KeyError:
            response["type"] = "error"
            response[
                "text"] = "command_id, session_id, and JSON response object required"
    else:
        response["type"] = "error"
        response["text"] = "/api/respond requires a JSON request"
    return tools.return_json(response)
Exemplo n.º 7
0
def start_session():
    '''
    :param: username
    :param: password
    Generate a session id and start a new session

    :return:
    '''
    log.info(":API:/api/start_session")
    # Check the information that the user has submitted
    response = {"type": None, "data": {}, "text": None}
    if request.is_json:
        request_data = request.get_json()
    else:
        request_data = request.form
    try:
        if request.method == "POST":
            username = request_data["username"]
            password = request_data["password"]
            client = "API-POST"
        elif request.method == "GET":
            username = request.args.get("username", "")
            password = request.args.get("password", "")
            client = "API-GET"
            if not (username and password):
                raise KeyError()
        if tools.check_string([username, password]):
            log.info(":{0}:Checking password".format(username))
            users = db["users"]
            user_data = users.find_one(username=username)
            if user_data:
                user_data = db["users"].find_one(username=username)
                # Check the password
                db_hash = user_data["password"]
                user_auth = bcrypt.checkpw(password.encode('utf8'),
                                           db_hash.encode('utf8'))
                if user_auth:
                    log.info(":{0}:Authentication successful".format(username))
                    # Return the session id to the user
                    session_id = tools.gen_session(username, client, db)
                    if session_id:
                        response["type"] = "success"
                        response["text"] = "Authentication successful"
                        response["data"].update({"session_id": session_id})
                    else:
                        response["type"] = "error"
                        response["text"] = "Invalid username/password"
            else:
                response["type"] = "error"
                response[
                    "text"] = "Couldn't find user with username {0}".format(
                        username)
        else:
            response["type"] = "error"
            response["text"] = "Invalid input"
    except KeyError:
        response["type"] = "error"
        response[
            "text"] = "Couldn't find username and password in request data"
    # Render the response as json
    if request.method == "GET":
        session.update({"session_data": response})
        if response["type"] == "success":
            return redirect("/")
        log.debug("Rendering command template")
        return render_template("command.html")
    else:
        return tools.return_json(response)
Exemplo n.º 8
0
def new_user():
    '''
    Create new user in the database

    :param: username
    :param: password
    :param: first_name
    :param: email
    :param: city
    :param: country
    :param: state
    '''
    log.info(":API:/api/new_user")
    response = {"type": None, "data": {}, "text": None}
    try:
        if request.is_json:
            request_data = request.get_json()
        else:
            request_data = request.form
        username = str(request_data["username"])
        log.debug("Username is {0}".format(username))
        password = str(request_data["password"])
        first_name = str(request_data["first_name"])
        last_name = str(request_data["last_name"])
        email = str(request_data["email"])
        city = str(request_data["city"])
        country = str(request_data["country"])
        state = str(request_data["state"])
        check_list = [
            username, password, first_name, last_name, email, city, country,
            state
        ]
        passed = tools.check_string(check_list)
        if passed:
            log.debug(
                "Attempting to create new user with username {0} and email {1}"
                .format(username, email))
            # Check to see if the username exists
            users = db["users"]
            if users.find_one(username=username):
                # If that username is already taken
                taken_message = "Username {0} is already taken".format(
                    username)
                log.debug(taken_message)
                response["type"] = "error"
                response["text"] = taken_message
            else:
                # Add the new user to the database
                log.info(
                    ":{0}:Adding a new user to the database".format(username))
                db.begin()
                # Hash the password
                log.debug("Hashing password")
                hashed = bcrypt.hashpw(password.encode('utf8'),
                                       bcrypt.gensalt())
                log.debug("Hashed password is {0}".format(hashed))
                is_admin = username in configuration_data["admins"]
                try:
                    db['users'].insert({
                        "username":
                        username,
                        "first_name":
                        first_name,
                        "last_name":
                        last_name,
                        "email":
                        email,
                        "password":
                        hashed,
                        "admin":
                        is_admin,
                        "default_plugin":
                        "search",
                        "notifications":
                        json.dumps(["email"]),
                        "ip":
                        request.environ.get('HTTP_X_REAL_IP',
                                            request.remote_addr),
                        "news_site":
                        "http://reuters.com",
                        "city":
                        city,
                        "country":
                        country,
                        "state":
                        state,
                        "temp_unit":
                        "fahrenheit",
                        "timezone":
                        whenareyou(city)
                    })
                    db.commit()
                    response["type"] = "success"
                    response[
                        "text"] = "Thank you {0}, you are now registered for W.I.L.L".format(
                            first_name)
                except:
                    db.rollback()
                    response["type"] = "error"
                    response[
                        "text"] = "There was an error in signing you up for W.I.L.L. Please check the information you entered"
        else:
            log.warning(":{0}:Failed SQL evaluation".format(username))
            response["type"] = "error"
            response["text"] = "Invalid input, valid chars are {0}".format(
                tools.valid_chars)

    except KeyError:
        log.error("Needed data not found in new user request")
        response["type"] = "error"
        response["text"] = "Couldn't find required data in request. " \
                           "To create a new user, a username, password, first name, last name," \
                           "and email is required"
    return tools.return_json(response)
Exemplo n.º 9
0
def settings():
    """
    :param username:
    :param password:
    :param Optional - setting to be changed:
    Change the users settings

    :return:
    """
    log.info(":API:/api/settings")
    response = {"type": None, "text": None, "data": {}}
    if request.is_json:
        request_data = request.get_json()
    else:
        request_data = request.form
    if "username" in request_data.keys() and "password" in request_data.keys():
        username = request_data["username"]
        password = request_data["password"]
        if tools.check_string(request_data.values()):
            user_table = db["users"].find_one(username=username)
            if user_table:
                db_hash = user_table["password"]
                if bcrypt.checkpw(password.encode('utf8'),
                                  db_hash.encode('utf8')):
                    #TODO: write a framework that allows changing of notifications
                    immutable_settings = [
                        "username", "admin", "id", "user_token",
                        "notifications", "password"
                    ]
                    db.begin()
                    log.info(
                        ":{0}:Changing settings for user".format(username))
                    try:
                        for setting in request_data.keys():
                            if setting not in immutable_settings:
                                db["users"].upsert(
                                    {
                                        "username": username,
                                        setting: request.form[setting]
                                    }, ['username'])
                        db.commit()
                        response["type"] = "success"
                        response["text"] = "Updated settings"
                    except Exception as db_error:
                        log.debug(
                            "Exception {0}, {1} occurred while trying to commit changes to the database"
                            .format(db_error.message, db_error.args))
                        response["type"] = "error"
                        response[
                            "text"] = "Error encountered while trying to update db, changes not committed"
                        db.rollback()
            else:
                response["type"] = "error"
                response["text"] = "User {0} doesn't exist".format(username)
        else:
            response["type"] = "error"
            response["text"] = "Invalid input"

    else:
        response["type"] = "error"
        response["text"] = "Couldn't find username or password in request data"
    return tools.return_json(response)