def test_upload_seeds(test_context):
    (client_db_path, server_db) = test_context

    # Upload contacts from database
    client_proc = subprocess.run([
        script_path("device/upload_seeds.py"),
        "-d",
        "-D",
        client_db_path,
        "-s",
        SERVER_URL,
        "-v",
        (START_TIME + timedelta(minutes=2 * EPOCH_LENGTH)).isoformat(),
        (START_TIME + timedelta(minutes=8 * EPOCH_LENGTH)).isoformat(),
    ])
    assert client_proc.returncode == 0

    # See if they arrived in the server database
    (epochs, seeds) = server_db.get_epoch_seeds_tuple()
    assert (epoch_from_time(START_TIME + timedelta(minutes=2 * EPOCH_LENGTH)) -
            1 not in epochs)
    assert epoch_from_time(START_TIME +
                           timedelta(minutes=2 * EPOCH_LENGTH)) in epochs
    assert epoch_from_time(START_TIME +
                           timedelta(minutes=8 * EPOCH_LENGTH)) in epochs
    assert (epoch_from_time(START_TIME + timedelta(minutes=8 * EPOCH_LENGTH)) +
            1 not in epochs)
    assert bytes.fromhex("deadbeef06") in seeds
示例#2
0
def main():
    print("## Test vectors computing EphID given a seed ##")
    for seed_str in [SEED0, SEED1]:
        seed = bytes.fromhex(seed_str)
        ephid = ephid_from_seed(seed)

        print(" - Seed:", seed.hex())
        print(" - EphID:", ephid.hex())
        print()

    print("\n## Test vectors computing epoch number ##")
    for time in [TIME0, TIME1, TIME2]:
        print(" - Time:", time.isoformat(" "))
        print(" - Epoch Number:", epoch_from_time(time))
        print()

    print("\n## Test vector hashed observed EphIDs ##")
    ephid = ephid_from_seed(bytes.fromhex(SEED1))
    for time in [TIME0, TIME1, TIME2]:
        epoch = epoch_from_time(time)
        print(" - EphID:", ephid.hex())
        print(" - Time:", time.isoformat(" "))
        print(" - Epoch:", epoch)
        print(" - Hashed observation:",
              hashed_observation_from_ephid(ephid, epoch).hex())
        print()
示例#3
0
def test_delete_epoch_seeds(db_connection):
    time_out = datetime(2020, 4, 25, 20, 59, tzinfo=timezone.utc)
    time_in = datetime(2020, 4, 25, 21, 1, tzinfo=timezone.utc)
    db_connection.add_epoch_seed(epoch_from_time(time_out), "out")
    db_connection.add_epoch_seed(epoch_from_time(time_in), "in")

    all_records = db_connection.get_epoch_seeds()
    assert sum(1 for _ in all_records) == 2

    db_connection.delete_expired_data(
        datetime(2020, 4, 25, 21, 00, tzinfo=timezone.utc))

    all_records = db_connection.get_epoch_seeds()
    for (epoch, seed) in all_records:
        assert epoch == epoch_from_time(time_in)
        assert seed == b"in"
示例#4
0
    def _create_new_day_ephids(self):
        """Compute a new set of seeds and ephids for a new day"""

        # The ephids are required by the transmitter
        if not self.transmitter:
            return

        # Generate fresh seeds and store them
        seeds = [generate_new_seed() for _ in range(NUM_EPOCHS_PER_DAY)]
        ephids = [ephid_from_seed(seed) for seed in seeds]

        # Convert to epoch numbers
        first_epoch = epoch_from_time(self.start_of_today)

        with self.db.atomic():
            # Verify the ids have not been already been created
            if self.db.get_epoch_seeds(first_epoch, first_epoch + 1):
                return

            # Store seeds and compute EphIDs
            for relative_epoch in range(0, NUM_EPOCHS_PER_DAY):
                self.db.add_epoch_ids(
                    first_epoch + relative_epoch,
                    seeds[relative_epoch],
                    ephids[relative_epoch],
                )
示例#5
0
def test_check_advance_day_firing(contact_tracer):
    with Replace("dp3t.protocols.unlinkable_db.datetime",
                 test_datetime(**START_TIME_TOMORROW)):
        contact_tracer.check_advance_day(datetime(**START_TIME_TOMORROW))
    epoch = epoch_from_time(datetime(**START_TIME_TOMORROW))
    seeds = contact_tracer.db.get_epoch_seeds(epoch, epoch + 1)
    assert len(seeds) == 1
示例#6
0
    def get_tracing_information(self,
                                first_contagious_time,
                                last_contagious_time=None):
        """Return the seeds corresponding to the requested time range

        *Warning:* This function should not be used to retrieve tracing
        information for future epochs to limit the amount of linking
        information available to the server. Unfortunately, this class does not
        have a notion of the exact time, so it is up to the caller to verify
        this constraint.

        Args:
            first_contagious_time (:obj:`datetime.datetime`): The time from which we
                 should start tracing
            last_contagious_time (:obj:`datatime.datatime`, optional): The last time
                 for tracing. Default value: the beginning of the current day.

        Returns:
            epochs: the epochs
            seeds: the corresponding seeds

        Raises:
            ValueError: If the requested key is unavailable or if
                last_contagious_time is before first_contagious_time
        """

        if last_contagious_time is None:
            last_contagious_time = self.start_of_today

        if last_contagious_time < first_contagious_time:
            raise ValueError(
                "Last_contagious_time should be after first_contagious_time")

        start_epoch = epoch_from_time(first_contagious_time)
        end_epoch = epoch_from_time(last_contagious_time)
        reported_epochs = range(start_epoch, end_epoch + 1)

        return reported_epochs, self.get_tracing_seeds_for_epochs(
            reported_epochs)
