Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consume new endpoint to return last 14 days keys after onboarding #227

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ APP_VERSION_NAME=1.0
SUBMIT_URL=https://submission.covidshield.app
RETRIEVE_URL=https://retrieval.covidshield.app
HMAC_KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
REGION=302
MCC_CODE=302;
REGION=302;
TRANSMISSION_RISK_LEVEL=2
MINIMUM_FETCH_INTERVAL=15

Expand Down
25 changes: 24 additions & 1 deletion src/services/BackendService/BackendService.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {downloadDiagnosisKeysFile} from '../../bridge/CovidShield';
import {TemporaryExposureKey} from '../../bridge/ExposureNotification';

import {BackendService} from './BackendService';
Expand Down Expand Up @@ -89,7 +90,7 @@ describe('BackendService', () => {

describe('reportDiagnosisKeys', () => {
it('returns last 14 keys if there is more than 14', async () => {
const backendService = new BackendService('http://localhost', 'https://localhost', 'mock', 0);
const backendService = new BackendService('http://localhost', 'https://localhost', 'mock', 302);
const keys = generateRandomKeys(20);

await backendService.reportDiagnosisKeys(
Expand All @@ -115,4 +116,26 @@ describe('BackendService', () => {
});
});
});

describe('retrieveDiagnosisKeys', () => {
it('returns keys file for set period', async () => {
const backendService = new BackendService('http://localhost', 'https://localhost', 'mock', 302);

await backendService.retrieveDiagnosisKeys(18457);

expect(downloadDiagnosisKeysFile).toHaveBeenCalledWith(
'http://localhost/retrieve/302/18457/c4d9820c20f7073e47f54cc1bd24475fb98c8ab9ffc0ea81dded3f8ebfb48b67',
);
});

it('returns keys file for 14 days if period is 0', async () => {
const backendService = new BackendService('http://localhost', 'https://localhost', 'mock', 302);

await backendService.retrieveDiagnosisKeys(0);

expect(downloadDiagnosisKeysFile).toHaveBeenCalledWith(
'http://localhost/retrieve/302/00000/ca365ad512568f4292953403590b398e3f1336efcb4f1acedb20926c35408bd9',
);
});
});
});
12 changes: 8 additions & 4 deletions src/services/BackendService/BackendService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {TemporaryExposureKey} from 'bridge/ExposureNotification';
import nacl from 'tweetnacl';
import {getRandomBytes, downloadDiagnosisKeysFile} from 'bridge/CovidShield';
import {blobFetch} from 'shared/fetch';
import {TRANSMISSION_RISK_LEVEL, REGION} from 'env';
import {TRANSMISSION_RISK_LEVEL} from 'env';
import {captureMessage} from 'shared/log';

import {covidshield} from './covidshield';
Expand All @@ -15,6 +15,9 @@ import {BackendInterface, SubmissionKeySet} from './types';
const MAX_UPLOAD_KEYS = 14;
const FETCH_HEADERS = {headers: {'Cache-Control': 'no-store'}};

// See https://github.com/cds-snc/covid-shield-server/pull/176
const LAST_14_DAYS_PERIOD = '00000';

export class BackendService implements BackendInterface {
retrieveUrl: string;
submitUrl: string;
Expand All @@ -29,15 +32,16 @@ export class BackendService implements BackendInterface {
}

async retrieveDiagnosisKeys(period: number) {
const message = `${this.region}:${period}:${Math.floor(Date.now() / 1000 / 3600)}`;
const periodStr = `${period > 0 ? period : LAST_14_DAYS_PERIOD}`;
const message = `${this.region}:${periodStr}:${Math.floor(Date.now() / 1000 / 3600)}`;
const hmac = hmac256(message, encHex.parse(this.hmacKey)).toString(encHex);
const url = `${this.retrieveUrl}/retrieve/${this.region}/${period}/${hmac}`;
const url = `${this.retrieveUrl}/retrieve/${this.region}/${periodStr}/${hmac}`;
captureMessage('retrieveDiagnosisKeys', {period, url});
return downloadDiagnosisKeysFile(url);
}

async getExposureConfiguration() {
const url = `${this.retrieveUrl}/exposure-configuration/${REGION}.json`;
const url = `${this.retrieveUrl}/exposure-configuration/${this.region}.json`;
captureMessage('getExposureConfiguration', {url});
return (await fetch(url, FETCH_HEADERS)).json();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe('ExposureNotificationService', () => {
.mockImplementation((args: any) => new OriginalDate(args));

await service.updateExposureStatus();
expect(server.retrieveDiagnosisKeys).toHaveBeenCalledTimes(14);
expect(server.retrieveDiagnosisKeys).toHaveBeenCalledTimes(1);
});

it('backfills the right amount of keys for current day', async () => {
Expand All @@ -98,7 +98,7 @@ describe('ExposureNotificationService', () => {
},
});
await service.updateExposureStatus();
expect(server.retrieveDiagnosisKeys).toHaveBeenCalledTimes(0);
expect(server.retrieveDiagnosisKeys).toHaveBeenCalledTimes(1);

server.retrieveDiagnosisKeys.mockClear();

Expand All @@ -109,7 +109,7 @@ describe('ExposureNotificationService', () => {
},
});
await service.updateExposureStatus();
expect(server.retrieveDiagnosisKeys).toHaveBeenCalledTimes(1);
expect(server.retrieveDiagnosisKeys).toHaveBeenCalledTimes(2);

server.retrieveDiagnosisKeys.mockClear();

Expand All @@ -120,7 +120,7 @@ describe('ExposureNotificationService', () => {
},
});
await service.updateExposureStatus();
expect(server.retrieveDiagnosisKeys).toHaveBeenCalledTimes(2);
expect(server.retrieveDiagnosisKeys).toHaveBeenCalledTimes(3);
});

