@abtnode/auth 1.16.23-beta-7b5b0175 → 1.16.23-beta-06c3a221
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/lib/auth.js +8 -1
- package/lib/connect-to-did-spaces.js +99 -0
- package/lib/util/api.js +7 -0
- package/lib/util/spaces.js +190 -0
- package/locales/en.js +1 -0
- package/locales/zh.js +1 -0
- package/package.json +13 -8
package/lib/auth.js
CHANGED
|
@@ -40,6 +40,7 @@ const createPassportSvg = require('./util/create-passport-svg');
|
|
|
40
40
|
const messages = {
|
|
41
41
|
description: getLocaleMap('description'),
|
|
42
42
|
requestProfile: getLocaleMap('requestProfile'),
|
|
43
|
+
requestDidSpace: getLocaleMap('requestDidSpace'),
|
|
43
44
|
requestNFT: getLocaleMap('requestNFT'),
|
|
44
45
|
requestCredential: getLocaleMap('requestCredential'),
|
|
45
46
|
requestPassport: getLocaleMap('requestPassport'),
|
|
@@ -807,7 +808,13 @@ const handleIssuePassportResponse = async ({
|
|
|
807
808
|
const getVCFromClaims = ({ claims, challenge, trustedIssuers, vcTypes, locale = 'en', vcId }) => {
|
|
808
809
|
const credential = claims
|
|
809
810
|
.filter(Boolean) // FIXES: https://github.com/ArcBlock/did-connect/issues/74
|
|
810
|
-
.find(
|
|
811
|
+
.find(
|
|
812
|
+
(x) =>
|
|
813
|
+
x.type === 'verifiableCredential' &&
|
|
814
|
+
// 注意此处不要筛选出 did Spaces 的 verifiableCredential
|
|
815
|
+
x?.meta?.purpose !== 'DidSpace' &&
|
|
816
|
+
vcTypes.some((item) => x.item.includes(item))
|
|
817
|
+
);
|
|
811
818
|
|
|
812
819
|
if (!credential || !credential.presentation) {
|
|
813
820
|
return {};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const { getAppUrl, getAppName, getAppDescription } = require('@blocklet/meta/lib/util');
|
|
2
|
+
const { Joi } = require('@arcblock/validator');
|
|
3
|
+
const logger = require('@abtnode/logger')(require('../../../package.json').name);
|
|
4
|
+
const { DID_SPACES } = require('@blocklet/constant');
|
|
5
|
+
const { messages } = require('./auth');
|
|
6
|
+
const { getDidSpacesInfoByClaims, silentAuthorizationInConnect } = require('./util/spaces');
|
|
7
|
+
|
|
8
|
+
const ExtraParamsSchema = Joi.object({
|
|
9
|
+
referrer: Joi.string()
|
|
10
|
+
.uri({ scheme: ['http', 'https'] })
|
|
11
|
+
.required(),
|
|
12
|
+
appPid: Joi.DID().optional(),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @description
|
|
17
|
+
* @param {import('@abtnode/core').TNode} node
|
|
18
|
+
* @return {*}
|
|
19
|
+
*/
|
|
20
|
+
function createConnectToDidSpacesRoute(node) {
|
|
21
|
+
return {
|
|
22
|
+
action: 'connect-to-did-spaces',
|
|
23
|
+
onStart: ({ extraParams }) => {
|
|
24
|
+
const { error } = ExtraParamsSchema.validate(extraParams, {
|
|
25
|
+
allowUnknown: true,
|
|
26
|
+
});
|
|
27
|
+
if (error) {
|
|
28
|
+
throw new Error(error);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
onConnect: ({ extraParams: { locale } }) => {
|
|
33
|
+
return {
|
|
34
|
+
assetOrVC: {
|
|
35
|
+
description: messages.requestDidSpace[locale],
|
|
36
|
+
optional: false,
|
|
37
|
+
filters: [
|
|
38
|
+
{
|
|
39
|
+
tag: DID_SPACES.NFT_TAG, // 用于筛选 NFT
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
type: DID_SPACES.VC_TYPES, // 用于筛选 VC
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
meta: {
|
|
46
|
+
purpose: 'DidSpace',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
onAuth: async ({ claims, challenge, extraParams: { appPid, locale, referrer }, updateSession, request }) => {
|
|
53
|
+
/** @type {import('@abtnode/client').BlockletState} */
|
|
54
|
+
const blocklet = request.getBlocklet ? await request.getBlocklet() : await node.getBlocklet({ did: appPid });
|
|
55
|
+
|
|
56
|
+
const existsConnectSpaceClaim = claims.some(
|
|
57
|
+
(x) => x?.meta?.purpose === 'DidSpace' && ['asset', 'verifiableCredential'].includes(x.type)
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
if (!existsConnectSpaceClaim) {
|
|
61
|
+
logger.error('Unable to find claim for DID Spaces', { claims });
|
|
62
|
+
throw new Error('Unable to find claim for DID Spaces');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const didSpaceInfo = await getDidSpacesInfoByClaims({ claims });
|
|
66
|
+
const appUrl = getAppUrl(blocklet);
|
|
67
|
+
const { data } = await silentAuthorizationInConnect(didSpaceInfo, {
|
|
68
|
+
appInfo: {
|
|
69
|
+
appDid: blocklet.appDid,
|
|
70
|
+
appName: getAppName(blocklet),
|
|
71
|
+
appDescription: getAppDescription(blocklet),
|
|
72
|
+
appUrl,
|
|
73
|
+
scopes: 'list:object read:object write:object',
|
|
74
|
+
referrer,
|
|
75
|
+
},
|
|
76
|
+
verifyNFTParams: {
|
|
77
|
+
claims,
|
|
78
|
+
challenge,
|
|
79
|
+
locale,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @type {Omit<import('@abtnode/client').SpaceGatewayInput, 'protected'>}
|
|
85
|
+
*/
|
|
86
|
+
const spaceGateway = {
|
|
87
|
+
did: data.did,
|
|
88
|
+
name: data.name,
|
|
89
|
+
endpoint: data.endpoint,
|
|
90
|
+
url: didSpaceInfo.didSpacesCoreUrl,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// 两边都要做同样的校验
|
|
94
|
+
await updateSession({ spaceGateway, ...data }, true);
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = { createConnectToDidSpacesRoute };
|
package/lib/util/api.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
const isUrl = require('is-url');
|
|
2
|
+
const Client = require('@ocap/client');
|
|
3
|
+
const { isValid } = require('@arcblock/did');
|
|
4
|
+
const { joinURL } = require('ufo');
|
|
5
|
+
const { api } = require('./api');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @description
|
|
9
|
+
* @param {string} endpoint
|
|
10
|
+
* @return {string}
|
|
11
|
+
*/
|
|
12
|
+
function getDIDSpacesUrlFromDisplayUrl(endpoint) {
|
|
13
|
+
if (!isUrl(endpoint)) {
|
|
14
|
+
throw new Error(`Endpoint(${endpoint}) is not a valid url`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return endpoint.replace(/\/api\/.+/, '');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @description
|
|
22
|
+
* @param {{
|
|
23
|
+
* chainHost: string,
|
|
24
|
+
* assetDid: string,
|
|
25
|
+
* }} { chainHost, assetDid }
|
|
26
|
+
* @return {Promise<{
|
|
27
|
+
* didSpacesCoreUrl: string,
|
|
28
|
+
* assetDid: string
|
|
29
|
+
* }>}
|
|
30
|
+
*/
|
|
31
|
+
async function getDidSpaceInfoByAsset({ chainHost, assetDid }) {
|
|
32
|
+
if (!isValid(assetDid)) {
|
|
33
|
+
throw new Error(`Invalid asset did(${assetDid})`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const client = new Client(chainHost);
|
|
37
|
+
/** @type {{ state: import('@ocap/client').AssetState }} */
|
|
38
|
+
const { state } = await client.getAssetState({ address: assetDid });
|
|
39
|
+
|
|
40
|
+
const didSpacesCoreUrl = getDIDSpacesUrlFromDisplayUrl(state.display.content);
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
didSpacesCoreUrl,
|
|
44
|
+
assetDid,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* @description
|
|
49
|
+
* @param {{ vcClaim: any }} { vcClaim }
|
|
50
|
+
* @return {{
|
|
51
|
+
* didSpacesCoreUrl: string,
|
|
52
|
+
* spaceDid: string,
|
|
53
|
+
* }}
|
|
54
|
+
*/
|
|
55
|
+
async function getDidSpaceInfoByVC({ vcClaim }) {
|
|
56
|
+
const vcData = JSON.parse(JSON.parse(vcClaim.presentation).verifiableCredential[0]);
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @type {{
|
|
60
|
+
* appAuth: {
|
|
61
|
+
* appUrl?: string,
|
|
62
|
+
* spaceDid: string,
|
|
63
|
+
* endpoint?: string,
|
|
64
|
+
* }
|
|
65
|
+
* }}
|
|
66
|
+
* */
|
|
67
|
+
const { appAuth } = vcData.credentialSubject;
|
|
68
|
+
const spacesAnyUrl = appAuth.appUrl || appAuth.endpoint;
|
|
69
|
+
|
|
70
|
+
if (!spacesAnyUrl) {
|
|
71
|
+
throw new Error('Unable to find any valid space paths');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const didSpacesCoreUrl = await getDidSpacesCoreUrl(spacesAnyUrl);
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
didSpacesCoreUrl,
|
|
78
|
+
spaceDid: appAuth.spaceDid,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @description
|
|
84
|
+
* @param {string} spacesAnyUrl
|
|
85
|
+
* @param {{ timeout: number }} [options={ timeout: 5000 }]
|
|
86
|
+
* @return {Promise<string>}
|
|
87
|
+
*/
|
|
88
|
+
async function getDidSpacesCoreUrl(spacesAnyUrl, options = { timeout: 5000 }) {
|
|
89
|
+
const u = new URL(spacesAnyUrl);
|
|
90
|
+
|
|
91
|
+
/** @type {{ data: import('@blocklet/sdk').WindowBlocklet }} */
|
|
92
|
+
const { data: blockletMeta } = await api.get(joinURL(u.origin, '/__blocklet__.js?type=json'), {
|
|
93
|
+
timeout: options.timeout,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
/** @type {string} */
|
|
97
|
+
const mountPoint = blockletMeta.componentMountPoints.find(
|
|
98
|
+
(x) => x.did === 'z8iZnaYxnkMD5AKRjTKiCb8pQr1ut8UantAcf'
|
|
99
|
+
)?.mountPoint;
|
|
100
|
+
|
|
101
|
+
if (!mountPoint) {
|
|
102
|
+
throw new Error(`MountPoint(${mountPoint}) not found`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return joinURL(u.origin, mountPoint);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @typedef {{
|
|
110
|
+
* didSpacesCoreUrl: string,
|
|
111
|
+
* spaceDid?: string,
|
|
112
|
+
* assetDid?: string, // spaceDid, assetDid 必定会存在一个
|
|
113
|
+
* }} DidSpaceInfo
|
|
114
|
+
* @typedef {{
|
|
115
|
+
* appDid: string,
|
|
116
|
+
* appName: string,
|
|
117
|
+
* appDescription: string,
|
|
118
|
+
* scopes: string,
|
|
119
|
+
* appUrl: string,
|
|
120
|
+
* referer: string,
|
|
121
|
+
* }} DidSpaceExtraParams
|
|
122
|
+
* @typedef {{
|
|
123
|
+
* claims: any[],
|
|
124
|
+
* challenge: any,
|
|
125
|
+
* locale: 'en' | 'zh',
|
|
126
|
+
* }} DidSpaceVerifyNFTParams
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @description
|
|
131
|
+
* @param {{ claims: any[] }} { claims }
|
|
132
|
+
* @return {Promise<DidSpaceInfo>}
|
|
133
|
+
*/
|
|
134
|
+
function getDidSpacesInfoByClaims({ claims }) {
|
|
135
|
+
const assetOrVcClaim = claims.find(
|
|
136
|
+
(x) => x?.meta?.purpose === 'DidSpace' && ['asset', 'verifiableCredential'].includes(x.type)
|
|
137
|
+
);
|
|
138
|
+
if (!assetOrVcClaim) {
|
|
139
|
+
// 说明 DID Spaces 对于应用来说不是必要的
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const isAssetClaim = assetOrVcClaim.type === 'asset';
|
|
144
|
+
if (isAssetClaim) {
|
|
145
|
+
return getDidSpaceInfoByAsset({
|
|
146
|
+
chainHost: getChainHostByAssetChainId(assetOrVcClaim.assetChainId),
|
|
147
|
+
assetDid: assetOrVcClaim.asset,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return getDidSpaceInfoByVC({ vcClaim: assetOrVcClaim });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @description
|
|
155
|
+
* @param {DidSpaceInfo} didSpaceInfo
|
|
156
|
+
* @param {{
|
|
157
|
+
* extrasParams: DidSpaceExtraParams,
|
|
158
|
+
* verifyNFTParams: DidSpaceVerifyNFTParams
|
|
159
|
+
* }} { extrasParams, verifyNFTParams }
|
|
160
|
+
* @return {*}
|
|
161
|
+
*/
|
|
162
|
+
async function silentAuthorizationInConnect(didSpaceInfo, data) {
|
|
163
|
+
const silentAuthorizationUrl = joinURL(didSpaceInfo.didSpacesCoreUrl, '/api/space/silent-authorization');
|
|
164
|
+
|
|
165
|
+
const res = await api.put(silentAuthorizationUrl, data, {
|
|
166
|
+
params: {
|
|
167
|
+
spaceDid: didSpaceInfo.spaceDid,
|
|
168
|
+
assetDid: didSpaceInfo.assetDid,
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
return res;
|
|
173
|
+
}
|
|
174
|
+
const CHAIN_HOST_MAP = {
|
|
175
|
+
beta: 'https://beta.abtnetwork.io/api/',
|
|
176
|
+
'xenon-2020-01-15': 'https://abtnetwork.io/api/',
|
|
177
|
+
};
|
|
178
|
+
function getChainHostByAssetChainId(assetChainId) {
|
|
179
|
+
if (assetChainId in CHAIN_HOST_MAP) {
|
|
180
|
+
return CHAIN_HOST_MAP[assetChainId];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
throw new Error(`Unknown asset chain id(${assetChainId})`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
module.exports = {
|
|
187
|
+
getDIDSpacesUrlFromDisplayUrl,
|
|
188
|
+
getDidSpacesInfoByClaims,
|
|
189
|
+
silentAuthorizationInConnect,
|
|
190
|
+
};
|
package/locales/en.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
module.exports = {
|
|
3
3
|
description: 'Connect your DID Wallet',
|
|
4
4
|
requestProfile: 'Please provide following information to continue',
|
|
5
|
+
requestDidSpace: 'Please authorize DID Space to continue',
|
|
5
6
|
requestNFT: 'Please present NFT to exchange for passport',
|
|
6
7
|
requestCredential: 'Please provide credential',
|
|
7
8
|
requestPassport: 'Please provide passport',
|
package/locales/zh.js
CHANGED
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.23-beta-
|
|
6
|
+
"version": "1.16.23-beta-06c3a221",
|
|
7
7
|
"description": "Simple lib to manage auth in ABT Node",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -20,29 +20,34 @@
|
|
|
20
20
|
"author": "linchen <linchen1987@foxmail.com> (http://github.com/linchen1987)",
|
|
21
21
|
"license": "Apache-2.0",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@abtnode/constant": "1.16.23-beta-
|
|
24
|
-
"@abtnode/logger": "1.16.23-beta-
|
|
25
|
-
"@abtnode/util": "1.16.23-beta-
|
|
23
|
+
"@abtnode/constant": "1.16.23-beta-06c3a221",
|
|
24
|
+
"@abtnode/logger": "1.16.23-beta-06c3a221",
|
|
25
|
+
"@abtnode/util": "1.16.23-beta-06c3a221",
|
|
26
26
|
"@arcblock/did": "1.18.108",
|
|
27
|
-
"@arcblock/nft-display": "2.9.
|
|
27
|
+
"@arcblock/nft-display": "2.9.17",
|
|
28
|
+
"@arcblock/validator": "^1.18.108",
|
|
28
29
|
"@arcblock/vc": "1.18.108",
|
|
29
|
-
"@blocklet/constant": "1.16.23-beta-
|
|
30
|
-
"@blocklet/meta": "1.16.23-beta-
|
|
30
|
+
"@blocklet/constant": "1.16.23-beta-06c3a221",
|
|
31
|
+
"@blocklet/meta": "1.16.23-beta-06c3a221",
|
|
32
|
+
"@ocap/client": "^1.18.108",
|
|
31
33
|
"@ocap/mcrypto": "1.18.108",
|
|
32
34
|
"@ocap/util": "1.18.108",
|
|
33
35
|
"@ocap/wallet": "1.18.108",
|
|
36
|
+
"axios": "^0.27.2",
|
|
34
37
|
"flat": "^5.0.2",
|
|
35
38
|
"fs-extra": "^11.2.0",
|
|
39
|
+
"is-url": "^1.2.4",
|
|
36
40
|
"joi": "17.11.0",
|
|
37
41
|
"jsonwebtoken": "^9.0.0",
|
|
38
42
|
"lodash": "^4.17.21",
|
|
39
43
|
"p-retry": "4.6.1",
|
|
40
44
|
"semver": "^7.3.8",
|
|
41
45
|
"transliteration": "^2.3.5",
|
|
46
|
+
"ufo": "^1.3.2",
|
|
42
47
|
"url-join": "^4.0.1"
|
|
43
48
|
},
|
|
44
49
|
"devDependencies": {
|
|
45
50
|
"jest": "^29.7.0"
|
|
46
51
|
},
|
|
47
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "10d2351eb9a0a222781d803798e15390622e421b"
|
|
48
53
|
}
|