Beispiel #1
0
def get_gps_events(db,
                   device_ids,
                   page_number=1,
                   per_page=30,
                   time_from=None,
                   time_to=None):
    """Retrieve gps events from the database for one or more devices

    Returns gps events as a list of dicts
    """
    if isinstance(device_ids, str):
        device_ids = [device_ids]

    if time_from is None:
        time_from = utils.now_at_utc() - datetime.timedelta(days=90)
    if time_to is None:
        time_to = utils.now_at_utc() + datetime.timedelta(hours=1)

    events = []
    total = 0
    for (
            plaform,
            osversion,
            appversion,
            model,
            time_from,
            time_to,
            latitude,
            longitude,
            accuracy,
            speed,
            speed_accuracy,
            altitude,
            altitude_accuracy,
            total,
    ) in db.execute(
            "{CALL getdatabyUUIDList (?,?,?,?,?)}",
        (",".join(device_ids), time_from, time_to, page_number, per_page),
    ).fetchall():
        # from schema, *all* fields are nullable
        # so make sure that any casting handles None
        event = {
            "time_from": utils.isoformat(time_from),
            "time_to": utils.isoformat(time_to),
            "latitude": cast_nullable_float(latitude),
            "longitude": cast_nullable_float(longitude),
            "accuracy": accuracy,
            "speed": speed,
            "speed_accuracy": speed_accuracy,
            "altitude": altitude,
            "altitude_accuracy": altitude_accuracy,
        }
        events.append(event)
    return events, total
Beispiel #2
0
async def generate_and_store_pin(phone_number):
    pin_code = generate_pin()
    timestamp = utils.now_at_utc()
    await store_pin_code(
        phone_number=phone_number, pin_code=pin_code, timestamp=timestamp,
    )
    return pin_code
Beispiel #3
0
def main(port):
    tornado.options.parse_command_line()
    # first-thing, check the database connection
    test_number = "+0010101011"
    for i in range(2):
        # perform an initial connect and query to validate our connection and permissions
        app_log.info("Checking access log routines")
        asyncio.run(
            sql.log_access(
                phone_numbers=[test_number],
                timestamp=utils.now_at_utc(),
                person_name="Smittestopp Backend",
                person_id="",
                person_organization="Simula Research Laboratory",
                organization="Simula Research Laboratory",
                legal_means="Vedlikehold",
            ))
        asyncio.run(sql.get_access_log(test_number, per_page=2))
        # app_log.info("Checking gps log routine")
        # asyncio.run(sql.get_gps_events([device_id]), per_page=1)

    # after calling run, there's no loop!
    asyncio.set_event_loop(asyncio.new_event_loop())

    app_log.info("Database connection okay!")

    graph.keep_jwt_keys_updated()
    start_app(
        endpoints(),
        port,
    )
async def insert_test_applog():
    await sql.log_access(
        timestamp=utils.now_at_utc(),
        phone_numbers=["+0012341234"],
        person_name="For Etternavn",
        person_organization="Some Organization",
        person_id="",
        organization="Norsk Helsenett",
        legal_means="Some legal means",
    )

    await sql.log_access(
        timestamp=utils.now_at_utc(),
        phone_numbers=["+0012341234"],
        person_name="",
        person_organization="Some Other Organization",
        person_id="",
        organization="Norsk Helsenett",
        legal_means="Some legal means",
    )
async def insert_pin_test_data():
    with testsql.set_db_user(testsql.DB_USER_SERVICE_API):
        # Pin created more than a week ago - not reusable.
        await pin.store_pin_code(
            phone_number="+0012341234",
            pin_code="testdbpinX",
            timestamp=utils.now_at_utc() - timedelta(days=17),
        )

        # Pin created less than a week ago - reusable.
        await pin.store_pin_code(
            phone_number="+0012341234",
            pin_code="testdbpin1",
            timestamp=utils.now_at_utc() - timedelta(days=6, minutes=1),
        )

        # Pin created more than a week ago - not reusable.
        await pin.store_pin_code(
            phone_number="+0012341236",
            pin_code="testdbpin2",
            timestamp=utils.now_at_utc() - timedelta(days=7, minutes=1),
        )
