@velocitycareerlabs/server-webwallet 1.27.0-dev-build.18cc7822e → 1.27.0-dev-build.191854f58
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/package.json +18 -18
- package/src/controllers/linkedin/controller.js +9 -6
- package/src/fetchers/career-wallet/create-account-fetcher.js +4 -2
- package/src/fetchers/career-wallet/create-did-fetcher.js +12 -9
- package/src/fetchers/career-wallet/get-app-config.js +6 -6
- package/src/fetchers/career-wallet/get-consents.js +8 -5
- package/src/fetchers/career-wallet/get-credential-categories.js +6 -2
- package/src/fetchers/career-wallet/get-personas.js +4 -2
- package/src/fetchers/career-wallet/post-consent.js +7 -4
- package/src/fetchers/career-wallet/send-feedback.js +8 -9
- package/src/fetchers/career-wallet/sign-fetcher.js +8 -9
- package/src/fetchers/career-wallet/verify-id-credential-confirm-code.js +9 -7
- package/src/fetchers/career-wallet/verify-id-credential-request-code.js +9 -7
- package/src/fetchers/credverify/remove-credentials.js +9 -6
- package/src/fetchers/lib-api/get-credential-display-schema.js +6 -7
- package/src/fetchers/linkedin/create-linkedin-post.js +35 -32
- package/src/fetchers/linkedin/get-access-token.js +18 -15
- package/src/fetchers/linkedin/get-linkedin-user-email.js +8 -5
- package/src/fetchers/linkedin/get-linkedin-user-id.js +11 -11
- package/src/fetchers/linkedin/register-image-to-upload.js +20 -17
- package/src/fetchers/linkedin/revoke-linkedin-access.js +18 -12
- package/src/fetchers/linkedin/upload-image-to-linkedin.js +10 -10
- package/src/init-server.js +44 -64
- package/src/plugins/crypto-services/jwt-sign-service-impl.js +7 -1
- package/src/plugins/crypto-services/key-service-impl.js +7 -1
- package/src/plugins/fetch-errors-handler-plugin.js +22 -9
- package/test/fetch-errors-handler-plugin.test.js +34 -11
- package/test/linkedin-controller.test.js +1 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velocitycareerlabs/server-webwallet",
|
|
3
|
-
"version": "1.27.0-dev-build.
|
|
3
|
+
"version": "1.27.0-dev-build.191854f58",
|
|
4
4
|
"description": "Web Wallet application",
|
|
5
5
|
"repository": "https://github.com/velocitycareerlabs/packages",
|
|
6
6
|
"engines": {
|
|
@@ -34,31 +34,31 @@
|
|
|
34
34
|
"@fastify/swagger": "^9.0.0",
|
|
35
35
|
"@fastify/swagger-ui": "^5.0.0",
|
|
36
36
|
"@spencejs/spence-mongo-repos": "^0.10.2",
|
|
37
|
-
"@velocitycareerlabs/migrations": "1.27.0-dev-build.
|
|
38
|
-
"@verii/auth": "1.0.
|
|
39
|
-
"@verii/common-functions": "1.0.
|
|
40
|
-
"@verii/common-schemas": "1.0.
|
|
41
|
-
"@verii/config": "1.0.
|
|
42
|
-
"@verii/fastify-plugins": "1.0.
|
|
43
|
-
"@verii/
|
|
44
|
-
"@verii/
|
|
45
|
-
"@verii/server-provider": "1.0.
|
|
46
|
-
"@verii/vc-checks": "1.0.
|
|
47
|
-
"@verii/vnf-nodejs-wallet-sdk": "1.0.
|
|
37
|
+
"@velocitycareerlabs/migrations": "1.27.0-dev-build.191854f58",
|
|
38
|
+
"@verii/auth": "1.1.0-pre.1762411615",
|
|
39
|
+
"@verii/common-functions": "1.1.0-pre.1762411615",
|
|
40
|
+
"@verii/common-schemas": "1.1.0-pre.1762411615",
|
|
41
|
+
"@verii/config": "1.1.0-pre.1762411615",
|
|
42
|
+
"@verii/fastify-plugins": "1.1.0-pre.1762411615",
|
|
43
|
+
"@verii/http-client": "1.1.0-pre.1762411615",
|
|
44
|
+
"@verii/jwt": "1.1.0-pre.1762411615",
|
|
45
|
+
"@verii/server-provider": "1.1.0-pre.1762411615",
|
|
46
|
+
"@verii/vc-checks": "1.1.0-pre.1762411615",
|
|
47
|
+
"@verii/vnf-nodejs-wallet-sdk": "1.1.0-pre.1762411615",
|
|
48
48
|
"blueimp-md5": "2.19.0",
|
|
49
49
|
"env-var": "^7.0.0",
|
|
50
50
|
"fastify": "^5.0.0",
|
|
51
51
|
"fastify-plugin": "^5.0.0",
|
|
52
|
-
"got": "11.8.6",
|
|
53
52
|
"http-errors": "2.0.0",
|
|
54
53
|
"lodash": "^4.17.21",
|
|
55
54
|
"migrate-mongo": "~11.0.0",
|
|
56
|
-
"mongodb": "~6.19.0"
|
|
55
|
+
"mongodb": "~6.19.0",
|
|
56
|
+
"undici": "^7.0.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@spencejs/spence-factories": "0.10.2",
|
|
60
|
-
"@verii/crypto": "1.0.
|
|
61
|
-
"@verii/tests-helpers": "1.0.
|
|
60
|
+
"@verii/crypto": "1.1.0-pre.1762411615",
|
|
61
|
+
"@verii/tests-helpers": "1.1.0-pre.1762411615",
|
|
62
62
|
"dotenv": "16.6.1",
|
|
63
63
|
"eslint": "8.57.1",
|
|
64
64
|
"eslint-config-airbnb-base": "14.2.1",
|
|
@@ -70,9 +70,9 @@
|
|
|
70
70
|
"eslint-plugin-prettier": "4.2.5",
|
|
71
71
|
"eslint-watch": "7.0.0",
|
|
72
72
|
"expect": "30.2.0",
|
|
73
|
-
"nock": "
|
|
73
|
+
"nock": "v15.0.0-beta.6",
|
|
74
74
|
"nodemon": "3.1.10",
|
|
75
75
|
"prettier": "2.8.8"
|
|
76
76
|
},
|
|
77
|
-
"gitHead": "
|
|
77
|
+
"gitHead": "6fa4496c8f99eb2b05763ba4d8140a5e3008707e"
|
|
78
78
|
}
|
|
@@ -119,7 +119,7 @@ const linkedinController = async (fastify) => {
|
|
|
119
119
|
userEmail: elements[0]['handle~'].emailAddress,
|
|
120
120
|
};
|
|
121
121
|
} catch (error) {
|
|
122
|
-
if (error?.
|
|
122
|
+
if (error?.statusCode === 401) {
|
|
123
123
|
await accounts.updateUsingFilter(
|
|
124
124
|
{
|
|
125
125
|
filter: { userId: user.sub },
|
|
@@ -244,11 +244,14 @@ const linkedinController = async (fastify) => {
|
|
|
244
244
|
asset: uploadLinkData.value.asset,
|
|
245
245
|
};
|
|
246
246
|
|
|
247
|
-
await uploadImageToLinkedin(
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
247
|
+
await uploadImageToLinkedin(
|
|
248
|
+
{
|
|
249
|
+
accessToken: linkedinAccessToken,
|
|
250
|
+
file: params.logo,
|
|
251
|
+
uploadUrl: imageData.uploadUrl,
|
|
252
|
+
},
|
|
253
|
+
req
|
|
254
|
+
);
|
|
252
255
|
}
|
|
253
256
|
return createLinkedinPost(
|
|
254
257
|
{
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
const createCareerWalletAccount = (payload, { careerWalletFetch }) => {
|
|
2
|
-
|
|
1
|
+
const createCareerWalletAccount = async (payload, { careerWalletFetch }) => {
|
|
2
|
+
const response = await careerWalletFetch.post('api/v0.6/accounts', payload);
|
|
3
|
+
|
|
4
|
+
return response.json();
|
|
3
5
|
};
|
|
4
6
|
|
|
5
7
|
module.exports = {
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
const createDidForAccount = (crv, accessToken, { careerWalletFetch }) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
const createDidForAccount = async (crv, accessToken, { careerWalletFetch }) => {
|
|
2
|
+
const response = await careerWalletFetch.post(
|
|
3
|
+
'api/v0.6/create_did_key',
|
|
4
|
+
{
|
|
5
|
+
crv: `${crv}`,
|
|
6
|
+
didMethod: 'did:jwk',
|
|
7
|
+
},
|
|
8
|
+
{
|
|
8
9
|
headers: {
|
|
9
10
|
Authorization: `Bearer ${accessToken}`,
|
|
10
11
|
},
|
|
11
|
-
}
|
|
12
|
-
|
|
12
|
+
}
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
return response.json();
|
|
13
16
|
};
|
|
14
17
|
|
|
15
18
|
module.exports = {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const getAppConfig = async ({ careerWalletFetch
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
const getAppConfig = async ({ careerWalletFetch }) => {
|
|
2
|
+
const response = await careerWalletFetch.get(
|
|
3
|
+
'api/v0.6/careerwallet/appconfig'
|
|
4
|
+
);
|
|
5
|
+
|
|
6
|
+
return response.json();
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
module.exports = {
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
const getConsentLatest = (accountId, { careerWalletFetch, config }) => {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
const getConsentLatest = async (accountId, { careerWalletFetch, config }) => {
|
|
2
|
+
const response = await careerWalletFetch.get(
|
|
3
|
+
`api/v0.6/careerwallet/consents/latest?accountId=${accountId}`,
|
|
4
|
+
{
|
|
4
5
|
headers: {
|
|
5
6
|
Authorization: `Bearer ${config.careerWalletAdminAccessToken}`,
|
|
6
7
|
},
|
|
7
|
-
}
|
|
8
|
-
|
|
8
|
+
}
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
return response.json();
|
|
9
12
|
};
|
|
10
13
|
|
|
11
14
|
module.exports = {
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
const getCredentialCategories = ({ careerWalletFetch }) => {
|
|
2
|
-
|
|
1
|
+
const getCredentialCategories = async ({ careerWalletFetch }) => {
|
|
2
|
+
const response = await careerWalletFetch.get(
|
|
3
|
+
'api/v0.6/credential-categories'
|
|
4
|
+
);
|
|
5
|
+
|
|
6
|
+
return response.json();
|
|
3
7
|
};
|
|
4
8
|
|
|
5
9
|
module.exports = {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
const getPersonas = ({ careerWalletFetch
|
|
2
|
-
|
|
1
|
+
const getPersonas = async ({ careerWalletFetch }) => {
|
|
2
|
+
const response = await careerWalletFetch.get('reference/personas');
|
|
3
|
+
|
|
4
|
+
return response.json();
|
|
3
5
|
};
|
|
4
6
|
|
|
5
7
|
module.exports = {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
const postConsent = (payload, authorization, { careerWalletFetch }) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
const postConsent = async (payload, authorization, { careerWalletFetch }) => {
|
|
2
|
+
const response = await careerWalletFetch.post(
|
|
3
|
+
'api/v0.6/careerwallet/consents/add',
|
|
4
|
+
payload
|
|
5
|
+
);
|
|
6
|
+
|
|
7
|
+
return response.json();
|
|
5
8
|
};
|
|
6
9
|
|
|
7
10
|
module.exports = {
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
const sendFeedback = (payload, { careerWalletFetch, config }) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
.json();
|
|
1
|
+
const sendFeedback = async (payload, { careerWalletFetch, config }) => {
|
|
2
|
+
const response = await careerWalletFetch.post('api/v0.6/feedback', payload, {
|
|
3
|
+
headers: {
|
|
4
|
+
Authorization: `Bearer ${config.careerWalletAdminAccessToken}`,
|
|
5
|
+
},
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
return response.json();
|
|
10
9
|
};
|
|
11
10
|
|
|
12
11
|
module.exports = {
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
const signFetcher = (payload, accessToken, { careerWalletFetch }) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
.json();
|
|
1
|
+
const signFetcher = async (payload, accessToken, { careerWalletFetch }) => {
|
|
2
|
+
const response = await careerWalletFetch.post('api/v0.6/jwt/sign', payload, {
|
|
3
|
+
headers: {
|
|
4
|
+
Authorization: `Bearer ${accessToken}`,
|
|
5
|
+
},
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
return response.json();
|
|
10
9
|
};
|
|
11
10
|
|
|
12
11
|
module.exports = {
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
const verifyIdCredentialConfirmCode = async (
|
|
2
2
|
verificationCode,
|
|
3
|
-
{ careerWalletFetch,
|
|
3
|
+
{ careerWalletFetch, config }
|
|
4
4
|
) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const response = await careerWalletFetch.post(
|
|
6
|
+
'api/v0.6/verify/confirm',
|
|
7
|
+
{ verificationCode },
|
|
8
|
+
{
|
|
8
9
|
headers: {
|
|
9
10
|
'x-vcl-verif-version': config.vclVerificationVersion,
|
|
10
11
|
Authorization: `Bearer ${config.careerWalletAdminAccessToken}`,
|
|
11
12
|
},
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
return response.json();
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
module.exports = {
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
const verifyIdCredentialRequestCode = async (
|
|
2
2
|
credentialType,
|
|
3
3
|
value,
|
|
4
|
-
{ careerWalletFetch,
|
|
4
|
+
{ careerWalletFetch, config }
|
|
5
5
|
) => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const response = await careerWalletFetch.post(
|
|
7
|
+
`api/v0.6/verify/${credentialType}/request-code`,
|
|
8
|
+
{ value },
|
|
9
|
+
{
|
|
9
10
|
headers: {
|
|
10
11
|
'x-vcl-verif-version': config.vclVerificationVersion,
|
|
11
12
|
Authorization: `Bearer ${config.careerWalletAdminAccessToken}`,
|
|
12
13
|
},
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
return response.json();
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
module.exports = {
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
const removeCredentials = (
|
|
1
|
+
const removeCredentials = async (
|
|
2
2
|
payload,
|
|
3
3
|
{ verificationServiceActionFetch, config }
|
|
4
4
|
) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const response = await verificationServiceActionFetch.post(
|
|
6
|
+
'remove-credentials',
|
|
7
|
+
payload,
|
|
8
|
+
{
|
|
8
9
|
headers: {
|
|
9
10
|
Authorization: `Bearer ${config.careerWalletAdminAccessToken}`,
|
|
10
11
|
},
|
|
11
|
-
}
|
|
12
|
-
|
|
12
|
+
}
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
return response.json();
|
|
13
16
|
};
|
|
14
17
|
|
|
15
18
|
module.exports = {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
const getCredentialDisplaySchema = async (
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
.json();
|
|
1
|
+
const getCredentialDisplaySchema = async (credentialType, { libFetch }) => {
|
|
2
|
+
const response = await libFetch.get(
|
|
3
|
+
`display-descriptors/${credentialType}.descriptor.json`
|
|
4
|
+
);
|
|
5
|
+
|
|
6
|
+
return response.json();
|
|
8
7
|
};
|
|
9
8
|
|
|
10
9
|
module.exports = {
|
|
@@ -1,43 +1,46 @@
|
|
|
1
|
-
const createLinkedinPost = (
|
|
1
|
+
const createLinkedinPost = async (
|
|
2
2
|
{ accessToken, linkedinUserId, text, asset },
|
|
3
3
|
{ linkedInFetch }
|
|
4
4
|
) => {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const response = await linkedInFetch.post(
|
|
6
|
+
'ugcPosts',
|
|
7
|
+
{
|
|
8
|
+
author: `urn:li:person:${linkedinUserId}`,
|
|
9
|
+
lifecycleState: 'PUBLISHED',
|
|
10
|
+
specificContent: {
|
|
11
|
+
'com.linkedin.ugc.ShareContent': {
|
|
12
|
+
shareCommentary: {
|
|
13
|
+
text,
|
|
14
|
+
},
|
|
15
|
+
...(asset
|
|
16
|
+
? {
|
|
17
|
+
shareMediaCategory: 'IMAGE',
|
|
18
|
+
media: [
|
|
19
|
+
{
|
|
20
|
+
status: 'READY',
|
|
21
|
+
media: asset,
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
}
|
|
25
|
+
: {
|
|
26
|
+
shareMediaCategory: 'NONE',
|
|
27
|
+
}),
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
visibility: {
|
|
31
|
+
'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
7
35
|
headers: {
|
|
8
36
|
'Content-Type': 'application/json',
|
|
9
37
|
'X-Restli-Protocol-Version': '2.0.0',
|
|
10
38
|
Authorization: `Bearer ${accessToken}`,
|
|
11
39
|
},
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
'com.linkedin.ugc.ShareContent': {
|
|
17
|
-
shareCommentary: {
|
|
18
|
-
text,
|
|
19
|
-
},
|
|
20
|
-
...(asset
|
|
21
|
-
? {
|
|
22
|
-
shareMediaCategory: 'IMAGE',
|
|
23
|
-
media: [
|
|
24
|
-
{
|
|
25
|
-
status: 'READY',
|
|
26
|
-
media: asset,
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
}
|
|
30
|
-
: {
|
|
31
|
-
shareMediaCategory: 'NONE',
|
|
32
|
-
}),
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
visibility: {
|
|
36
|
-
'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC',
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
})
|
|
40
|
-
.json();
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return response.json();
|
|
41
44
|
};
|
|
42
45
|
|
|
43
46
|
module.exports = {
|
|
@@ -1,24 +1,27 @@
|
|
|
1
|
-
const getLinkedInAccessToken = (
|
|
1
|
+
const getLinkedInAccessToken = async (
|
|
2
2
|
{ code, redirectUri },
|
|
3
3
|
{ config, linkedInAuthFetch }
|
|
4
4
|
) => {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const response = await linkedInAuthFetch.post(
|
|
6
|
+
'accessToken',
|
|
7
|
+
String(
|
|
8
|
+
new URLSearchParams({
|
|
9
|
+
code,
|
|
10
|
+
redirect_uri:
|
|
11
|
+
redirectUri || `${config.webWalletBaseUrl}/share-to-linkedin`,
|
|
12
|
+
client_id: config.linkedIn.clientId,
|
|
13
|
+
client_secret: config.linkedIn.clientSecret,
|
|
14
|
+
grant_type: 'authorization_code',
|
|
15
|
+
})
|
|
16
|
+
),
|
|
17
|
+
{
|
|
7
18
|
headers: {
|
|
8
19
|
'Content-Type': ' application/x-www-form-urlencoded',
|
|
9
20
|
},
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
redirectUri || `${config.webWalletBaseUrl}/share-to-linkedin`,
|
|
15
|
-
client_id: config.linkedIn.clientId,
|
|
16
|
-
client_secret: config.linkedIn.clientSecret,
|
|
17
|
-
grant_type: 'authorization_code',
|
|
18
|
-
})
|
|
19
|
-
),
|
|
20
|
-
})
|
|
21
|
-
.json();
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return response.json();
|
|
22
25
|
};
|
|
23
26
|
|
|
24
27
|
module.exports = {
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
const getLinkedInUserEmail = (accessToken, { linkedInFetch }) => {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
const getLinkedInUserEmail = async (accessToken, { linkedInFetch }) => {
|
|
2
|
+
const response = await linkedInFetch.get(
|
|
3
|
+
'emailAddress?q=members&projection=(elements*(handle~))',
|
|
4
|
+
{
|
|
4
5
|
headers: {
|
|
5
6
|
Authorization: `Bearer ${accessToken}`,
|
|
6
7
|
},
|
|
7
|
-
}
|
|
8
|
-
|
|
8
|
+
}
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
return response.json();
|
|
9
12
|
};
|
|
10
13
|
|
|
11
14
|
module.exports = {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
const getLinkedInUserId = (accessToken, { linkedInFetch }) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
{
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
const getLinkedInUserId = async (accessToken, { linkedInFetch }) => {
|
|
2
|
+
const response = await linkedInFetch.get(
|
|
3
|
+
'me?projection=(id,localizedFirstName,localizedLastName,profilePicture(displayImage~digitalmediaAsset:playableStreams))',
|
|
4
|
+
{
|
|
5
|
+
headers: {
|
|
6
|
+
Authorization: `Bearer ${accessToken}`,
|
|
7
|
+
},
|
|
8
|
+
}
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
return response.json();
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
module.exports = {
|
|
@@ -1,28 +1,31 @@
|
|
|
1
|
-
const registerImageToUpload = (
|
|
1
|
+
const registerImageToUpload = async (
|
|
2
2
|
{ linkedinUserId, accessToken },
|
|
3
3
|
{ linkedInFetch }
|
|
4
4
|
) => {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const response = await linkedInFetch.post(
|
|
6
|
+
'assets?action=registerUpload',
|
|
7
|
+
{
|
|
8
|
+
registerUploadRequest: {
|
|
9
|
+
recipes: ['urn:li:digitalmediaRecipe:feedshare-image'],
|
|
10
|
+
owner: `urn:li:person:${linkedinUserId}`,
|
|
11
|
+
serviceRelationships: [
|
|
12
|
+
{
|
|
13
|
+
relationshipType: 'OWNER',
|
|
14
|
+
identifier: 'urn:li:userGeneratedContent',
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
{
|
|
7
20
|
headers: {
|
|
8
21
|
'Content-Type': 'application/json',
|
|
9
22
|
'X-Restli-Protocol-Version': '2.0.0',
|
|
10
23
|
Authorization: `Bearer ${accessToken}`,
|
|
11
24
|
},
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
serviceRelationships: [
|
|
17
|
-
{
|
|
18
|
-
relationshipType: 'OWNER',
|
|
19
|
-
identifier: 'urn:li:userGeneratedContent',
|
|
20
|
-
},
|
|
21
|
-
],
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
})
|
|
25
|
-
.json();
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return response.json();
|
|
26
29
|
};
|
|
27
30
|
|
|
28
31
|
module.exports = {
|
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
const revokeLinkedinAccess = (
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
const revokeLinkedinAccess = async (
|
|
2
|
+
accessToken,
|
|
3
|
+
{ config, linkedInAuthFetch }
|
|
4
|
+
) => {
|
|
5
|
+
const response = await linkedInAuthFetch.post(
|
|
6
|
+
'revoke',
|
|
7
|
+
String(
|
|
8
|
+
new URLSearchParams({
|
|
9
|
+
client_id: config.linkedIn.clientId,
|
|
10
|
+
client_secret: config.linkedIn.clientSecret,
|
|
11
|
+
token: accessToken,
|
|
12
|
+
})
|
|
13
|
+
),
|
|
14
|
+
{
|
|
4
15
|
headers: {
|
|
5
16
|
'Content-Type': ' application/x-www-form-urlencoded',
|
|
6
17
|
},
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
token: accessToken,
|
|
12
|
-
})
|
|
13
|
-
),
|
|
14
|
-
})
|
|
15
|
-
.json();
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
return response.json();
|
|
16
22
|
};
|
|
17
23
|
|
|
18
24
|
module.exports = {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
const
|
|
1
|
+
const uploadImageToLinkedin = async (
|
|
2
|
+
{ accessToken, uploadUrl, file },
|
|
3
|
+
{ fetch }
|
|
4
|
+
) => {
|
|
5
|
+
const response = await fetch.post(uploadUrl, file, {
|
|
6
|
+
headers: {
|
|
7
|
+
Authorization: `Bearer ${accessToken}`,
|
|
8
|
+
},
|
|
9
|
+
});
|
|
2
10
|
|
|
3
|
-
|
|
4
|
-
return got
|
|
5
|
-
.post(uploadUrl, {
|
|
6
|
-
headers: {
|
|
7
|
-
Authorization: `Bearer ${accessToken}`,
|
|
8
|
-
},
|
|
9
|
-
body: file,
|
|
10
|
-
})
|
|
11
|
-
.json();
|
|
11
|
+
return response.json();
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
module.exports = {
|
package/src/init-server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { corsPlugin } = require('@verii/fastify-plugins');
|
|
2
|
-
const
|
|
2
|
+
const { httpClientPlugin } = require('@verii/fastify-plugins');
|
|
3
3
|
const AutoLoad = require('@fastify/autoload');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const { pick } = require('lodash/fp');
|
|
@@ -27,87 +27,67 @@ const initServer = (server) => {
|
|
|
27
27
|
autoHooks: true,
|
|
28
28
|
cascadeHooks: true,
|
|
29
29
|
})
|
|
30
|
-
.
|
|
31
|
-
'
|
|
32
|
-
|
|
30
|
+
.register(httpClientPlugin, {
|
|
31
|
+
name: 'fetch',
|
|
32
|
+
options: pick(
|
|
33
|
+
['nodeEnv', 'requestTimeout', 'traceIdHeader', 'isTest'],
|
|
34
|
+
server.config
|
|
35
|
+
),
|
|
36
|
+
})
|
|
37
|
+
.register(httpClientPlugin, {
|
|
38
|
+
name: 'agentFetch',
|
|
39
|
+
options: {
|
|
33
40
|
...server.config,
|
|
34
41
|
prefixUrl: server.config.agentUrl,
|
|
35
|
-
}
|
|
36
|
-
)
|
|
37
|
-
.decorateRequest('agentFetch', null)
|
|
38
|
-
.addHook('preValidation', async (req) => {
|
|
39
|
-
req.agentFetch = server.baseAgentFetch(req);
|
|
42
|
+
},
|
|
40
43
|
})
|
|
41
|
-
.
|
|
42
|
-
'
|
|
43
|
-
|
|
44
|
+
.register(httpClientPlugin, {
|
|
45
|
+
name: 'registrarFetch',
|
|
46
|
+
options: {
|
|
44
47
|
...server.config,
|
|
45
48
|
prefixUrl: server.config.registrarUrl,
|
|
46
|
-
}
|
|
47
|
-
)
|
|
48
|
-
.decorateRequest('registrarFetch', null)
|
|
49
|
-
.addHook('preValidation', async (req) => {
|
|
50
|
-
req.registrarFetch = server.baseRegistrarFetch(req);
|
|
49
|
+
},
|
|
51
50
|
})
|
|
52
|
-
.
|
|
53
|
-
'
|
|
54
|
-
|
|
55
|
-
...pick(
|
|
51
|
+
.register(httpClientPlugin, {
|
|
52
|
+
name: 'libFetch',
|
|
53
|
+
options: {
|
|
54
|
+
...pick(
|
|
55
|
+
['nodeEnv', 'requestTimeout', 'traceIdHeader', 'isTest'],
|
|
56
|
+
server.config
|
|
57
|
+
),
|
|
56
58
|
prefixUrl: server.config.libUrl,
|
|
57
|
-
}
|
|
58
|
-
)
|
|
59
|
-
.decorateRequest('libFetch', null)
|
|
60
|
-
.addHook('preValidation', async (req) => {
|
|
61
|
-
req.libFetch = server.baseLibFetch(req);
|
|
59
|
+
},
|
|
62
60
|
})
|
|
63
|
-
.
|
|
64
|
-
'
|
|
65
|
-
|
|
66
|
-
...pick(
|
|
61
|
+
.register(httpClientPlugin, {
|
|
62
|
+
name: 'verificationServiceActionFetch',
|
|
63
|
+
options: {
|
|
64
|
+
...pick(
|
|
65
|
+
['nodeEnv', 'requestTimeout', 'traceIdHeader', 'isTest'],
|
|
66
|
+
server.config
|
|
67
|
+
),
|
|
67
68
|
prefixUrl: server.config.verificationServiceActionBaseUrl,
|
|
68
|
-
}
|
|
69
|
-
)
|
|
70
|
-
.decorateRequest('verificationServiceActionFetch', null)
|
|
71
|
-
.addHook('preValidation', async (req) => {
|
|
72
|
-
req.verificationServiceActionFetch =
|
|
73
|
-
server.baseVerificationServiceActionFetch(req);
|
|
69
|
+
},
|
|
74
70
|
})
|
|
75
|
-
.
|
|
76
|
-
'
|
|
77
|
-
|
|
71
|
+
.register(httpClientPlugin, {
|
|
72
|
+
name: 'careerWalletFetch',
|
|
73
|
+
options: {
|
|
78
74
|
...server.config,
|
|
79
75
|
prefixUrl: server.config.careerWalletUrl,
|
|
80
|
-
}
|
|
81
|
-
)
|
|
82
|
-
.decorate(
|
|
83
|
-
'globalCareerWalletFetch',
|
|
84
|
-
server.baseCareerWalletFetch({ log: server.log })
|
|
85
|
-
)
|
|
86
|
-
.decorateRequest('careerWalletFetch', null)
|
|
87
|
-
.addHook('preValidation', async (req) => {
|
|
88
|
-
req.careerWalletFetch = server.baseCareerWalletFetch(req);
|
|
76
|
+
},
|
|
89
77
|
})
|
|
90
|
-
.
|
|
91
|
-
'
|
|
92
|
-
|
|
78
|
+
.register(httpClientPlugin, {
|
|
79
|
+
name: 'linkedInFetch',
|
|
80
|
+
options: {
|
|
93
81
|
...server.config,
|
|
94
82
|
prefixUrl: server.config.linkedIn.apiUrl,
|
|
95
|
-
}
|
|
96
|
-
)
|
|
97
|
-
.decorateRequest('linkedInFetch', null)
|
|
98
|
-
.addHook('preValidation', async (req) => {
|
|
99
|
-
req.linkedInFetch = server.baseLinkedInFetch(req);
|
|
83
|
+
},
|
|
100
84
|
})
|
|
101
|
-
.
|
|
102
|
-
'
|
|
103
|
-
|
|
85
|
+
.register(httpClientPlugin, {
|
|
86
|
+
name: 'linkedInAuthFetch',
|
|
87
|
+
options: {
|
|
104
88
|
...server.config,
|
|
105
89
|
prefixUrl: server.config.linkedIn.authUrl,
|
|
106
|
-
}
|
|
107
|
-
)
|
|
108
|
-
.decorateRequest('linkedInAuthFetch', null)
|
|
109
|
-
.addHook('preValidation', async (req) => {
|
|
110
|
-
req.linkedInAuthFetch = server.baseLinkedInAuthFetch(req);
|
|
90
|
+
},
|
|
111
91
|
})
|
|
112
92
|
.register(vnfSdkPlugin)
|
|
113
93
|
.addHook('preValidation', async (req) => {
|
|
@@ -13,7 +13,13 @@ const JwtSignServiceImpl = (context) => {
|
|
|
13
13
|
const signedJwtRes = await signFetcher(
|
|
14
14
|
payload,
|
|
15
15
|
remoteCryptoServicesToken,
|
|
16
|
-
{
|
|
16
|
+
{
|
|
17
|
+
...context,
|
|
18
|
+
careerWalletFetch: context.baseCareerWalletFetch()(
|
|
19
|
+
context.config.careerWalletUrl,
|
|
20
|
+
context
|
|
21
|
+
),
|
|
22
|
+
}
|
|
17
23
|
);
|
|
18
24
|
const signedJwt = signedJwtRes.compactJwt;
|
|
19
25
|
return new Promise((resolve) => {
|
|
@@ -9,7 +9,13 @@ const KeyServiceImpl = (context) => {
|
|
|
9
9
|
const didJwkJson = await createDidForAccount(
|
|
10
10
|
didJwkDescriptor.signatureAlgorithm,
|
|
11
11
|
didJwkDescriptor.remoteCryptoServicesToken,
|
|
12
|
-
{
|
|
12
|
+
{
|
|
13
|
+
...context,
|
|
14
|
+
careerWalletFetch: context.baseCareerWalletFetch()(
|
|
15
|
+
context.config.careerWalletUrl,
|
|
16
|
+
context
|
|
17
|
+
),
|
|
18
|
+
}
|
|
13
19
|
);
|
|
14
20
|
return new Promise((resolve) => {
|
|
15
21
|
resolve(VCLDidJwk.fromJSON(didJwkJson));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const fp = require('fastify-plugin');
|
|
2
2
|
const newError = require('http-errors');
|
|
3
|
-
const {
|
|
3
|
+
const { errors } = require('undici');
|
|
4
4
|
const { isObject } = require('lodash/fp');
|
|
5
5
|
const { WebWalletServerError } = require('../errors/error-codes');
|
|
6
6
|
|
|
@@ -20,7 +20,7 @@ const fetchErrorsHandlerPlugin = (fastify, options, next) => {
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
const handleHttpErrors = (error) => {
|
|
23
|
-
if (error instanceof
|
|
23
|
+
if (error instanceof errors.ResponseError) {
|
|
24
24
|
handleHTTPError(error);
|
|
25
25
|
} else {
|
|
26
26
|
handleGenericError(error);
|
|
@@ -28,16 +28,29 @@ const handleHttpErrors = (error) => {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
const handleHTTPError = (error) => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
error
|
|
34
|
-
errorBody?.message || errorBody || error.response.statusMessage,
|
|
35
|
-
{
|
|
31
|
+
if (!error.errorCode) {
|
|
32
|
+
const errorBody = getErrorBody(error);
|
|
33
|
+
throw newError(getStatusCode(error), getErrorMesssage(error, errorBody), {
|
|
36
34
|
...(isObject(errorBody) ? errorBody : {}),
|
|
37
|
-
}
|
|
38
|
-
|
|
35
|
+
});
|
|
36
|
+
} else {
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
+
const getErrorBody = (error) =>
|
|
42
|
+
parseErrorBody(error?.response?.body || error?.body);
|
|
43
|
+
|
|
44
|
+
const getStatusCode = (error) =>
|
|
45
|
+
error?.response?.statusCode || error?.statusCode;
|
|
46
|
+
|
|
47
|
+
const getErrorMesssage = (error, errorBody) =>
|
|
48
|
+
errorBody?.message ||
|
|
49
|
+
errorBody ||
|
|
50
|
+
error?.statusMessage ||
|
|
51
|
+
error?.code ||
|
|
52
|
+
'HTTP Error';
|
|
53
|
+
|
|
41
54
|
const handleGenericError = (error) => {
|
|
42
55
|
if (!error.errorCode) {
|
|
43
56
|
throw newError(error.statusCode || 500, error.message, {
|
|
@@ -4,9 +4,21 @@ const { expect } = require('expect');
|
|
|
4
4
|
|
|
5
5
|
const buildFastify = require('fastify');
|
|
6
6
|
const nock = require('nock');
|
|
7
|
-
const
|
|
7
|
+
const { request, errors } = require('undici');
|
|
8
8
|
const { fetchErrorsHandlerPlugin } = require('../src/plugins');
|
|
9
9
|
|
|
10
|
+
const handleResponse = async (response, isText = false) => {
|
|
11
|
+
if (response.statusCode >= 300) {
|
|
12
|
+
const body = isText
|
|
13
|
+
? await response.body.text()
|
|
14
|
+
: await response.body.json();
|
|
15
|
+
throw new errors.ResponseError(body.message, response.statusCode, {
|
|
16
|
+
code: body.code,
|
|
17
|
+
body,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
10
22
|
describe('Test fetchErrorsHandlerPlugin', () => {
|
|
11
23
|
let fastify;
|
|
12
24
|
|
|
@@ -16,9 +28,13 @@ describe('Test fetchErrorsHandlerPlugin', () => {
|
|
|
16
28
|
});
|
|
17
29
|
|
|
18
30
|
it('Should return the same HTTPError as the nested fetch request', async () => {
|
|
19
|
-
fastify.get('/test', () =>
|
|
20
|
-
|
|
21
|
-
|
|
31
|
+
fastify.get('/test', async () => {
|
|
32
|
+
const response = await request(
|
|
33
|
+
'https://test/endpoint_that_returns_error'
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
await handleResponse(response);
|
|
37
|
+
});
|
|
22
38
|
|
|
23
39
|
const nockedRequest = nock('https://test')
|
|
24
40
|
.get('/endpoint_that_returns_error')
|
|
@@ -49,9 +65,13 @@ describe('Test fetchErrorsHandlerPlugin', () => {
|
|
|
49
65
|
});
|
|
50
66
|
|
|
51
67
|
it('Should return correct error when nested fetch request returns fatal error', async () => {
|
|
52
|
-
fastify.get('/test', () =>
|
|
53
|
-
|
|
54
|
-
|
|
68
|
+
fastify.get('/test', async () => {
|
|
69
|
+
const response = await request(
|
|
70
|
+
'https://test/endpoint_that_throws_fatal_error'
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
await handleResponse(response);
|
|
74
|
+
});
|
|
55
75
|
|
|
56
76
|
const nockedRequest = nock('https://test')
|
|
57
77
|
.get('/endpoint_that_throws_fatal_error')
|
|
@@ -65,7 +85,6 @@ describe('Test fetchErrorsHandlerPlugin', () => {
|
|
|
65
85
|
expect(response.statusCode).toBe(500);
|
|
66
86
|
|
|
67
87
|
expect(response.json()).toEqual({
|
|
68
|
-
code: 'ERR_GOT_REQUEST_ERROR',
|
|
69
88
|
error: 'Internal Server Error',
|
|
70
89
|
message: 'Unknown fatal error',
|
|
71
90
|
statusCode: 500,
|
|
@@ -75,9 +94,13 @@ describe('Test fetchErrorsHandlerPlugin', () => {
|
|
|
75
94
|
});
|
|
76
95
|
|
|
77
96
|
it('Should return correct error when nested fetch request returns string error', async () => {
|
|
78
|
-
fastify.get('/test', () =>
|
|
79
|
-
|
|
80
|
-
|
|
97
|
+
fastify.get('/test', async () => {
|
|
98
|
+
const response = await request(
|
|
99
|
+
'https://test/endpoint_that_returns_error'
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
await handleResponse(response, true);
|
|
103
|
+
});
|
|
81
104
|
|
|
82
105
|
const nockedRequest = nock('https://test')
|
|
83
106
|
.get('/endpoint_that_returns_error')
|
|
@@ -401,9 +401,7 @@ describe('linkedin-controller', () => {
|
|
|
401
401
|
});
|
|
402
402
|
|
|
403
403
|
expect(response.statusCode).toBe(400);
|
|
404
|
-
expect(JSON.parse(response.payload).error).toBe(
|
|
405
|
-
'Response code 400 (Bad Request)'
|
|
406
|
-
);
|
|
404
|
+
expect(JSON.parse(response.payload).error).toBe('Response Error');
|
|
407
405
|
});
|
|
408
406
|
});
|
|
409
407
|
});
|