it('serializes status update', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {Platform} from 'react-native';
import ExposureNotification, {
ExposureSummary,
Status as SystemStatus,
Expand Down Expand Up @@ -263,10 +262,20 @@ export class ExposureNotificationService {
): AsyncGenerator<{keysFileUrl: string; period: number} | null> {
const runningDate = new Date();

const lastCheckedPeriod =
_lastCheckedPeriod || periodSinceEpoch(addDays(runningDate, -EXPOSURE_NOTIFICATION_CYCLE), HOURS_PER_PERIOD);
let runningPeriod = periodSinceEpoch(runningDate, HOURS_PER_PERIOD);

if (!_lastCheckedPeriod) {
try {
const keysFileUrl = await this.backendInterface.retrieveDiagnosisKeys(0);
yield {keysFileUrl, period: runningPeriod};
} catch (error) {
captureException('Error while downloading batch files', error);
}
return;
}

const lastCheckedPeriod = Math.max(_lastCheckedPeriod - 1, runningPeriod - EXPOSURE_NOTIFICATION_CYCLE);

while (runningPeriod > lastCheckedPeriod) {
try {
const keysFileUrl = await this.backendInterface.retrieveDiagnosisKeys(runningPeriod);
Expand Down Expand Up @@ -339,12 +348,7 @@ export class ExposureNotificationService {
if (!value) continue;
const {keysFileUrl, period} = value;
keysFileUrls.push(keysFileUrl);

// Temporarily disable persisting lastCheckPeriod on Android
// Ref https://github.com/cds-snc/covid-shield-mobile/issues/453
if (Platform.OS !== 'android') {
lastCheckedPeriod = Math.max(lastCheckedPeriod || 0, period);
}
lastCheckedPeriod = Math.max(lastCheckedPeriod || 0, period);
}

captureMessage('performExposureStatusUpdate', {
Expand All @@ -365,11 +369,12 @@ export class ExposureNotificationService {
lastCheckedPeriod,
);
}
return finalize({}, lastCheckedPeriod);
} catch (error) {
captureException('performExposureStatusUpdate', error);
}

return finalize({}, lastCheckedPeriod);
return finalize();
}

private async processPendingExposureSummary() {
Expand Down