示例#1
0
 def post(self):
     """
     Attempts to log in to the OECI web site using the provided username
     and password if successful, encrypt those credentials and return them
     in a cookie. If the credentials
     """
     data = request.get_json()
     if data is None:
         error(400, "No json data in request body")
     check_data_fields(data, ["oeci_username", "oeci_password"])
     credentials = {"oeci_username": data["oeci_username"], "oeci_password": data["oeci_password"]}
     crawler_session = requests.Session()
     try:
         Crawler.attempt_login(crawler_session, credentials["oeci_username"], credentials["oeci_password"])
     except InvalidOECIUsernamePassword as e:
         error(401, str(e))
     except OECIUnavailable as e:
         error(404, str(e))
     finally:
         crawler_session.close()
     cipher = DataCipher(key=current_app.config.get("SECRET_KEY"))
     encrypted_credentials = cipher.encrypt(credentials)
     response = make_response()
     # TODO: We will need an OECILogout endpoint to remove httponly=true cookies from frontend
     response.set_cookie(
         "oeci_token",
         secure=os.getenv("TIER") == "production",
         httponly=False,
         samesite="strict",
         expires=time.time() + 2 * 60 * 60,  # type: ignore # 2 hour lifetime
         value=encrypted_credentials,
     )
     return response, 201
示例#2
0
    def post(self):
        request_data = request.get_json()

        if request_data is None:
            error(400, "No json data in request body")

        check_data_fields(
            request_data,
            ["first_name", "last_name", "middle_name", "birth_date"])

        cipher = DataCipher(key=current_app.config.get("SECRET_KEY"))

        decrypted_credentials = cipher.decrypt(request.cookies["oeci_token"])

        login_result = (decrypted_credentials["oeci_username"] == "username"
                        and decrypted_credentials["oeci_password"]
                        == "password")
        if login_result is False:
            error(401, "Attempted login to OECI failed")

        record = build_record()
        response_data = {"data": {"record": record}}
        current_app.json_encoder = ExpungeModelEncoder

        return response_data  # Json-encoding happens automatically here
示例#3
0
    def post(self):
        request_data = request.get_json()
        if request_data is None or not request_data.get("aliases"):
            error(400, "No json data in request body")
        check_data_fields(request_data, ["aliases"])
        for alias in request_data["aliases"]:
            check_data_fields(
                alias,
                ["first_name", "last_name", "middle_name", "birth_date"])

        cipher = DataCipher(key=current_app.config.get("SECRET_KEY"))

        if not "oeci_token" in request.cookies.keys():
            error(401, "Missing login credentials to OECI.")
        decrypted_credentials = cipher.decrypt(request.cookies["oeci_token"])
        username, password = decrypted_credentials[
            "oeci_username"], decrypted_credentials["oeci_password"]

        record, ambiguous_record, questions = RecordCreator.build_record(
            username, password, request_data["aliases"])
        if questions:
            session["ambiguous_record"] = pickle.dumps(ambiguous_record)

        try:
            save_result(request_data, record)
        except Exception as ex:
            logging.error("Saving search result failed with exception: %s" %
                          ex,
                          stack_info=True)

        record_summary = RecordSummarizer.summarize(record, questions)
        response_data = {"data": {"record": record_summary}}
        encoded_response = json.dumps(response_data, cls=ExpungeModelEncoder)
        return encoded_response
示例#4
0
    def post(self):
        data = request.get_json()

        if data is None:
            error(400, "No json data in request body")

        check_data_fields(data, ["email", "password"])

        user_db_result = user_db_util.read(
            g.database,
            user_db_util.identify_by_email(g.database, data["email"]))

        if not user_db_result or not check_password_hash(
                user_db_result["hashed_password"], data["password"]):
            error(401, "Invalid username or password")

        user = from_dict(data_class=User, data=user_db_result)
        User.login_user(user)

        response = make_response()
        if user.admin:
            response.set_cookie(
                "is_admin",
                expires=time.time() + 365 * 24 * 60 *
                60,  # type: ignore # 1 year lifetime matches flask login cookie
            )
        return response, 200