Beispiel #6
0
async def fetch_or_generate_pin(phone_number, not_older_than=7):
    """ Fetch pin from database or generate now if too old

    If there are no pin codes associated with a phone number we create a new.
    If there are, but the latest is older than 'not_older_than', we also create a new.
    Otherwise we use the latest.
    """

    threshold = utils.now_at_utc() - timedelta(days=not_older_than)

    pin = await get_latest_pin_code_after_threshold(
        phone_number=phone_number, threshold=threshold
    )
    if pin is None:
        pin = await generate_and_store_pin(phone_number=phone_number)
    return pin
Beispiel #7
0
    async def audit_log(
        self,
        phone_numbers,
        person_name=None,
        person_id=None,
        person_organization=None,
        organization=None,
        legal_means=None,
    ):
        """Store an entry in the audit log"""
        timestamp = utils.now_at_utc()

        if person_name is None:
            person_name = self.audit_fields["person_name"]
        if person_id is None:
            person_id = self.audit_fields["person_id"]
        if person_organization is None:
            person_organization = self.audit_fields["person_organization"]
        if organization is None:
            organization = self.audit_fields["organization"]
        if legal_means is None:
            legal_means = self.audit_fields["legal_means"]
        if not organization:
            raise ValueError("organization required!")
        if not legal_means:
            raise ValueError("legal_means required!")

        try:
            await sql.log_access(
                timestamp=timestamp,
                phone_numbers=phone_numbers,
                person_name=person_name,
                person_id=person_id,
                person_organization=person_organization,
                organization=organization,
                legal_means=legal_means,
            )
        except pyodbc.InterfaceError as e:
            app_log.exception("Connection error in sql.log_access")
            raise web.HTTPError(
                503, "Internal temporary server error - please try again")
Beispiel #8
0
    async def post(self):
        body = self.get_json_body()
        phone_number = body["phone_number"]
        user = await self.lookup_user(phone_number)

        await self.audit_log(phone_numbers=[phone_number])

        phone_number = user["displayName"]
        mask_number = user["logName"]

        device_ids = []

        request_id = str(uuid.uuid4())
        app_log.info(
            f"Submitting analysis jobs for {mask_number}: {request_id}")
        request_info = f"lookup:{request_id}:info"
        # create job queue in redis

        db = get_redis()
        result_keys = []

        async for device_id in graph.device_ids_for_user(user):
            device_ids.append(device_id)
            result_key = f"lookup:{request_id}:result:{device_id}"
            result_keys.append(result_key)
            app_log.info(f"Submitting analysis job for {device_id}")
            job = {
                "request_id": request_id,
                "device_id": device_id,
                "result_key": result_key,
                "time_from": utils.isoformat(body.get("time_from")),
                "time_to": utils.isoformat(body.get("time_to")),
                "expiry": LOOKUP_RESULT_EXPIRY,
            }
            db.rpush(REDIS_JOBQUEUE_NAME, json.dumps(job).encode("utf8"))
            # push device id onto job queue
        if not device_ids:
            app_log.info(f"Phone number {mask_number} has no devices")
            self.set_status(404)
            self.write(
                json.dumps({
                    "phone_number": phone_number,
                    "found_in_system": False
                }))
            return

        app_log.info(f"Storing request info for {request_id}")
        db.set(
            request_info,
            json.dumps({
                "phone_number": phone_number,
                "result_keys": result_keys,
                "device_ids": device_ids,
            }),
            ex=LOOKUP_RESULT_EXPIRY,
        )

        self.set_status(202)
        self.write(
            json.dumps({
                "request_id":
                request_id,
                # todo: figure out how to get this right?
                # /fhi/ prefix isn't available from APIM
                # but it's wrong when not behind APIM
                "result_url":
                f"https://{self.request.host}/fhi/lookup/{request_id}",
                "result_expires":
                utils.isoformat(utils.now_at_utc() + datetime.timedelta(
                    seconds=LOOKUP_RESULT_EXPIRY)),
            }))