@velocitycareerlabs/server-careerwallet 1.25.0-dev-build.12642c864
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.localdev.env +47 -0
- package/.standalone.env +13 -0
- package/LICENSE +248 -0
- package/jest.config.js +20 -0
- package/migrate-mongo.config.js +25 -0
- package/migrations/20211017180227-create-personas.js +478 -0
- package/migrations/20211026185916-create-vanessa.js +79 -0
- package/migrations/20211026185917-update-personas.js +30 -0
- package/migrations/20211108124410-remove-surplus-personas.js +33 -0
- package/migrations/20211108132353-fix-vanessa-and-sheila.js +25 -0
- package/migrations/20220222123110-add-career-wallet-app-config.js +6 -0
- package/migrations/20220411104157-add-min-app-versions.js +15 -0
- package/migrations/20220419131726-create-nicole-flores-persona.js +63 -0
- package/migrations/20220515114034-update-persona-id-credentials.js +628 -0
- package/migrations/20220608093743-disable-mainnet-holderapp-id-verification.js +21 -0
- package/migrations/20220609063708-enable-mainnet-holderapp-id-verification.js +21 -0
- package/migrations/20220623091507-add-push-url.js +43 -0
- package/migrations/20220624133205-set-min-app-versions-to-11.js +16 -0
- package/migrations/20220710125326-set-min-app-version-to-0.10.7.js +16 -0
- package/migrations/20220811103500-add-verification-service-disclosure-deeplink.js +45 -0
- package/migrations/20220811123751-add-holderapp-dids-to-config.js +74 -0
- package/migrations/20220818072306-add-holderapp-endpoints-to-config.js +21 -0
- package/migrations/20220825090656-update-deeplink.js +46 -0
- package/migrations/20221003151823-app-config-add-public-verification-api.js +18 -0
- package/migrations/20221116085242-add-holderapp-sdk-to-config.js +15 -0
- package/migrations/20221121091030-update-holderapp-deeplink.js +19 -0
- package/migrations/20221128103425-update-holderapp-presentation-template.js +19 -0
- package/migrations/20221221091436-app-config-add-oauth.js +13 -0
- package/migrations/20221226205900-app-config-add-presentation-extension-api.js +18 -0
- package/migrations/20230120113141-update-holderapp-cashSiquence.js +15 -0
- package/migrations/20230123084103-update-holderapp-cacheSequence.js +15 -0
- package/migrations/20230214083430-update-holderapp-cache-Sequence.js +15 -0
- package/migrations/20230225173335-set-min-app-version-1.5.1.js +30 -0
- package/migrations/20230323120629-add-sunil-singh-persona.js +87 -0
- package/migrations/20230329081529-add-personas-by-env.js +294 -0
- package/migrations/20230329103219-remove-unused-personas.js +14 -0
- package/migrations/20230504090208-disable-yoti-migration.js +21 -0
- package/migrations/20230504123425-set-min-app-version-1.8.1.js +38 -0
- package/migrations/20230504185047-enable-yoti-migration.js +21 -0
- package/migrations/20230524053203-add-devices-index.js +16 -0
- package/migrations/20230704000002-add-common-holder-endpoints-to-config.js +16 -0
- package/migrations/20230704000003-add-linkedin-holder-endpoints-to-config.js +18 -0
- package/migrations/20230704104055-update-push-url-and-yoti-url.js +18 -0
- package/migrations/20230705000001-add-liburl-to-holderapp-config.js +20 -0
- package/migrations/20230814113134-app-config-add-oauth-client-id.js +18 -0
- package/migrations/20230821154136-yoti-new-session-url-fix.js +19 -0
- package/migrations/20230907134442-update-holderapp-cache-Sequence.js +15 -0
- package/migrations/20230919180000-set-holderapp-min-app-versions-1.15.0.js +16 -0
- package/migrations/20231011083137-update-holderapp-cache-sequence-6.js +15 -0
- package/migrations/20231102083252-set-holderapp-min-app-versions-1.14.0.js +16 -0
- package/migrations/20231108202229-set-holderapp-min-app-versions-1.15.0.js +16 -0
- package/migrations/20231115143332-holderapp-isDirectIssuerCheckOn-true.js +16 -0
- package/migrations/20231120100020-insert-didKeyMetadatum-for-old-accounts.js +59 -0
- package/migrations/20231207142742-remove-devices-from-accounts.js +46 -0
- package/migrations/20231226090805-app-config-set-direct-issuer-check.js +13 -0
- package/migrations/202312271524-set-holderapp-app-version-1.15.1.js +16 -0
- package/migrations/20232211171700-app-config-update-base-urls.js +18 -0
- package/migrations/20240102093506-holderapp-revert-version-1.15.0.js +16 -0
- package/migrations/202401041618111-holderapp-isDebugOn-false.js +17 -0
- package/migrations/20240131095122-test-personas-add-did.js +102 -0
- package/migrations/202402051547000-update-sdk.js +18 -0
- package/migrations/20240206101448-update-personas-vc-to-v2.js +137 -0
- package/migrations/202402061233000-set-xVnfProtocolVersion-2.js +13 -0
- package/migrations/202402081240000-set-xVnfProtocolVersion-1.js +13 -0
- package/migrations/202402131319-set-holderapp-min-versions-1.17.js +16 -0
- package/migrations/202402141152-set-holderapp-min-version-1.16.js +16 -0
- package/migrations/20240221123501-transform-account-keys-to-stringified-jwk.js +81 -0
- package/migrations/202402290955-update-holderapp-to-verifyMyCreds.js +36 -0
- package/migrations/20240311134223-update-keyid-persona.js +66 -0
- package/migrations/20240312141618-vl-7409-persona-update-maria-williams.js +82 -0
- package/migrations/202403181733000-remove-devices-from-all-accounts.js +27 -0
- package/migrations/20240401091041-set-holderapp-min-version-1.18.1.js +16 -0
- package/migrations/202404071847-app-config-update-yoti-url.js +19 -0
- package/migrations/20240724063405-vl-3827-new-yoti-session-url.js +19 -0
- package/migrations/20240731112302-vl-8160-add-persona-keys.js +101 -0
- package/migrations/20240911115206-vanessa-lin-id-credentials.js +57 -0
- package/migrations/202409201219-add-isWalletAvailable-field.js +13 -0
- package/migrations/202409221012-set-isWalletAvailable-true.js +13 -0
- package/migrations/20240922114643-holderapp-isWalletAvailable-refactor.js +36 -0
- package/migrations/20240923132213-update-android-ios-app-config.js +36 -0
- package/migrations/20240926061732-inc-cacheSequence-to-7.js +15 -0
- package/migrations/20240926073339-inc-cacheSequence-to-7-fix.js +18 -0
- package/migrations/202410081217-adam-smith-id-credntials.js +57 -0
- package/migrations/202410101243-adam_smith-id-credential.js +57 -0
- package/migrations/20241015124307-persona-key-id-type-fix.js +26 -0
- package/migrations/202501291027000-set-holderapp-did-web.js +37 -0
- package/migrations/environments/dev.env +34 -0
- package/migrations/environments/localdev.env +22 -0
- package/migrations/environments/prod.env +18 -0
- package/migrations/environments/qa.env +54 -0
- package/migrations/environments/staging.env +31 -0
- package/migrations/environments/test.env +18 -0
- package/package.json +84 -0
- package/src/assets/category-icons/assessment.png +0 -0
- package/src/assets/category-icons/badge.png +0 -0
- package/src/assets/category-icons/certification.png +0 -0
- package/src/assets/category-icons/education.png +0 -0
- package/src/assets/category-icons/employment.png +0 -0
- package/src/assets/category-icons/gig.png +0 -0
- package/src/assets/category-icons/identity.png +0 -0
- package/src/assets/category-icons/pharmacy.png +0 -0
- package/src/assets/category-icons/training.png +0 -0
- package/src/assets/credentialCategories.json +119 -0
- package/src/config/config.js +156 -0
- package/src/controllers/api/v0.6/accounts/autohooks.js +36 -0
- package/src/controllers/api/v0.6/accounts/controller.js +288 -0
- package/src/controllers/api/v0.6/accounts/schemas/careerwallet-accounts-didkeymetadatum-response.schema.js +41 -0
- package/src/controllers/api/v0.6/accounts/schemas/careerwallet-accounts-request.schema.js +49 -0
- package/src/controllers/api/v0.6/accounts/schemas/careerwallet-accounts-response.schema.js +74 -0
- package/src/controllers/api/v0.6/accounts/schemas/careerwallet-get-account-response.schema.js +72 -0
- package/src/controllers/api/v0.6/accounts/schemas/index.js +6 -0
- package/src/controllers/api/v0.6/careerwallet/appconfig/controller.js +25 -0
- package/src/controllers/api/v0.6/careerwallet/appconfig/repo.js +40 -0
- package/src/controllers/api/v0.6/careerwallet/autohooks.js +5 -0
- package/src/controllers/api/v0.6/careerwallet/consents/controller.js +66 -0
- package/src/controllers/api/v0.6/careerwallet/consents/latest/autohooks.js +7 -0
- package/src/controllers/api/v0.6/careerwallet/consents/latest/controller.js +76 -0
- package/src/controllers/api/v0.6/careerwallet/consents/repo.js +24 -0
- package/src/controllers/api/v0.6/careerwallet/consents/schemas/careerwallet-consent-response.schema.js +23 -0
- package/src/controllers/api/v0.6/careerwallet/consents/schemas/index.js +3 -0
- package/src/controllers/api/v0.6/create_did_key/autohooks.js +10 -0
- package/src/controllers/api/v0.6/create_did_key/controller.js +84 -0
- package/src/controllers/api/v0.6/create_did_key/schemas/index.js +4 -0
- package/src/controllers/api/v0.6/create_did_key/schemas/jwk-did-request.schema.js +20 -0
- package/src/controllers/api/v0.6/create_did_key/schemas/jwk-did-response.schema.js +41 -0
- package/src/controllers/api/v0.6/create_jwk/autohooks.js +10 -0
- package/src/controllers/api/v0.6/create_jwk/controller.js +46 -0
- package/src/controllers/api/v0.6/create_jwk/schemas/index.js +3 -0
- package/src/controllers/api/v0.6/create_jwk/schemas/jwk-response.schema.js +33 -0
- package/src/controllers/api/v0.6/credential-categories/controller.js +35 -0
- package/src/controllers/api/v0.6/devices/autohooks.js +11 -0
- package/src/controllers/api/v0.6/devices/controller.js +323 -0
- package/src/controllers/api/v0.6/devices/repo.js +27 -0
- package/src/controllers/api/v0.6/devices/schemas/device.schema.json +43 -0
- package/src/controllers/api/v0.6/devices/schemas/index.js +3 -0
- package/src/controllers/api/v0.6/feedback/controller.js +24 -0
- package/src/controllers/api/v0.6/feedback/schemas/index.js +3 -0
- package/src/controllers/api/v0.6/feedback/schemas/new-feedback.schema.js +47 -0
- package/src/controllers/api/v0.6/jwt/autohooks.js +10 -0
- package/src/controllers/api/v0.6/jwt/controller.js +44 -0
- package/src/controllers/api/v0.6/jwt/schemas/index.js +4 -0
- package/src/controllers/api/v0.6/jwt/schemas/jwt-request.schema.js +40 -0
- package/src/controllers/api/v0.6/jwt/schemas/jwt-response.schema.js +14 -0
- package/src/controllers/api/v0.6/oauth/controller.js +131 -0
- package/src/controllers/api/v0.6/push/controller.js +296 -0
- package/src/controllers/api/v0.6/push/firebase-initializer.js +21 -0
- package/src/controllers/api/v0.6/push/notification-types.js +37 -0
- package/src/controllers/api/v0.6/push/push-gateway-auth.js +123 -0
- package/src/controllers/api/v0.6/push/repo.js +24 -0
- package/src/controllers/api/v0.6/verification-offers/repo.js +25 -0
- package/src/controllers/api/v0.6/verify/autohooks.js +15 -0
- package/src/controllers/api/v0.6/verify/controller.js +348 -0
- package/src/controllers/api/v0.6/verify/repo.js +23 -0
- package/src/controllers/api/v0.6/verify/verification-credential-types.js +6 -0
- package/src/controllers/jwt/autohooks.js +10 -0
- package/src/controllers/jwt/controller.js +106 -0
- package/src/controllers/jwt/schemas/index.js +31 -0
- package/src/controllers/jwt/schemas/jwt-decode.response.200.schema.json +20 -0
- package/src/controllers/jwt/schemas/jwt-decode.schema.json +15 -0
- package/src/controllers/jwt/schemas/jwt-sign.response.200.schema.json +14 -0
- package/src/controllers/jwt/schemas/jwt-sign.schema.json +40 -0
- package/src/controllers/jwt/schemas/jwt-verify.response.200.schema.json +17 -0
- package/src/controllers/jwt/schemas/jwt-verify.schema.json +19 -0
- package/src/controllers/reference/autohooks.js +5 -0
- package/src/controllers/reference/countries/controller.js +81 -0
- package/src/controllers/reference/personas/controller.js +91 -0
- package/src/controllers/reference/personas/repo.js +29 -0
- package/src/controllers/reference/personas/schemas/index.js +3 -0
- package/src/controllers/reference/personas/schemas/persona.schema.json +108 -0
- package/src/controllers/root/controller.js +27 -0
- package/src/entities/accounts/constants.js +18 -0
- package/src/entities/accounts/domain/index.js +3 -0
- package/src/entities/accounts/domain/merge-scopes.js +9 -0
- package/src/entities/accounts/index.js +5 -0
- package/src/entities/accounts/repos/accounts.repo.js +64 -0
- package/src/entities/accounts/repos/id-token-claims-extension.js +31 -0
- package/src/entities/accounts/repos/index.js +3 -0
- package/src/entities/devices/constants.js +7 -0
- package/src/entities/devices/index.js +3 -0
- package/src/entities/feedback/domain/generate-feedback-email.js +23 -0
- package/src/entities/feedback/domain/index.js +3 -0
- package/src/entities/feedback/index.js +3 -0
- package/src/entities/index.js +9 -0
- package/src/entities/key-pairs/index.js +4 -0
- package/src/entities/key-pairs/orchestrators/generate-jwk.js +28 -0
- package/src/entities/key-pairs/orchestrators/get-key-pair.js +58 -0
- package/src/entities/key-pairs/orchestrators/index.js +4 -0
- package/src/entities/key-pairs/repos/index.js +3 -0
- package/src/entities/key-pairs/repos/key-pairs.repo.js +23 -0
- package/src/entities/oauth/constants.js +13 -0
- package/src/entities/oauth/domain/build-access-token.js +14 -0
- package/src/entities/oauth/domain/index.js +10 -0
- package/src/entities/oauth/domain/validate-audience.js +13 -0
- package/src/entities/oauth/domain/validate-client-id.js +13 -0
- package/src/entities/oauth/domain/validate-credential.js +16 -0
- package/src/entities/oauth/domain/validate-presentation.js +17 -0
- package/src/entities/oauth/domain/validate-refresh-token.js +17 -0
- package/src/entities/oauth/domain/validate-scope.js +30 -0
- package/src/entities/oauth/domain/verify-presentation.js +24 -0
- package/src/entities/oauth/index.js +4 -0
- package/src/entities/pushes/domains/errors.js +11 -0
- package/src/entities/pushes/domains/index.js +3 -0
- package/src/entities/pushes/index.js +3 -0
- package/src/entities/verification-code-attempts/index.js +3 -0
- package/src/entities/verification-code-attempts/orchestrators/index.js +3 -0
- package/src/entities/verification-code-attempts/orchestrators/validate-verification-code-attempts.js +79 -0
- package/src/entities/verification-code-attempts/repo.js +99 -0
- package/src/entities/verifications/constants.js +8 -0
- package/src/entities/verifications/index.js +3 -0
- package/src/helpers/caching-constants.js +6 -0
- package/src/helpers/index.js +3 -0
- package/src/index.js +15 -0
- package/src/init-server.js +88 -0
- package/src/plugins/index.js +4 -0
- package/src/plugins/vcl-verification-version-plugin.js +10 -0
- package/src/plugins/verify-access-token-plugin.js +116 -0
- package/src/standalone.js +8 -0
- package/test/accounts-controller.test.js +893 -0
- package/test/accounts-repo.test.js +92 -0
- package/test/careerwallet-config-controller.test.js +142 -0
- package/test/careerwallet-consents-controller.test.js +409 -0
- package/test/create_did_key-controller.test.js +397 -0
- package/test/create_jwk-controller.test.js +188 -0
- package/test/credential-categories-controller.test.js +29 -0
- package/test/credential-icons-controller.test.js +36 -0
- package/test/devices-controller.test.js +1025 -0
- package/test/factories/accounts-factory.js +15 -0
- package/test/factories/career-wallet-config-factory.js +60 -0
- package/test/factories/consents-career-wallet-factory.js +21 -0
- package/test/factories/devices-factory.js +16 -0
- package/test/factories/key-pairs-factory.js +18 -0
- package/test/factories/notifications-factory.js +16 -0
- package/test/factories/persona-factory.js +17 -0
- package/test/factories/refresh-tokens-factory.js +14 -0
- package/test/factories/verification-code-attempts-factory.js +17 -0
- package/test/factories/verification-factory.js +15 -0
- package/test/factories/verification-offer-factory.js +20 -0
- package/test/feedback-controller.test.js +225 -0
- package/test/helpers/.env.test +39 -0
- package/test/helpers/access-token.js +59 -0
- package/test/helpers/careerwallet-build-fastify.js +20 -0
- package/test/helpers/yoti.js +96 -0
- package/test/id-verification-controller.test.js +27 -0
- package/test/jwt-controller.test.js +1519 -0
- package/test/oauth-controller.test.js +639 -0
- package/test/push-controller.test.js +733 -0
- package/test/push-gateway-auth.test.js +208 -0
- package/test/reference-countries-controller.test.js +45 -0
- package/test/reference-personas-controller.test.js +179 -0
- package/test/root.test.js +21 -0
- package/test/swagger.test.js +21 -0
- package/test/verification-controller.test.js +1372 -0
|
@@ -0,0 +1,1025 @@
|
|
|
1
|
+
const { mongoDb } = require('@spencejs/spence-mongo-repos');
|
|
2
|
+
const { ObjectId } = require('mongodb');
|
|
3
|
+
const { omit } = require('lodash/fp');
|
|
4
|
+
const {
|
|
5
|
+
OBJECT_ID_FORMAT,
|
|
6
|
+
ISO_DATETIME_FORMAT,
|
|
7
|
+
} = require('@velocitycareerlabs/test-regexes');
|
|
8
|
+
const { generateKeyPair } = require('@velocitycareerlabs/crypto');
|
|
9
|
+
const { hexFromJwk } = require('@velocitycareerlabs/jwt');
|
|
10
|
+
const initDevicesFactory = require('./factories/devices-factory');
|
|
11
|
+
const initNotificationsFactory = require('./factories/notifications-factory');
|
|
12
|
+
const buildFastify = require('./helpers/careerwallet-build-fastify');
|
|
13
|
+
const devicesRepoPlugin = require('../src/controllers/api/v0.6/devices/repo');
|
|
14
|
+
const {
|
|
15
|
+
NotificationTypes,
|
|
16
|
+
} = require('../src/controllers/api/v0.6/push/notification-types');
|
|
17
|
+
const { accountScopes } = require('../src/entities');
|
|
18
|
+
const {
|
|
19
|
+
createAccessToken,
|
|
20
|
+
missingAccessTokenExpectation,
|
|
21
|
+
incorrectScopeExpectation,
|
|
22
|
+
incorrectAccessTokenExpectation,
|
|
23
|
+
} = require('./helpers/access-token');
|
|
24
|
+
|
|
25
|
+
const notificationExpectation = (notification) => ({
|
|
26
|
+
...omit(['createdAt', 'deviceId', 'linkedDevice'])(notification),
|
|
27
|
+
id: notification._id,
|
|
28
|
+
});
|
|
29
|
+
describe('devices endpoints', () => {
|
|
30
|
+
let fastify;
|
|
31
|
+
let persistDevices;
|
|
32
|
+
let device;
|
|
33
|
+
let persistNotifications;
|
|
34
|
+
let devicesRepo;
|
|
35
|
+
let publicKey;
|
|
36
|
+
let privateKey;
|
|
37
|
+
|
|
38
|
+
beforeAll(async () => {
|
|
39
|
+
({ publicKey, privateKey } = generateKeyPair({ format: 'jwk' }));
|
|
40
|
+
|
|
41
|
+
fastify = buildFastify({
|
|
42
|
+
holderAppServerAccessTokenPublicKey: publicKey,
|
|
43
|
+
holderAppServerAccessTokenSigningKey: hexFromJwk(privateKey),
|
|
44
|
+
oauthVerificationDisabledEndpoints: [
|
|
45
|
+
'GET:/api/v0.6/devices/:deviceId',
|
|
46
|
+
'GET:/api/v0.6/devices/:deviceId/pushes',
|
|
47
|
+
'DELETE:/api/v0.6/devices/:deviceId',
|
|
48
|
+
'PUT:/api/v0.6/devices/:deviceId',
|
|
49
|
+
],
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
await fastify.ready();
|
|
53
|
+
|
|
54
|
+
({ persistDevices } = initDevicesFactory(fastify));
|
|
55
|
+
({ persistNotifications } = initNotificationsFactory(fastify));
|
|
56
|
+
|
|
57
|
+
devicesRepo = devicesRepoPlugin(fastify)({
|
|
58
|
+
log: fastify.log,
|
|
59
|
+
config: fastify.config,
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
afterAll(async () => {
|
|
64
|
+
await mongoDb().collection('devices').deleteMany({});
|
|
65
|
+
await mongoDb().collection('notifications').deleteMany({});
|
|
66
|
+
await fastify.close();
|
|
67
|
+
});
|
|
68
|
+
describe('Unprotected endpoints or access token verification disabled', () => {
|
|
69
|
+
describe('register device', () => {
|
|
70
|
+
it('should respond 400 when deviceId does not exist', async () => {
|
|
71
|
+
const response = await fastify.injectJson({
|
|
72
|
+
method: 'POST',
|
|
73
|
+
url: '/api/v0.6/devices',
|
|
74
|
+
payload: {
|
|
75
|
+
deviceType: 'phone',
|
|
76
|
+
deviceOS: 'osx',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(response.statusCode).toEqual(400);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should respond 400 when deviceId is empty string', async () => {
|
|
84
|
+
const response = await fastify.injectJson({
|
|
85
|
+
method: 'POST',
|
|
86
|
+
url: '/api/v0.6/devices',
|
|
87
|
+
payload: {
|
|
88
|
+
deviceType: 'phone',
|
|
89
|
+
deviceOS: 'osx',
|
|
90
|
+
deviceId: '',
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
expect(response.statusCode).toEqual(400);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should respond 400 when deviceType does not exist', async () => {
|
|
98
|
+
const response = await fastify.injectJson({
|
|
99
|
+
method: 'POST',
|
|
100
|
+
url: '/api/v0.6/devices',
|
|
101
|
+
payload: { deviceId: '122334', deviceOS: 'osx' },
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
expect(response.statusCode).toEqual(400);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should respond 400 when deviceType does not match the enum', async () => {
|
|
108
|
+
const response = await fastify.injectJson({
|
|
109
|
+
method: 'POST',
|
|
110
|
+
url: '/api/v0.6/devices',
|
|
111
|
+
payload: {
|
|
112
|
+
deviceId: '122334',
|
|
113
|
+
deviceType: 'laptop',
|
|
114
|
+
deviceOS: 'osx',
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(response.statusCode).toEqual(400);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should respond 400 when deviceOS does not exist', async () => {
|
|
122
|
+
const response = await fastify.injectJson({
|
|
123
|
+
method: 'POST',
|
|
124
|
+
url: '/api/v0.6/devices',
|
|
125
|
+
payload: {
|
|
126
|
+
deviceId: '122334',
|
|
127
|
+
deviceType: 'phone',
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
expect(response.statusCode).toEqual(400);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should respond 400 when deviceOS does not match the enum', async () => {
|
|
135
|
+
const response = await fastify.injectJson({
|
|
136
|
+
method: 'POST',
|
|
137
|
+
url: '/api/v0.6/devices',
|
|
138
|
+
payload: {
|
|
139
|
+
deviceId: '122334',
|
|
140
|
+
deviceType: 'phone',
|
|
141
|
+
deviceOS: 'chromeos',
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
expect(response.statusCode).toEqual(400);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should register a device', async () => {
|
|
149
|
+
const response = await fastify.injectJson({
|
|
150
|
+
method: 'POST',
|
|
151
|
+
url: '/api/v0.6/devices',
|
|
152
|
+
payload: {
|
|
153
|
+
deviceId: '122334',
|
|
154
|
+
deviceType: 'phone',
|
|
155
|
+
deviceOS: 'ios',
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
expect(response.statusCode).toEqual(200);
|
|
160
|
+
expect(response.json).toEqual({
|
|
161
|
+
deviceId: '122334',
|
|
162
|
+
deviceType: 'phone',
|
|
163
|
+
deviceOS: 'ios',
|
|
164
|
+
pushToken: expect.any(String),
|
|
165
|
+
});
|
|
166
|
+
const dbResult = await mongoDb()
|
|
167
|
+
.collection('devices')
|
|
168
|
+
.findOne({ deviceId: '122334' });
|
|
169
|
+
expect(dbResult).toEqual({
|
|
170
|
+
_id: expect.any(ObjectId),
|
|
171
|
+
deviceId: '122334',
|
|
172
|
+
deviceType: 'phone',
|
|
173
|
+
deviceOS: 'ios',
|
|
174
|
+
pushToken: expect.any(String),
|
|
175
|
+
createdAt: expect.any(Date),
|
|
176
|
+
updatedAt: expect.any(Date),
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should respond 200 when pushActivated flag does not exist', async () => {
|
|
181
|
+
const response = await fastify.injectJson({
|
|
182
|
+
method: 'POST',
|
|
183
|
+
url: '/api/v0.6/devices',
|
|
184
|
+
payload: {
|
|
185
|
+
deviceId: '122334',
|
|
186
|
+
deviceType: 'phone',
|
|
187
|
+
deviceOS: 'ios',
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
expect(response.statusCode).toEqual(200);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should respond 400 when pushActivated is non boolean', async () => {
|
|
195
|
+
const response = await fastify.injectJson({
|
|
196
|
+
method: 'POST',
|
|
197
|
+
url: '/api/v0.6/devices',
|
|
198
|
+
payload: {
|
|
199
|
+
deviceId: '122334',
|
|
200
|
+
deviceType: 'phone',
|
|
201
|
+
deviceOS: 'ios',
|
|
202
|
+
pushActivated: 'nonBoolean',
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
expect(response.statusCode).toEqual(400);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should register device with the same deviceId without creating a new device', async () => {
|
|
211
|
+
await mongoDb().collection('devices').deleteMany({});
|
|
212
|
+
const reqJSON = {
|
|
213
|
+
method: 'POST',
|
|
214
|
+
url: '/api/v0.6/devices',
|
|
215
|
+
payload: {
|
|
216
|
+
deviceId: '122334',
|
|
217
|
+
deviceType: 'phone',
|
|
218
|
+
deviceOS: 'ios',
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
const response = await fastify.injectJson(reqJSON);
|
|
222
|
+
const response2 = await fastify.injectJson(reqJSON);
|
|
223
|
+
await fastify.injectJson(reqJSON);
|
|
224
|
+
|
|
225
|
+
expect(response.statusCode).toEqual(200);
|
|
226
|
+
expect(response.json).toEqual({
|
|
227
|
+
deviceId: '122334',
|
|
228
|
+
deviceType: 'phone',
|
|
229
|
+
deviceOS: 'ios',
|
|
230
|
+
pushToken: expect.any(String),
|
|
231
|
+
});
|
|
232
|
+
expect(response.json).toEqual(response2.json);
|
|
233
|
+
const dbResult = await mongoDb()
|
|
234
|
+
.collection('devices')
|
|
235
|
+
.find({ deviceId: '122334' })
|
|
236
|
+
.toArray();
|
|
237
|
+
expect(dbResult.length).toEqual(1);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
describe('get a device by device id', () => {
|
|
241
|
+
beforeAll(async () => {
|
|
242
|
+
device = await persistDevices();
|
|
243
|
+
await persistDevices({ deviceId: '1223' });
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('should return a device by deviceId', async () => {
|
|
247
|
+
const response = await fastify.injectJson({
|
|
248
|
+
method: 'GET',
|
|
249
|
+
url: `/api/v0.6/devices/${device.deviceId}`,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
expect(response.statusCode).toEqual(200);
|
|
253
|
+
expect(response.json).toEqual({
|
|
254
|
+
...omit('_id', device),
|
|
255
|
+
id: expect.stringMatching(OBJECT_ID_FORMAT),
|
|
256
|
+
updatedAt: expect.stringMatching(ISO_DATETIME_FORMAT),
|
|
257
|
+
createdAt: expect.stringMatching(ISO_DATETIME_FORMAT),
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should return a list of devices', async () => {
|
|
262
|
+
const response = await fastify.injectJson({
|
|
263
|
+
method: 'GET',
|
|
264
|
+
url: '/api/v0.6/devices',
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
expect(response.statusCode).toEqual(200);
|
|
268
|
+
expect(response.json).toEqual(
|
|
269
|
+
expect.arrayContaining([
|
|
270
|
+
{
|
|
271
|
+
...omit('_id', device),
|
|
272
|
+
id: expect.stringMatching(OBJECT_ID_FORMAT),
|
|
273
|
+
updatedAt: expect.stringMatching(ISO_DATETIME_FORMAT),
|
|
274
|
+
createdAt: expect.stringMatching(ISO_DATETIME_FORMAT),
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
...omit('_id', device),
|
|
278
|
+
id: expect.stringMatching(OBJECT_ID_FORMAT),
|
|
279
|
+
updatedAt: expect.stringMatching(ISO_DATETIME_FORMAT),
|
|
280
|
+
createdAt: expect.stringMatching(ISO_DATETIME_FORMAT),
|
|
281
|
+
},
|
|
282
|
+
])
|
|
283
|
+
);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
describe('remove a device by device id', () => {
|
|
288
|
+
beforeAll(async () => {
|
|
289
|
+
device = await persistDevices();
|
|
290
|
+
notification = await persistNotifications({
|
|
291
|
+
deviceId: device.deviceId,
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('should delete a device', async () => {
|
|
296
|
+
const response = await fastify.injectJson({
|
|
297
|
+
method: 'DELETE',
|
|
298
|
+
url: `/api/v0.6/devices/${device.deviceId}`,
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
expect(response.statusCode).toEqual(204);
|
|
302
|
+
expect(response.json).toEqual({});
|
|
303
|
+
const dbResult = await mongoDb()
|
|
304
|
+
.collection('devices')
|
|
305
|
+
.findOne({ deviceId: device.deviceId });
|
|
306
|
+
expect(dbResult).toEqual(null);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('should delete a device and the linked notifications', async () => {
|
|
310
|
+
await mongoDb().collection('devices').deleteMany({});
|
|
311
|
+
await mongoDb().collection('notifications').deleteMany({});
|
|
312
|
+
device = await persistDevices();
|
|
313
|
+
const { deviceId, _id } = device;
|
|
314
|
+
await persistNotifications({
|
|
315
|
+
deviceId,
|
|
316
|
+
linkedDevice: new ObjectId(_id),
|
|
317
|
+
});
|
|
318
|
+
await persistNotifications({
|
|
319
|
+
deviceId,
|
|
320
|
+
linkedDevice: new ObjectId(_id),
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const response = await fastify.injectJson({
|
|
324
|
+
method: 'DELETE',
|
|
325
|
+
url: `/api/v0.6/devices/${deviceId}`,
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
expect(response.statusCode).toEqual(204);
|
|
329
|
+
expect(response.json).toEqual({});
|
|
330
|
+
let dbResult = await mongoDb()
|
|
331
|
+
.collection('devices')
|
|
332
|
+
.findOne({ deviceId });
|
|
333
|
+
expect(dbResult).toEqual(null);
|
|
334
|
+
dbResult = await mongoDb()
|
|
335
|
+
.collection('notifications')
|
|
336
|
+
.findOne({ deviceId });
|
|
337
|
+
expect(dbResult).toEqual(null);
|
|
338
|
+
});
|
|
339
|
+
it('should delete a device without linked notifications', async () => {
|
|
340
|
+
device = await persistDevices();
|
|
341
|
+
const { deviceId } = device;
|
|
342
|
+
|
|
343
|
+
const response = await fastify.injectJson({
|
|
344
|
+
method: 'DELETE',
|
|
345
|
+
url: `/api/v0.6/devices/${deviceId}`,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
expect(response.statusCode).toEqual(204);
|
|
349
|
+
expect(response.json).toEqual({});
|
|
350
|
+
let dbResult = await mongoDb()
|
|
351
|
+
.collection('devices')
|
|
352
|
+
.findOne({ deviceId });
|
|
353
|
+
expect(dbResult).toEqual(null);
|
|
354
|
+
dbResult = await mongoDb()
|
|
355
|
+
.collection('notifications')
|
|
356
|
+
.findOne({ deviceId });
|
|
357
|
+
expect(dbResult).toEqual(null);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it('should throw an error when device not found', async () => {
|
|
361
|
+
const response = await fastify.injectJson({
|
|
362
|
+
method: 'DELETE',
|
|
363
|
+
url: '/api/v0.6/devices/1234',
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
expect(response.statusCode).toEqual(404);
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
let notification;
|
|
371
|
+
let notifications;
|
|
372
|
+
describe('get notifications for a device', () => {
|
|
373
|
+
const deviceId =
|
|
374
|
+
// eslint-disable-next-line max-len
|
|
375
|
+
'fs9hEl5QeENQmf_fR4xl4k:APA91bGJgbkY03CIcOTm2h1gEXv4jHgY1UuhIavAR9_IiN6p-VBUqfpkNF3UZM_V9pqq1iFckvteao4wjT7Q8gxg7DuC9yH9e0MuxX2U6byM-SAL1J0P-DaWBsPiRyLLkjIcB60nq21J';
|
|
376
|
+
beforeAll(async () => {
|
|
377
|
+
notification = await persistNotifications();
|
|
378
|
+
notifications = [
|
|
379
|
+
await persistNotifications({ deviceId }),
|
|
380
|
+
await persistNotifications({ deviceId }),
|
|
381
|
+
];
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it('should return one notification for the deviceId', async () => {
|
|
385
|
+
const response = await fastify.injectJson({
|
|
386
|
+
method: 'GET',
|
|
387
|
+
url: `/api/v0.6/devices/${notification.deviceId}/pushes`,
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
expect(response.statusCode).toEqual(200);
|
|
391
|
+
expect(response.json).toEqual({
|
|
392
|
+
nextPushSeqId: notification._id,
|
|
393
|
+
pushes: [
|
|
394
|
+
{
|
|
395
|
+
...notificationExpectation(notification),
|
|
396
|
+
},
|
|
397
|
+
],
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it('should return notifications for the deviceId', async () => {
|
|
402
|
+
const response = await fastify.injectJson({
|
|
403
|
+
method: 'GET',
|
|
404
|
+
url: `/api/v0.6/devices/${deviceId}/pushes`,
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
expect(response.statusCode).toEqual(200);
|
|
408
|
+
expect(response.json).toEqual({
|
|
409
|
+
nextPushSeqId: notifications[1]._id,
|
|
410
|
+
pushes: notifications.map(notificationExpectation),
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
it('should return a filtered array of notifications', async () => {
|
|
415
|
+
const pushSeqId = notifications[0]._id;
|
|
416
|
+
const response = await fastify.injectJson({
|
|
417
|
+
method: 'GET',
|
|
418
|
+
url: `/api/v0.6/devices/${deviceId}/pushes?pushSeqId=${pushSeqId}`,
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
expect(response.statusCode).toEqual(200);
|
|
422
|
+
expect(response.json).toEqual({
|
|
423
|
+
nextPushSeqId: notifications[1]._id,
|
|
424
|
+
pushes: [
|
|
425
|
+
{
|
|
426
|
+
...notificationExpectation(notifications[1]),
|
|
427
|
+
},
|
|
428
|
+
],
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it('should return an empty array of notifications', async () => {
|
|
433
|
+
const withoutNotificationsId = 'CR18oDogm8BiCtdSqgsnP';
|
|
434
|
+
const response = await fastify.injectJson({
|
|
435
|
+
method: 'GET',
|
|
436
|
+
url: `/api/v0.6/devices/${withoutNotificationsId}/pushes`,
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
expect(response.statusCode).toEqual(200);
|
|
440
|
+
expect(response.json).toEqual({
|
|
441
|
+
pushes: [],
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
describe('update device id on FCM token refresh', () => {
|
|
447
|
+
it('should return updated device with new push token id', async () => {
|
|
448
|
+
const { deviceId } = await persistDevices();
|
|
449
|
+
const newDeviceId = `${deviceId}-new`;
|
|
450
|
+
|
|
451
|
+
const response = await fastify.injectJson({
|
|
452
|
+
method: 'PUT',
|
|
453
|
+
url: `/api/v0.6/devices/${deviceId}`,
|
|
454
|
+
payload: {
|
|
455
|
+
deviceType: 'phone',
|
|
456
|
+
deviceOS: 'ios',
|
|
457
|
+
deviceId: newDeviceId,
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
expect(response.statusCode).toEqual(200);
|
|
462
|
+
|
|
463
|
+
expect(response.json).toEqual({
|
|
464
|
+
deviceType: 'phone',
|
|
465
|
+
deviceOS: 'ios',
|
|
466
|
+
deviceId: newDeviceId,
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
expect(
|
|
470
|
+
await devicesRepo.findOne({ deviceId: newDeviceId })
|
|
471
|
+
).toBeTruthy();
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
it('should return 404 in case device not found', async () => {
|
|
475
|
+
const { deviceId } = await persistDevices();
|
|
476
|
+
const notExistingDeviceId = 'not-existing-device-id';
|
|
477
|
+
|
|
478
|
+
const response = await fastify.injectJson({
|
|
479
|
+
method: 'PUT',
|
|
480
|
+
url: `/api/v0.6/devices/${notExistingDeviceId}`,
|
|
481
|
+
payload: {
|
|
482
|
+
deviceType: 'phone',
|
|
483
|
+
deviceOS: 'ios',
|
|
484
|
+
deviceId,
|
|
485
|
+
},
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
expect(response.statusCode).toEqual(404);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
it('related push notifications should have updated device id', async () => {
|
|
492
|
+
const { deviceId, _id } = await persistDevices();
|
|
493
|
+
const newDeviceId = `${deviceId}-new`;
|
|
494
|
+
|
|
495
|
+
await persistNotifications({
|
|
496
|
+
deviceId,
|
|
497
|
+
linkedDevice: new ObjectId(_id),
|
|
498
|
+
});
|
|
499
|
+
await persistNotifications({
|
|
500
|
+
deviceId,
|
|
501
|
+
linkedDevice: new ObjectId(_id),
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
await fastify.injectJson({
|
|
505
|
+
method: 'PUT',
|
|
506
|
+
url: `/api/v0.6/devices/${deviceId}`,
|
|
507
|
+
payload: {
|
|
508
|
+
deviceType: 'phone',
|
|
509
|
+
deviceOS: 'ios',
|
|
510
|
+
deviceId: newDeviceId,
|
|
511
|
+
},
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
const dbResult = await mongoDb()
|
|
515
|
+
.collection('notifications')
|
|
516
|
+
.find({ deviceId: newDeviceId })
|
|
517
|
+
.toArray();
|
|
518
|
+
|
|
519
|
+
expect(dbResult).toHaveLength(2);
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
it('in case new device id is the same notifications should not be updated', async () => {
|
|
523
|
+
const { deviceId, _id } = await persistDevices();
|
|
524
|
+
|
|
525
|
+
await persistNotifications({
|
|
526
|
+
deviceId,
|
|
527
|
+
linkedDevice: new ObjectId(_id),
|
|
528
|
+
});
|
|
529
|
+
await persistNotifications({
|
|
530
|
+
deviceId,
|
|
531
|
+
linkedDevice: new ObjectId(_id),
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
await fastify.injectJson({
|
|
535
|
+
method: 'PUT',
|
|
536
|
+
url: `/api/v0.6/devices/${deviceId}`,
|
|
537
|
+
payload: {
|
|
538
|
+
deviceType: 'phone',
|
|
539
|
+
deviceOS: 'ios',
|
|
540
|
+
deviceId,
|
|
541
|
+
},
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
const notificationsThatHaventChanged = await mongoDb()
|
|
545
|
+
.collection('notifications')
|
|
546
|
+
.find({
|
|
547
|
+
deviceId,
|
|
548
|
+
$expr: { $eq: ['$createdAt', '$updatedAt'] },
|
|
549
|
+
})
|
|
550
|
+
.toArray();
|
|
551
|
+
|
|
552
|
+
expect(notificationsThatHaventChanged).toHaveLength(2);
|
|
553
|
+
});
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
describe('Notifications should have proper fields in GET /pushes response', () => {
|
|
557
|
+
let deviceId;
|
|
558
|
+
let response;
|
|
559
|
+
let presentationVerifiedNotification;
|
|
560
|
+
let newOffersReadyNotification;
|
|
561
|
+
let noOffersFoundNotification;
|
|
562
|
+
let credentialRevokedNotification;
|
|
563
|
+
let credentialReplacedNotification;
|
|
564
|
+
|
|
565
|
+
beforeAll(async () => {
|
|
566
|
+
({ deviceId } = await persistDevices());
|
|
567
|
+
|
|
568
|
+
presentationVerifiedNotification = await persistNotifications({
|
|
569
|
+
deviceId,
|
|
570
|
+
data: {
|
|
571
|
+
notificationType: NotificationTypes.PresentationVerified,
|
|
572
|
+
notificationId: 'testNotificationId1',
|
|
573
|
+
count: '0',
|
|
574
|
+
issuer: 'testDid1',
|
|
575
|
+
exchangeId: 'testExchangeId',
|
|
576
|
+
serviceEndpoint: 'https://testserviceendpoint.com',
|
|
577
|
+
},
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
newOffersReadyNotification = await persistNotifications({
|
|
581
|
+
deviceId,
|
|
582
|
+
data: {
|
|
583
|
+
notificationType: NotificationTypes.NewOffersReady,
|
|
584
|
+
notificationId: 'testNotificationId2',
|
|
585
|
+
count: '0',
|
|
586
|
+
issuer: 'testDid2',
|
|
587
|
+
exchangeId: 'testExchangeId',
|
|
588
|
+
serviceEndpoint: 'https://testserviceendpoint.com',
|
|
589
|
+
credentialTypes: '["EmploymentPastV1.1"]',
|
|
590
|
+
},
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
noOffersFoundNotification = await persistNotifications({
|
|
594
|
+
deviceId,
|
|
595
|
+
data: {
|
|
596
|
+
notificationType: NotificationTypes.NoOffersFound,
|
|
597
|
+
notificationId: 'testNotificationId3',
|
|
598
|
+
count: '0',
|
|
599
|
+
issuer: 'testDid3',
|
|
600
|
+
exchangeId: 'testExchangeId',
|
|
601
|
+
serviceEndpoint: 'https://testserviceendpoint.com',
|
|
602
|
+
credentialTypes: '[]',
|
|
603
|
+
},
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
credentialRevokedNotification = await persistNotifications({
|
|
607
|
+
deviceId,
|
|
608
|
+
data: {
|
|
609
|
+
notificationType: NotificationTypes.CredentialRevoked,
|
|
610
|
+
notificationId: 'testNotificationId4',
|
|
611
|
+
count: '0',
|
|
612
|
+
issuer: 'testDid4',
|
|
613
|
+
exchangeId: 'testExchangeId',
|
|
614
|
+
serviceEndpoint: 'https://testserviceendpoint.com',
|
|
615
|
+
credentialTypes: '["EmploymentPastV1.1"]',
|
|
616
|
+
credentialId: 'testCredentialId',
|
|
617
|
+
},
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
credentialReplacedNotification = await persistNotifications({
|
|
621
|
+
deviceId,
|
|
622
|
+
data: {
|
|
623
|
+
notificationType: NotificationTypes.CredentialReplaced,
|
|
624
|
+
notificationId: 'testNotificationId5',
|
|
625
|
+
count: '0',
|
|
626
|
+
issuer: 'testDid5',
|
|
627
|
+
exchangeId: 'testExchangeId',
|
|
628
|
+
serviceEndpoint: 'https://testserviceendpoint.com',
|
|
629
|
+
credentialTypes: '["EmploymentPastV1.1"]',
|
|
630
|
+
replacementCredentialType: 'EmploymentCurrentV1.1',
|
|
631
|
+
},
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
response = await fastify.injectJson({
|
|
635
|
+
method: 'GET',
|
|
636
|
+
url: `/api/v0.6/devices/${deviceId}/pushes`,
|
|
637
|
+
});
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
it('PresentationVerified notification should have proper fields in GET /pushes response', async () => {
|
|
641
|
+
expect(response.json).toEqual(
|
|
642
|
+
expect.objectContaining({
|
|
643
|
+
pushes: expect.arrayContaining([
|
|
644
|
+
{
|
|
645
|
+
...notificationExpectation(presentationVerifiedNotification),
|
|
646
|
+
data: {
|
|
647
|
+
notificationType: NotificationTypes.PresentationVerified,
|
|
648
|
+
notificationId: 'testNotificationId1',
|
|
649
|
+
count: '0',
|
|
650
|
+
issuer: 'testDid1',
|
|
651
|
+
exchangeId: 'testExchangeId',
|
|
652
|
+
},
|
|
653
|
+
},
|
|
654
|
+
]),
|
|
655
|
+
})
|
|
656
|
+
);
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
it('NewOffersReady notification should have proper fields in GET /pushes response', async () => {
|
|
660
|
+
expect(response.json).toEqual(
|
|
661
|
+
expect.objectContaining({
|
|
662
|
+
pushes: expect.arrayContaining([
|
|
663
|
+
{
|
|
664
|
+
...notificationExpectation(newOffersReadyNotification),
|
|
665
|
+
data: {
|
|
666
|
+
notificationType: NotificationTypes.NewOffersReady,
|
|
667
|
+
notificationId: 'testNotificationId2',
|
|
668
|
+
count: '0',
|
|
669
|
+
issuer: 'testDid2',
|
|
670
|
+
exchangeId: 'testExchangeId',
|
|
671
|
+
credentialTypes: '["EmploymentPastV1.1"]',
|
|
672
|
+
},
|
|
673
|
+
},
|
|
674
|
+
]),
|
|
675
|
+
})
|
|
676
|
+
);
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
it('NoOffersFound notification should have proper fields in GET /pushes response', async () => {
|
|
680
|
+
expect(response.json).toEqual(
|
|
681
|
+
expect.objectContaining({
|
|
682
|
+
pushes: expect.arrayContaining([
|
|
683
|
+
{
|
|
684
|
+
...notificationExpectation(noOffersFoundNotification),
|
|
685
|
+
data: {
|
|
686
|
+
notificationType: NotificationTypes.NoOffersFound,
|
|
687
|
+
notificationId: 'testNotificationId3',
|
|
688
|
+
count: '0',
|
|
689
|
+
issuer: 'testDid3',
|
|
690
|
+
exchangeId: 'testExchangeId',
|
|
691
|
+
credentialTypes: '[]',
|
|
692
|
+
},
|
|
693
|
+
},
|
|
694
|
+
]),
|
|
695
|
+
})
|
|
696
|
+
);
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
it('CredentialRevoked notification should have proper fields in GET /pushes response', async () => {
|
|
700
|
+
expect(response.json).toEqual(
|
|
701
|
+
expect.objectContaining({
|
|
702
|
+
pushes: expect.arrayContaining([
|
|
703
|
+
{
|
|
704
|
+
...notificationExpectation(credentialRevokedNotification),
|
|
705
|
+
data: {
|
|
706
|
+
notificationType: NotificationTypes.CredentialRevoked,
|
|
707
|
+
notificationId: 'testNotificationId4',
|
|
708
|
+
count: '0',
|
|
709
|
+
issuer: 'testDid4',
|
|
710
|
+
exchangeId: 'testExchangeId',
|
|
711
|
+
credentialTypes: '["EmploymentPastV1.1"]',
|
|
712
|
+
credentialId: 'testCredentialId',
|
|
713
|
+
},
|
|
714
|
+
},
|
|
715
|
+
]),
|
|
716
|
+
})
|
|
717
|
+
);
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
it('CredentialReplaced notification should have proper fields in GET /pushes response', async () => {
|
|
721
|
+
expect(response.json).toEqual(
|
|
722
|
+
expect.objectContaining({
|
|
723
|
+
pushes: expect.arrayContaining([
|
|
724
|
+
{
|
|
725
|
+
...notificationExpectation(credentialReplacedNotification),
|
|
726
|
+
data: {
|
|
727
|
+
notificationType: NotificationTypes.CredentialReplaced,
|
|
728
|
+
notificationId: 'testNotificationId5',
|
|
729
|
+
count: '0',
|
|
730
|
+
issuer: 'testDid5',
|
|
731
|
+
exchangeId: 'testExchangeId',
|
|
732
|
+
credentialTypes: '["EmploymentPastV1.1"]',
|
|
733
|
+
replacementCredentialType: 'EmploymentCurrentV1.1',
|
|
734
|
+
},
|
|
735
|
+
},
|
|
736
|
+
]),
|
|
737
|
+
})
|
|
738
|
+
);
|
|
739
|
+
});
|
|
740
|
+
});
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
describe('Access token verification enabled', () => {
|
|
744
|
+
const deviceId = 'test-device-id';
|
|
745
|
+
|
|
746
|
+
beforeAll(async () => {
|
|
747
|
+
fastify.overrides.reqConfig = (config) => ({
|
|
748
|
+
...config,
|
|
749
|
+
oauthVerificationDisabledEndpoints: [], // enabled for all endpoints
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
device = await persistDevices();
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
describe('GET /api/v0.6/devices/:deviceId/pushes - get pushes endpoint', () => {
|
|
756
|
+
it('should return notifications for the deviceId if correct access token and inbox scope are provided', async () => {
|
|
757
|
+
const accessToken = await createAccessToken(
|
|
758
|
+
accountScopes.inbox,
|
|
759
|
+
privateKey
|
|
760
|
+
);
|
|
761
|
+
|
|
762
|
+
const notifications = [
|
|
763
|
+
await persistNotifications({ deviceId }),
|
|
764
|
+
await persistNotifications({ deviceId }),
|
|
765
|
+
];
|
|
766
|
+
|
|
767
|
+
const response = await fastify.injectJson({
|
|
768
|
+
method: 'GET',
|
|
769
|
+
url: `/api/v0.6/devices/${deviceId}/pushes`,
|
|
770
|
+
headers: {
|
|
771
|
+
authorization: `Bearer ${accessToken}`,
|
|
772
|
+
},
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
expect(response.statusCode).toEqual(200);
|
|
776
|
+
expect(response.json).toEqual({
|
|
777
|
+
nextPushSeqId: notifications[1]._id,
|
|
778
|
+
pushes: notifications.map(notificationExpectation),
|
|
779
|
+
});
|
|
780
|
+
});
|
|
781
|
+
|
|
782
|
+
it('should return 401 when no access token is provided', async () => {
|
|
783
|
+
const response = await fastify.injectJson({
|
|
784
|
+
method: 'GET',
|
|
785
|
+
url: `/api/v0.6/devices/${deviceId}/pushes`,
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
missingAccessTokenExpectation(response);
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
it('Should return 403 when incorrect scope is provided', async () => {
|
|
792
|
+
const accessToken = await createAccessToken('wrong-scope', privateKey);
|
|
793
|
+
|
|
794
|
+
const response = await fastify.injectJson({
|
|
795
|
+
method: 'GET',
|
|
796
|
+
url: `/api/v0.6/devices/${deviceId}/pushes`,
|
|
797
|
+
headers: {
|
|
798
|
+
authorization: `Bearer ${accessToken}`,
|
|
799
|
+
},
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
incorrectScopeExpectation(response);
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
it('should return 401 when incorrect access token is provided', async () => {
|
|
806
|
+
const response = await fastify.injectJson({
|
|
807
|
+
method: 'GET',
|
|
808
|
+
url: `/api/v0.6/devices/${deviceId}/pushes`,
|
|
809
|
+
headers: {
|
|
810
|
+
authorization: 'Bearer incorrect_token',
|
|
811
|
+
},
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
incorrectAccessTokenExpectation(response);
|
|
815
|
+
});
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
describe('GET /api/v0.6/devices/:deviceId - get device endpoint', () => {
|
|
819
|
+
it('should return a device by deviceId if correct access token and account scope are provided', async () => {
|
|
820
|
+
const accessToken = await createAccessToken(
|
|
821
|
+
accountScopes.account,
|
|
822
|
+
privateKey
|
|
823
|
+
);
|
|
824
|
+
|
|
825
|
+
const response = await fastify.injectJson({
|
|
826
|
+
method: 'GET',
|
|
827
|
+
url: `/api/v0.6/devices/${device.deviceId}`,
|
|
828
|
+
headers: {
|
|
829
|
+
authorization: `Bearer ${accessToken}`,
|
|
830
|
+
},
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
expect(response.statusCode).toEqual(200);
|
|
834
|
+
expect(response.json).toEqual({
|
|
835
|
+
...omit('_id', device),
|
|
836
|
+
id: expect.stringMatching(OBJECT_ID_FORMAT),
|
|
837
|
+
updatedAt: expect.stringMatching(ISO_DATETIME_FORMAT),
|
|
838
|
+
createdAt: expect.stringMatching(ISO_DATETIME_FORMAT),
|
|
839
|
+
});
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
it('should return 401 when no access token is provided', async () => {
|
|
843
|
+
const response = await fastify.injectJson({
|
|
844
|
+
method: 'GET',
|
|
845
|
+
url: `/api/v0.6/devices/${device.deviceId}`,
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
missingAccessTokenExpectation(response);
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
it('Should return 403 when incorrect scope is provided', async () => {
|
|
852
|
+
const accessToken = await createAccessToken('wrong-scope', privateKey);
|
|
853
|
+
|
|
854
|
+
const response = await fastify.injectJson({
|
|
855
|
+
method: 'GET',
|
|
856
|
+
url: `/api/v0.6/devices/${device.deviceId}`,
|
|
857
|
+
headers: {
|
|
858
|
+
authorization: `Bearer ${accessToken}`,
|
|
859
|
+
},
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
incorrectScopeExpectation(response);
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
it('should return 401 when incorrect access token is provided', async () => {
|
|
866
|
+
const response = await fastify.injectJson({
|
|
867
|
+
method: 'GET',
|
|
868
|
+
url: `/api/v0.6/devices/${device.deviceId}`,
|
|
869
|
+
headers: {
|
|
870
|
+
authorization: 'Bearer incorrect_token',
|
|
871
|
+
},
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
incorrectAccessTokenExpectation(response);
|
|
875
|
+
});
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
describe('DELETE /api/v0.6/devices/:deviceId - delete devices endpoint', () => {
|
|
879
|
+
it('should delete a device if correct access token and account scope are provided', async () => {
|
|
880
|
+
const accessToken = await createAccessToken(
|
|
881
|
+
accountScopes.account,
|
|
882
|
+
privateKey
|
|
883
|
+
);
|
|
884
|
+
|
|
885
|
+
const response = await fastify.injectJson({
|
|
886
|
+
method: 'DELETE',
|
|
887
|
+
url: `/api/v0.6/devices/${device.deviceId}`,
|
|
888
|
+
headers: {
|
|
889
|
+
authorization: `Bearer ${accessToken}`,
|
|
890
|
+
},
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
expect(response.statusCode).toEqual(204);
|
|
894
|
+
expect(response.json).toEqual({});
|
|
895
|
+
const dbResult = await mongoDb()
|
|
896
|
+
.collection('devices')
|
|
897
|
+
.findOne({ deviceId: device.deviceId });
|
|
898
|
+
expect(dbResult).toEqual(null);
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
it('should return 401 when no access token is provided', async () => {
|
|
902
|
+
const response = await fastify.injectJson({
|
|
903
|
+
method: 'DELETE',
|
|
904
|
+
url: `/api/v0.6/devices/${device.deviceId}`,
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
missingAccessTokenExpectation(response);
|
|
908
|
+
});
|
|
909
|
+
|
|
910
|
+
it('Should return 403 when incorrect scope is provided', async () => {
|
|
911
|
+
const accessToken = await createAccessToken('wrong-scope', privateKey);
|
|
912
|
+
|
|
913
|
+
const response = await fastify.injectJson({
|
|
914
|
+
method: 'DELETE',
|
|
915
|
+
url: `/api/v0.6/devices/${device.deviceId}`,
|
|
916
|
+
headers: {
|
|
917
|
+
authorization: `Bearer ${accessToken}`,
|
|
918
|
+
},
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
incorrectScopeExpectation(response);
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
it('should return 401 when incorrect access token is provided', async () => {
|
|
925
|
+
const response = await fastify.injectJson({
|
|
926
|
+
method: 'DELETE',
|
|
927
|
+
url: `/api/v0.6/devices/${device.deviceId}`,
|
|
928
|
+
headers: {
|
|
929
|
+
authorization: 'Bearer incorrect_token',
|
|
930
|
+
},
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
incorrectAccessTokenExpectation(response);
|
|
934
|
+
});
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
describe('PUT /api/v0.6/devices - update device endpoint', () => {
|
|
938
|
+
it('should return updated device with new push token id if correct access token and account scope are provided', async () => {
|
|
939
|
+
const oldDeviceId = 'old-device-id';
|
|
940
|
+
const oldDevice = await persistDevices({ deviceId: oldDeviceId });
|
|
941
|
+
const newDeviceId = `${oldDevice.deviceId}-new`;
|
|
942
|
+
|
|
943
|
+
const accessToken = await createAccessToken(
|
|
944
|
+
accountScopes.account,
|
|
945
|
+
privateKey
|
|
946
|
+
);
|
|
947
|
+
|
|
948
|
+
const response = await fastify.injectJson({
|
|
949
|
+
method: 'PUT',
|
|
950
|
+
url: `/api/v0.6/devices/${oldDevice.deviceId}`,
|
|
951
|
+
payload: {
|
|
952
|
+
deviceType: 'phone',
|
|
953
|
+
deviceOS: 'ios',
|
|
954
|
+
deviceId: newDeviceId,
|
|
955
|
+
},
|
|
956
|
+
headers: {
|
|
957
|
+
authorization: `Bearer ${accessToken}`,
|
|
958
|
+
},
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
expect(response.statusCode).toEqual(200);
|
|
962
|
+
|
|
963
|
+
expect(response.json).toEqual({
|
|
964
|
+
deviceType: 'phone',
|
|
965
|
+
deviceOS: 'ios',
|
|
966
|
+
deviceId: newDeviceId,
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
expect(
|
|
970
|
+
await devicesRepo.findOne({ deviceId: newDeviceId })
|
|
971
|
+
).toBeTruthy();
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
it('should return 401 when no access token is provided', async () => {
|
|
975
|
+
const response = await fastify.injectJson({
|
|
976
|
+
method: 'PUT',
|
|
977
|
+
url: `/api/v0.6/devices/${device.deviceId}`,
|
|
978
|
+
payload: {
|
|
979
|
+
deviceType: 'phone',
|
|
980
|
+
deviceOS: 'ios',
|
|
981
|
+
deviceId,
|
|
982
|
+
},
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
missingAccessTokenExpectation(response);
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
it('Should return 403 when incorrect scope is provided', async () => {
|
|
989
|
+
const accessToken = await createAccessToken('wrong-scope', privateKey);
|
|
990
|
+
|
|
991
|
+
const response = await fastify.injectJson({
|
|
992
|
+
method: 'PUT',
|
|
993
|
+
url: `/api/v0.6/devices/${device.deviceId}`,
|
|
994
|
+
payload: {
|
|
995
|
+
deviceType: 'phone',
|
|
996
|
+
deviceOS: 'ios',
|
|
997
|
+
deviceId,
|
|
998
|
+
},
|
|
999
|
+
headers: {
|
|
1000
|
+
authorization: `Bearer ${accessToken}`,
|
|
1001
|
+
},
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
incorrectScopeExpectation(response);
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
it('should return 401 when incorrect access token is provided', async () => {
|
|
1008
|
+
const response = await fastify.injectJson({
|
|
1009
|
+
method: 'PUT',
|
|
1010
|
+
url: `/api/v0.6/devices/${device.deviceId}`,
|
|
1011
|
+
payload: {
|
|
1012
|
+
deviceType: 'phone',
|
|
1013
|
+
deviceOS: 'ios',
|
|
1014
|
+
deviceId,
|
|
1015
|
+
},
|
|
1016
|
+
headers: {
|
|
1017
|
+
authorization: 'Bearer incorrect_token',
|
|
1018
|
+
},
|
|
1019
|
+
});
|
|
1020
|
+
|
|
1021
|
+
incorrectAccessTokenExpectation(response);
|
|
1022
|
+
});
|
|
1023
|
+
});
|
|
1024
|
+
});
|
|
1025
|
+
});
|