示例#5
0
    def post(self):
        """
        Attempts to log in to the OECI web site using the provided username
        and password if successful, encrypt those credentials and return them
        in a cookie. If the credentials
        """

        data = request.get_json()

        if data is None:
            error(400, "No json data in request body")

        check_data_fields(data, ["oeci_username", "oeci_password"])

        credentials = {"oeci_username": data["oeci_username"], "oeci_password": data["oeci_password"]}

        cipher = DataCipher(key=current_app.config.get("SECRET_KEY"))

        encrypted_credentials = cipher.encrypt(credentials)

        response = make_response()

        # TODO: We will need an OECILogout endpoint to remove httponly=true cookies from frontend
        response.set_cookie(
            "oeci_token",
            secure=os.getenv("TIER") == "production",
            httponly=False,
            samesite="strict",
            expires=time.time() + 15 * 60,  # 15 minutes
            value=encrypted_credentials,
        )

        return response, 201
示例#6
0
    def post(self):
        request_data = request.get_json()

        if request_data is None or not request_data.get("names"):
            error(400, "No json data in request body")

        for alias in request_data["names"]:
            check_data_fields(
                alias,
                ["first_name", "last_name", "middle_name", "birth_date"])

        cipher = DataCipher(key=current_app.config.get("SECRET_KEY"))

        if not "oeci_token" in request.cookies.keys():
            error(401, "Missing login credentials to OECI.")

        decrypted_credentials = cipher.decrypt(request.cookies["oeci_token"])

        crawler = Crawler()

        login_result = crawler.login(decrypted_credentials["oeci_username"],
                                     decrypted_credentials["oeci_password"],
                                     close_session=False)

        if login_result is False:
            error(401, "Attempted login to OECI failed")

        cases: List[Case] = []
        for alias in request_data["names"]:
            cases += crawler.search(
                alias["first_name"],
                alias["last_name"],
                alias["middle_name"],
                alias["birth_date"],
            ).cases
        cases_with_unique_case_number = [
            list(group)[0]
            for key, group in groupby(cases, lambda case: case.case_number)
        ]
        record = Record(cases_with_unique_case_number)

        expunger = Expunger(record)
        expunger.run()

        try:
            save_result(request_data, record)
        except Exception as ex:
            logging.error("Saving search result failed with exception: %s" %
                          ex,
                          stack_info=True)

        record_summary = RecordSummarizer.summarize(record)
        response_data = {"data": {"record": record_summary}}

        current_app.json_encoder = ExpungeModelEncoder

        return response_data  # Json-encoding happens automatically here
示例#7
0
    def post(self):
        data = request.get_json()

        if data is None:
            error(400, "No json data in request body")

        check_data_fields(data, ["email", "password"])

        user_db_result = user_db_util.read(g.database, user_db_util.identify_by_email(g.database, data["email"]))

        if not user_db_result or not check_password_hash(user_db_result["hashed_password"], data["password"]):
            error(401, "Invalid username or password")

        user = from_dict(data_class=User, data=user_db_result)
        User.login_user(user)
        return jsonify({})
示例#8
0
    def post(self):
        """
        Create a new user with provided email, password, and admin flag.
        - If required fields are missing in the request, return 400
        - Password must be 8 or more characters long. Otherwise return 422
        - Email must not already be in use by an existing user.
          Otherwise return 422
        - If success, return 201 with the new user's email, admin flag,
          and creation timestamp.
        """

        data = request.get_json()

        if data is None:
            error(400, "No json data in request body")

        check_data_fields(data,
                          ["email", "name", "group_name", "password", "admin"])

        if len(data["password"]) < 8:
            error(422, "New password is less than 8 characters long!")

        password_hash = generate_password_hash(data["password"])

        try:
            create_user_result = user_db_util.create(
                g.database,
                email=data["email"],
                name=data["name"],
                group_name=data["group_name"],
                password_hash=password_hash,
                admin=data["admin"],
            )

        except UniqueViolation:
            error(422, "User with that email address already exists")

        response_data = {
            "user_id": create_user_result["user_id"],
            "email": create_user_result["email"],
            "admin": create_user_result["admin"],
            "name": create_user_result["name"],
            "group_name": create_user_result["group_name"],
            "timestamp": create_user_result["date_created"],
        }

        return jsonify(response_data), 201