def test_context():
    # Initialize client database
    (client_db_handle, client_db_path) = mkstemp()
    close(client_db_handle)
    client_db = ClientDatabase(client_db_path)

    # Add seeds to the client database
    for i in range(0, 10):
        e = epoch_from_time(START_TIME + timedelta(minutes=i * EPOCH_LENGTH))
        client_db.add_epoch_ids(e, bytes.fromhex(f"deadbeef0{i}"), f"E{i}")
    close(client_db_handle)
    # subprocess.call(["/home/dds/src/epidose/utils/client-db-report.sh", client_db_path])

    # Instantiate the back-end server
    (server_db_handle, server_db_path) = mkstemp()
    close(server_db_handle)
    server_proc = subprocess.Popen([
        script_path("back_end/ha_server.py"), "-d", "-v", "-D", server_db_path
    ])

    # Wait for server to come up
    count = 0
    while True:
        try:
            res = requests.get(f"{SERVER_URL}/version")
            if res.ok:
                break
        except requests.exceptions.ConnectionError:
            pass
        sleep(0.1)
        count += 0.1
        # Timeout after 5s
        if count > 5:
            raise TimeoutError

    server_db = ServerDatabase(server_db_path)

    yield (client_db_path, server_db)
    # Shutdown the server
    res = requests.get(f"{SERVER_URL}/shutdown")
    assert res.ok

    # Wait for the server to finish
    server_proc.wait()

    # Cleanup
    server_db.close()
    remove(server_db_path)
    remove(client_db_path)
示例#8
0
    def get_ephid_for_time(self, time):
        """Return the EphID corresponding to the requested time

        Args:
            time (:obj:`datetime.datetime`): The requested time

        Raises:
            ValueError: If the requested ephid is unavailable
        """
        # Convert to epoch number
        epoch = epoch_from_time(time)

        ephid = self.db.get_epoch_ephid(epoch)
        if not ephid:
            raise ValueError("EphID not available, did you call next_day()?")

        return ephid
示例#9
0
    def add_observation(self, ephid, time, rssi=0):
        """Add ephID to list of observations. Time must correspond to the current day

        Args:
            ephID (byte array): the observed ephID
            time (:obj:`datatime.datetime`): time of observation
            rssi: the observation's received signal strength indicator

        Raises:
            ValueError: If time does not correspond to the current day
        """

        if not time.date() == self.today:
            raise ValueError("Observation must correspond to current day")

        epoch = epoch_from_time(time)
        hashed_observation = hashed_observation_from_ephid(ephid, epoch)
        self.db.add_observation(day_timestamp(self.today), hashed_observation,
                                rssi)
示例#10
0
    def next_day(self):
        """Setup seeds and EphIDs for the next day, and do housekeeping"""

        # Update current day
        self.start_of_today = self.start_of_today + timedelta(days=1)

        # Generate new EphIDs for new day
        self._create_new_day_ephids()

        # Remove old observations
        if self.receiver:
            last_retained_day = self.today - timedelta(days=RETENTION_PERIOD)
            self.db.delete_past_observations(day_timestamp(last_retained_day))

        # Remove old seeds and ephids
        if self.transmitter:
            days_back = timedelta(days=RETENTION_PERIOD)
            last_valid_time = self.start_of_today - days_back
            last_retained_epoch = epoch_from_time(last_valid_time)
            self.db.delete_past_epoch_ids(last_retained_epoch)
示例#11
0
 def delete_expired_data(self, last_retained_day):
     """Delete contagious user data that has expired."""
     last_retained_epoch = epoch_from_time(last_retained_day)
     query = ContagiousIds.delete().where(
         ContagiousIds.epoch < last_retained_epoch)
     query.execute()
示例#12
0
def test_epoch_from_time():
    epoch0 = epoch_from_time(TIME0)
    assert epoch0 == EPOCH0

    epoch1 = epoch_from_time(TIME1)
    assert epoch1 == EPOCH1
示例#13
0
def test_check_next_day_empty(contact_tracer):
    epoch = epoch_from_time(START_TIME + timedelta(days=1))
    seeds = contact_tracer.db.get_epoch_seeds(epoch, epoch + 1)
    assert len(seeds) == 0
示例#14
0
def test_seeds_initialized(contact_tracer):
    epoch = epoch_from_time(START_TIME)
    seeds = contact_tracer.db.get_epoch_seeds(epoch, epoch + 1)
    assert len(seeds) == 1
示例#15
0
def test_no_seeds_for_receiver():
    ct = ContactTracer(start_time=START_TIME, transmitter=False)
    epoch = epoch_from_time(START_TIME)
    seeds = ct.db.get_epoch_seeds(epoch, epoch + 1)
    assert len(seeds) == 0
    ct.db.close()