示例#9
0
    def post(self):
        request_data = request.get_json()

        if request_data is None:
            error(400, "No json data in request body")

        check_data_fields(
            request_data,
            ["first_name", "last_name", "middle_name", "birth_date"])

        cipher = DataCipher(key=current_app.config.get("SECRET_KEY"))

        if not "oeci_token" in request.cookies.keys():
            error(401, "Missing login credentials to OECI.")

        decrypted_credentials = cipher.decrypt(request.cookies["oeci_token"])

        crawler = Crawler()

        login_result = crawler.login(decrypted_credentials["oeci_username"],
                                     decrypted_credentials["oeci_password"],
                                     close_session=False)

        if login_result is False:
            error(401, "Attempted login to OECI failed")

        record = crawler.search(request_data["first_name"],
                                request_data["last_name"],
                                request_data["middle_name"],
                                request_data["birth_date"])

        expunger = Expunger(record)
        expunger.run()

        try:
            save_result(request_data, record)
        except Exception as ex:
            logging.error("Saving search result failed with exception: %s" %
                          ex,
                          stack_info=True)

        response_data = {"data": {"record": record}}

        current_app.json_encoder = ExpungeModelEncoder

        return response_data  #Json-encoding happens automatically here
示例#10
0
    def post(self):
        """
        Create a new user with provided email, password, and admin flag.
        - If required fields are missing in the request, return 400
        - Password must be 8 or more characters long. Otherwise return 422
        - Email must not already be in use by an existing user.
          Otherwise return 422
        - If success, return 201 with the new user's email, admin flag,
          and creation timestamp.
        """

        data = request.get_json()

        if data is None:
            error(400, "No json data in request body")

        # print("data received by Users.post():", data)
        check_data_fields(data,
                          ['email', 'name', 'group_name', 'password', 'admin'])

        if len(data['password']) < 8:
            error(422, 'New password is less than 8 characters long!')

        password_hash = generate_password_hash(data['password'])

        try:
            create_user_result = user.create(g.database,
                                             email=data['email'],
                                             name=data['name'],
                                             group_name=data['group_name'],
                                             password_hash=password_hash,
                                             admin=data['admin'])

        except UniqueViolation:
            error(422, 'User with that email address already exists')

        response_data = {
            'email': create_user_result['email'],
            'admin': create_user_result['admin'],
            'timestamp': create_user_result['date_created'],
        }
        # user_id is not required by the frontend here so it is not included.
        # other endpoints may expose the user_id e.g. for other admin
        # user-management operations.

        return jsonify(response_data), 201
示例#11
0
    def post(self):
        data = request.get_json()

        if data == None:
            error(400, "No json data in request body")

        check_data_fields(data, ['email', 'password'])

        user_db_result = get_user_by_email(g.database, data['email'])

        if (not user_db_result or
                not check_password_hash(user_db_result['hashed_password'], data['password'])):
            error(401, 'Invalid username or password')

        response_data = {
            'auth_token': get_auth_token(current_app, user_db_result['user_id'])
        }
        return jsonify(response_data)
示例#12
0
    def post(self):
        request_data = request.get_json()

        if request_data is None or not request_data.get("names"):
            error(400, "No json data in request body")

        for alias in request_data["names"]:
            check_data_fields(
                alias,
                ["first_name", "last_name", "middle_name", "birth_date"])

        record = build_record()
        record_summary = RecordSummarizer.summarize(record)
        response_data = {"data": {"record": record_summary}}

        current_app.json_encoder = ExpungeModelEncoder

        return response_data  # Json-encoding happens automatically here
示例#13
0
    def post(self):
        """
        Attempts to log in to the OECI web site using the provided username
        and password if successful, encrypt those credentials and return them
        in a cookie. If the credentials
        """

        data = request.get_json()

        if data is None:
            error(400, "No json data in request body")

        check_data_fields(data, ["oeci_username", "oeci_password"])

        credentials = {
            "oeci_username": data["oeci_username"],
            "oeci_password": data["oeci_password"]
        }

        login_result = (data["oeci_username"] == "username"
                        and data["oeci_password"] == "password")

        if not login_result:
            error(401, "Invalid OECI username or password.")

        cipher = DataCipher(key=current_app.config.get("JWT_SECRET_KEY"))

        encrypted_credentials = cipher.encrypt(credentials)

        response = make_response()

        response.set_cookie(
            "oeci_token",
            # currently nginx/flask app are running as HTTP
            # secure=True requires HTTPS to maintain secure cookies
            # https://resources.infosecinstitute.com/securing-cookies-httponly-secure-flags/#gref
            # We will need an OECILogout endpoint to remove httponly=true cookies from frontend
            secure=False,
            httponly=False,
            samesite="strict",
            expires=time.time() + 15 * 60,  # 15 minutes
            value=encrypted_credentials)

        return response, 201
示例#14
0
    def post(self):
        request_data = request.get_json()

        if request_data is None:
            error(400, "No json data in request body")

        check_data_fields(request_data, ["first_name", "last_name",
                                 "middle_name", "birth_date"])

        cipher = DataCipher(
            key=current_app.config.get("JWT_SECRET_KEY"))

        decrypted_credentials = cipher.decrypt(request.cookies["oeci_token"])

        crawler = Crawler()

        login_result = crawler.login(
            decrypted_credentials["oeci_username"],
            decrypted_credentials["oeci_password"],
            close_session=False)

        if login_result is False:
            error(401, "Attempted login to OECI failed")

        record = crawler.search(
            request_data["first_name"],
            request_data["last_name"],
            request_data["middle_name"],
            request_data["birth_date"])

        expunger = Expunger(record)
        expunger.run()

        response_data = {
            "data": {
                "record": record
            }
        }

        current_app.json_encoder = ExpungeModelEncoder

        return response_data #Json-encoding happens automatically here
示例#15
0
    def post(self):
        """
        Attempts to log in to the OECI web site using the provided username
        and password if successful, encrypt those credentials and return them
        in a cookie. If the credentials
        """

        data = request.get_json()

        if data is None:
            error(400, "No json data in request body")

        check_data_fields(data, ["oeci_username", "oeci_password"])

        credentials = {"oeci_username": data["oeci_username"],
                       "oeci_password": data["oeci_password"]}

        login_result = Crawler().login(
            credentials["oeci_username"],
            credentials["oeci_password"],
            close_session=True)

        if not login_result:
            error(401, "Invalid OECI username or password.")

        cipher = DataCipher(
            key=current_app.config.get("JWT_SECRET_KEY"))

        encrypted_credentials = cipher.encrypt(credentials)

        response = make_response()

        response.set_cookie(
            "oeci_token",
            secure=True,
            httponly=True,
            samesite="strict",
            expires=time.time() + 15 * 60,  # 15 minutes
            value=encrypted_credentials)

        return response, 201
示例#16
0
 def _validate_request(request_data):
     check_data_fields(request_data, ["aliases"])
     for alias in request_data["aliases"]:
         check_data_fields(alias, ["first_name", "last_name", "middle_name", "birth_date"])
示例#17
0
    def post(self):
        request_data = request.get_json()

        if request_data is None:
            error(400, "No json data in request body")

        check_data_fields(
            request_data,
            ["first_name", "last_name", "middle_name", "birth_date"])

        cipher = DataCipher(key=current_app.config.get("JWT_SECRET_KEY"))

        decrypted_credentials = cipher.decrypt(request.cookies["oeci_token"])

        crawler = Crawler()

        login_result = (decrypted_credentials["oeci_username"] == "username"
                        and decrypted_credentials["oeci_password"]
                        == "password")

        if login_result is False:
            error(401, "Attempted login to OECI failed")

        response_data = json.loads("""{"data": {"record": {
    "total_balance_due": 4550.4,
    "cases": [
        {
            "name": "Doe, John D",
            "birth_year": 1943,
            "case_number": "X0001",
            "citation_number": "C0001",
            "location": "Multnomah",
            "date": "Sat, 23 Mar 1963 00:00:00 GMT",
            "violation_type": "Offense Misdemeanor",
            "current_status": "Closed",
            "charges": [
                {
                    "name": "Driving Uninsured",
                    "statute": "806010",
                    "level": "Class B Felony",
                    "date": "Sun, 12 Mar 2017 00:00:00 GMT",
                    "disposition": {
                        "date": "Mon, 12 Jun 2017 00:00:00 GMT",
                        "ruling": "Convicted - Failure to Appear"
                    },
                    "expungement_result": {
                        "type_eligibility": false,
                        "type_eligibility_reason": "Ineligible under 137.225(5)",
                        "time_eligibility": null,
                        "time_eligibility_reason": null,
                        "date_of_eligibility": null
                    }
                },
                {
                    "name": "Violation Driving While Suspended or Revoked",
                    "statute": "811175",
                    "level": "Class B Felony",
                    "date": "Sun, 12 Mar 2017 00:00:00 GMT",
                    "disposition": {
                        "date": "Mon, 12 Jun 2017 00:00:00 GMT",
                        "ruling": "Dismissed"
                    },
                    "expungement_result": {
                        "type_eligibility": true,
                        "type_eligibility_reason": "Eligible under 137.225(1)(b)",
                        "time_eligibility": null,
                        "time_eligibility_reason": null,
                        "date_of_eligibility": null
                    }
                },
                {
                    "name": "Failure to Obey Traffic Control Device",
                    "statute": "811265",
                    "level": "Class B Felony",
                    "date": "Sun, 12 Mar 2017 00:00:00 GMT",
                    "disposition": {
                        "date": "Mon, 12 Jun 2017 00:00:00 GMT",
                        "ruling": "Dismissed"
                    },
                    "expungement_result": {
                        "type_eligibility": true,
                        "type_eligibility_reason": "Eligible under 137.225(1)(b)",
                        "time_eligibility": null,
                        "time_eligibility_reason": null,
                        "date_of_eligibility": null
                    }
                }
            ],
            "balance_due": 1516.8,
            "case_detail_link": "https://publicaccess.courts.oregon.gov/PublicAccessLogin/CaseDetail.aspx?CaseID=X0001"
        },
        {
            "name": "Doe, John D",
            "birth_year": 1943,
            "case_number": "X0002",
            "citation_number": "C0002",
            "location": "Multnomah",
            "date": "Thu, 11 Apr 1963 00:00:00 GMT",
            "violation_type": "Offense Felony",
            "current_status": "Closed",
            "charges": [
                {
                    "name": "Driving Uninsured",
                    "statute": "806010",
                    "level": "Class B Felony",
                    "date": "Sun, 12 Mar 2017 00:00:00 GMT",
                    "disposition": {
                        "date": "Mon, 12 Jun 2017 00:00:00 GMT",
                        "ruling": "Convicted - Failure to Appear"
                    },
                    "expungement_result": {
                        "type_eligibility": false,
                        "type_eligibility_reason": "Ineligible under 137.225(5)",
                        "time_eligibility": null,
                        "time_eligibility_reason": null,
                        "date_of_eligibility": null
                    }
                },
                {
                    "name": "Violation Driving While Suspended or Revoked",
                    "statute": "811175",
                    "level": "Class B Felony",
                    "date": "Sun, 12 Mar 2017 00:00:00 GMT",
                    "disposition": {
                        "date": "Mon, 12 Jun 2017 00:00:00 GMT",
                        "ruling": "Dismissed"
                    },
                    "expungement_result": {
                        "type_eligibility": true,
                        "type_eligibility_reason": "Eligible under 137.225(1)(b)",
                        "time_eligibility": null,
                        "time_eligibility_reason": null,
                        "date_of_eligibility": null
                    }
                },
                {
                    "name": "Failure to Obey Traffic Control Device",
                    "statute": "811265",
                    "level": "Class B Felony",
                    "date": "Sun, 12 Mar 2017 00:00:00 GMT",
                    "disposition": {
                        "date": "Mon, 12 Jun 2017 00:00:00 GMT",
                        "ruling": "Dismissed"
                    },
                    "expungement_result": {
                        "type_eligibility": true,
                        "type_eligibility_reason": "Eligible under 137.225(1)(b)",
                        "time_eligibility": null,
                        "time_eligibility_reason": null,
                        "date_of_eligibility": null
                    }
                }
            ],
            "balance_due": 1516.8,
            "case_detail_link": "https://publicaccess.courts.oregon.gov/PublicAccessLogin/CaseDetail.aspx?CaseID=X0002"
        },
        {
            "name": "Doe, John D",
            "birth_year": 1943,
            "case_number": "X0003",
            "citation_number": "",
            "location": "Multnomah",
            "date": "Sun, 01 Apr 2012 00:00:00 GMT",
            "violation_type": "Offense Misdemeanor",
            "current_status": "Closed",
            "charges": [
                {
                    "name": "Driving Uninsured",
                    "statute": "806010",
                    "level": "Class B Felony",
                    "date": "Sun, 12 Mar 2017 00:00:00 GMT",
                    "disposition": {
                        "date": "Mon, 12 Jun 2017 00:00:00 GMT",
                        "ruling": "Convicted - Failure to Appear"
                    },
                    "expungement_result": {
                        "type_eligibility": false,
                        "type_eligibility_reason": "Ineligible under 137.225(5)",
                        "time_eligibility": null,
                        "time_eligibility_reason": null,
                        "date_of_eligibility": null
                    }
                },
                {
                    "name": "Violation Driving While Suspended or Revoked",
                    "statute": "811175",
                    "level": "Class B Felony",
                    "date": "Sun, 12 Mar 2017 00:00:00 GMT",
                    "disposition": {
                        "date": "Mon, 12 Jun 2017 00:00:00 GMT",
                        "ruling": "Dismissed"
                    },
                    "expungement_result": {
                        "type_eligibility": true,
                        "type_eligibility_reason": "Eligible under 137.225(1)(b)",
                        "time_eligibility": null,
                        "time_eligibility_reason": null,
                        "date_of_eligibility": null
                    }
                },
                {
                    "name": "Failure to Obey Traffic Control Device",
                    "statute": "811265",
                    "level": "Class B Felony",
                    "date": "Sun, 12 Mar 2017 00:00:00 GMT",
                    "disposition": {
                        "date": "Mon, 12 Jun 2017 00:00:00 GMT",
                        "ruling": "Dismissed"
                    },
                    "expungement_result": {
                        "type_eligibility": true,
                        "type_eligibility_reason": "Eligible under 137.225(1)(b)",
                        "time_eligibility": null,
                        "time_eligibility_reason": null,
                        "date_of_eligibility": null
                    }
                }
            ],
            "balance_due": 1516.8,
            "case_detail_link": "https://publicaccess.courts.oregon.gov/PublicAccessLogin/CaseDetail.aspx?CaseID=X0003"
        }
    ],
    "errors": []
}

}}""")
        return response_data  #Json-encoding happens automatically here