@abtnode/blocklet-services 1.16.17-beta-6f0c7674 → 1.16.17-beta-703fb879
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/api/libs/open-graph/emoji.js +80 -0
- package/api/libs/open-graph/index.js +14 -1
- package/api/services/auth/index.js +17 -8
- package/api/services/image/index.js +5 -0
- package/api/util/index.js +8 -1
- package/build/asset-manifest.json +5 -5
- package/build/index.html +1 -1
- package/build/service-worker.js +1 -1
- package/build/static/js/4716.1ecc2bb6.chunk.js +2 -0
- package/build/static/js/main.3cf7fedb.js +3 -0
- package/package.json +18 -18
- package/build/static/js/4716.4a231f60.chunk.js +0 -2
- package/build/static/js/main.9c5b4fb1.js +0 -3
- /package/build/static/js/{main.9c5b4fb1.js.LICENSE.txt → main.3cf7fedb.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* eslint-disable consistent-return */
|
|
2
|
+
/* eslint-disable no-bitwise */
|
|
3
|
+
const fetch = require('node-fetch').default;
|
|
4
|
+
|
|
5
|
+
const U200D = String.fromCharCode(8205); // zero-width joiner
|
|
6
|
+
const UFE0Fg = /\uFE0F/g; // variation selector regex
|
|
7
|
+
|
|
8
|
+
const getIconCode = (char) => toCodePoint(char.indexOf(U200D) < 0 ? char.replace(UFE0Fg, '') : char);
|
|
9
|
+
|
|
10
|
+
const toCodePoint = (unicodeSurrogates) => {
|
|
11
|
+
const r = [];
|
|
12
|
+
let c = 0;
|
|
13
|
+
let p = 0;
|
|
14
|
+
let i = 0;
|
|
15
|
+
while (i < unicodeSurrogates.length) {
|
|
16
|
+
c = unicodeSurrogates.charCodeAt(i++);
|
|
17
|
+
if (p) {
|
|
18
|
+
r.push((65536 + ((p - 55296) << 10) + (c - 56320)).toString(16));
|
|
19
|
+
p = 0;
|
|
20
|
+
} else if (c >= 55296 && c <= 56319) {
|
|
21
|
+
p = c;
|
|
22
|
+
} else {
|
|
23
|
+
r.push(c.toString(16));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return r.join('-');
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const apis = {
|
|
30
|
+
twemoji: (code) => `https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/${code.toLowerCase()}.svg`,
|
|
31
|
+
openmoji: 'https://cdn.jsdelivr.net/npm/@svgmoji/openmoji@2.0.0/svg/',
|
|
32
|
+
blobmoji: 'https://cdn.jsdelivr.net/npm/@svgmoji/blob@2.0.0/svg/',
|
|
33
|
+
noto: 'https://cdn.jsdelivr.net/gh/svgmoji/svgmoji/packages/svgmoji__noto/svg/',
|
|
34
|
+
fluent: (code) => `https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${code.toLowerCase()}_color.svg`,
|
|
35
|
+
fluentFlat: (code) =>
|
|
36
|
+
`https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${code.toLowerCase()}_flat.svg`,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// https://github.com/svgmoji/svgmoji
|
|
40
|
+
const loadEmoji = (code, type) => {
|
|
41
|
+
const api = apis[type] ?? apis.twemoji;
|
|
42
|
+
if (typeof api === 'function') {
|
|
43
|
+
return fetch(api(code));
|
|
44
|
+
}
|
|
45
|
+
return fetch(`${api}${code.toUpperCase()}.svg`);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const cache = new Map();
|
|
49
|
+
const loadDynamicAsset = (emojiType = 'twemoji') => {
|
|
50
|
+
const fn = async (languageCode, text) => {
|
|
51
|
+
if (languageCode === 'emoji') {
|
|
52
|
+
const code = getIconCode(text);
|
|
53
|
+
try {
|
|
54
|
+
const emoji = await loadEmoji(code, emojiType);
|
|
55
|
+
return `data:image/svg+xml;base64,${btoa(await emoji.text())}`;
|
|
56
|
+
} catch (err) {
|
|
57
|
+
console.error(`Failed to fetch emoji: ${text}:${code}`, err);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return async (...args) => {
|
|
63
|
+
const key = JSON.stringify({ ...args, emojiType });
|
|
64
|
+
const cached = cache.get(key);
|
|
65
|
+
if (cached) {
|
|
66
|
+
return cached;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const font = await fn(...args);
|
|
70
|
+
cache.set(key, font);
|
|
71
|
+
return font;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
module.exports = {
|
|
76
|
+
apis,
|
|
77
|
+
getIconCode,
|
|
78
|
+
loadEmoji,
|
|
79
|
+
loadDynamicAsset,
|
|
80
|
+
};
|
|
@@ -15,6 +15,7 @@ const logger = require('@abtnode/logger')('@abtnode/blocklet-services/og');
|
|
|
15
15
|
|
|
16
16
|
const { getTemplate, getLogoSvg } = require('./template');
|
|
17
17
|
const { getCacheFilePath } = require('../image');
|
|
18
|
+
const emoji = require('./emoji');
|
|
18
19
|
|
|
19
20
|
const TEMPLATES = ['default', 'section', 'cover'];
|
|
20
21
|
|
|
@@ -64,6 +65,12 @@ const schema = Joi.object({
|
|
|
64
65
|
logo: Joi.string()
|
|
65
66
|
.uri({ scheme: ['https'] })
|
|
66
67
|
.optional(),
|
|
68
|
+
|
|
69
|
+
// custom emoji
|
|
70
|
+
emoji: Joi.string()
|
|
71
|
+
.valid(...Object.keys(emoji.apis))
|
|
72
|
+
.optional()
|
|
73
|
+
.default('twemoji'),
|
|
67
74
|
}).options({ stripUnknown: true, allowUnknown: true, noDefaults: false });
|
|
68
75
|
|
|
69
76
|
const generateTasks = {};
|
|
@@ -133,9 +140,14 @@ const convertExternalImage = (url, dest) => {
|
|
|
133
140
|
headers: { Accept: 'image/*' },
|
|
134
141
|
},
|
|
135
142
|
(res) => {
|
|
143
|
+
if (res.statusCode && res.statusCode >= 400) {
|
|
144
|
+
reject(new Error(`unexpected external image status: ${res.statusCode}`));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
136
148
|
const [type] = (res.headers['content-type'] || '').split('/');
|
|
137
149
|
if (type !== 'image') {
|
|
138
|
-
reject(new Error(
|
|
150
|
+
reject(new Error(`unexpected external image format: ${type}`));
|
|
139
151
|
return;
|
|
140
152
|
}
|
|
141
153
|
|
|
@@ -226,6 +238,7 @@ const generateOgImage = async (params, tmpDir) => {
|
|
|
226
238
|
style: 'normal',
|
|
227
239
|
},
|
|
228
240
|
],
|
|
241
|
+
loadAdditionalAsset: emoji.loadDynamicAsset(params.emoji),
|
|
229
242
|
});
|
|
230
243
|
|
|
231
244
|
if (params.format === 'svg') {
|
|
@@ -88,6 +88,8 @@ const init = ({ node, options }) => {
|
|
|
88
88
|
* {boolean} res.blocked
|
|
89
89
|
* {boolean} res.authenticated
|
|
90
90
|
* {boolean} res.authorized
|
|
91
|
+
* {boolean} res.ignored
|
|
92
|
+
* {string} res.payable
|
|
91
93
|
*/
|
|
92
94
|
const checkAuth = async ({ req } = {}) => {
|
|
93
95
|
const config = (await req.getServiceConfig(NODE_SERVICES.AUTH)) || {};
|
|
@@ -100,32 +102,39 @@ const init = ({ node, options }) => {
|
|
|
100
102
|
|
|
101
103
|
const shouldIgnore = shouldIgnoreUrl(req.url, ignoreUrls);
|
|
102
104
|
if (shouldIgnore) {
|
|
103
|
-
return {};
|
|
105
|
+
return { ignored: true };
|
|
104
106
|
}
|
|
105
107
|
|
|
108
|
+
const teamDid = req.getBlockletDid();
|
|
109
|
+
|
|
106
110
|
if (!config.whoCanAccess || config.whoCanAccess === WHO_CAN_ACCESS.ALL) {
|
|
107
111
|
if (config.blockUnauthenticated && !req.user) {
|
|
108
112
|
return { blocked: true, authenticated: false };
|
|
109
113
|
}
|
|
110
114
|
} else if (!req.user) {
|
|
111
|
-
|
|
115
|
+
const rbac = await node.getRBAC(teamDid);
|
|
116
|
+
const allRoles = await rbac.getRoles(teamDid);
|
|
117
|
+
const payableRole = allRoles.find((x) => x.extra?.acquire?.pay);
|
|
118
|
+
return { blocked: true, authenticated: false, payable: payableRole?.extra?.acquire?.pay };
|
|
112
119
|
} else if (config.whoCanAccess === WHO_CAN_ACCESS.OWNER && req.user.role !== ROLES.OWNER) {
|
|
113
120
|
return { blocked: true, authenticated: true, authorized: false };
|
|
114
121
|
} else if (config.whoCanAccess.startsWith(WHO_CAN_ACCESS_PREFIX_ROLES)) {
|
|
115
122
|
const roles = getRolesFromAuthConfig(config);
|
|
116
123
|
if (!roles.includes(req.user.role)) {
|
|
117
|
-
|
|
124
|
+
const rbac = await node.getRBAC(teamDid);
|
|
125
|
+
const allRoles = await rbac.getRoles(teamDid);
|
|
126
|
+
const payableRole = allRoles.find((x) => roles.includes(x.name) && x.extra?.acquire?.pay);
|
|
127
|
+
return { blocked: true, authenticated: true, authorized: false, payable: payableRole?.extra?.acquire?.pay };
|
|
118
128
|
}
|
|
119
129
|
}
|
|
120
130
|
|
|
121
131
|
if (!config.blockUnauthorized) {
|
|
122
|
-
return {};
|
|
132
|
+
return { ignored: true };
|
|
123
133
|
}
|
|
124
134
|
|
|
125
135
|
const rule = await req.getRoutingRule();
|
|
126
136
|
if (rule.to && rule.to.interfaceName) {
|
|
127
137
|
const permissionName = genPermissionName(rule.to.interfaceName);
|
|
128
|
-
const teamDid = req.getBlockletDid();
|
|
129
138
|
const rbac = await node.getRBAC(teamDid);
|
|
130
139
|
|
|
131
140
|
if (await rbac.can(req.user.role, ...permissionName.split('_'))) {
|
|
@@ -245,12 +254,12 @@ const init = ({ node, options }) => {
|
|
|
245
254
|
};
|
|
246
255
|
|
|
247
256
|
middlewares.checkAuth = async (req, res, next) => {
|
|
248
|
-
const { blocked, authenticated, authorized } = await checkAuth({ req });
|
|
257
|
+
const { blocked, authenticated, authorized, payable } = await checkAuth({ req });
|
|
249
258
|
|
|
250
259
|
if (blocked) {
|
|
251
260
|
if (!authenticated) {
|
|
252
261
|
if (req.accepts(['html', 'json']) === 'html') {
|
|
253
|
-
res.redirect(getRedirectUrl({ req, pagePath: '/login' }));
|
|
262
|
+
res.redirect(getRedirectUrl({ req, pagePath: '/login', params: { payable } }));
|
|
254
263
|
} else {
|
|
255
264
|
// Security principles: user should not known the reason
|
|
256
265
|
res.status(404).json({ code: 404, error: REASON_404 });
|
|
@@ -260,7 +269,7 @@ const init = ({ node, options }) => {
|
|
|
260
269
|
|
|
261
270
|
if (!authorized) {
|
|
262
271
|
if (req.accepts(['html', 'json']) === 'html') {
|
|
263
|
-
res.redirect(getRedirectUrl({ req, pagePath: '/login' }));
|
|
272
|
+
res.redirect(getRedirectUrl({ req, pagePath: '/login', params: { authenticated: 1, payable } }));
|
|
264
273
|
} else {
|
|
265
274
|
// Security principles: user should not known the reason
|
|
266
275
|
res.status(404).json({ code: 404, error: REASON_404 });
|
|
@@ -28,6 +28,11 @@ const createImageService = ({ node }) => {
|
|
|
28
28
|
status: res.statusCode,
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
+
if (res.statusCode && res.statusCode >= 400) {
|
|
32
|
+
reject(new Error(`unexpected upstream response status: ${res.statusCode}`));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
31
36
|
const [type, extension] = (res.headers['content-type'] || '').split('/');
|
|
32
37
|
if (type !== 'image') {
|
|
33
38
|
reject(new Error(`unexpected response type from upstream: ${type}, expected image`));
|
package/api/util/index.js
CHANGED
|
@@ -81,7 +81,7 @@ const ensureProxyUrl = async (req) => {
|
|
|
81
81
|
return { target };
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
-
const getRedirectUrl = ({ req, pagePath }) => {
|
|
84
|
+
const getRedirectUrl = ({ req, pagePath, params = {} }) => {
|
|
85
85
|
const groupPrefix = getGroupPrefix(req);
|
|
86
86
|
const componentPrefix = getComponentPrefix(req);
|
|
87
87
|
const redirectPrefix = groupPrefix === componentPrefix ? groupPrefix : componentPrefix;
|
|
@@ -136,6 +136,13 @@ const getRedirectUrl = ({ req, pagePath }) => {
|
|
|
136
136
|
url.searchParams.set('chainHost', chainHost);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
Object.keys(params).forEach((key) => {
|
|
140
|
+
if (params[key] === undefined) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
url.searchParams.set(key, params[key]);
|
|
144
|
+
});
|
|
145
|
+
|
|
139
146
|
return `${url.pathname}${url.search}`;
|
|
140
147
|
};
|
|
141
148
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": {
|
|
3
3
|
"main.css": "/.well-known/service/static/static/css/main.7ea79dc8.css",
|
|
4
|
-
"main.js": "/.well-known/service/static/static/js/main.
|
|
5
|
-
"static/js/4716.
|
|
4
|
+
"main.js": "/.well-known/service/static/static/js/main.3cf7fedb.js",
|
|
5
|
+
"static/js/4716.1ecc2bb6.chunk.js": "/.well-known/service/static/static/js/4716.1ecc2bb6.chunk.js",
|
|
6
6
|
"static/js/4076.e73cb63a.chunk.js": "/.well-known/service/static/static/js/4076.e73cb63a.chunk.js",
|
|
7
7
|
"static/js/6658.0a27e04e.chunk.js": "/.well-known/service/static/static/js/6658.0a27e04e.chunk.js",
|
|
8
8
|
"static/js/3025.e2b1dac4.chunk.js": "/.well-known/service/static/static/js/3025.e2b1dac4.chunk.js",
|
|
@@ -107,8 +107,8 @@
|
|
|
107
107
|
"index.html": "/.well-known/service/static/index.html",
|
|
108
108
|
"static/media/space-connected.svg": "/.well-known/service/static/static/media/space-connected.9a4e18fd2bc7d065191b0d241a131c28.svg",
|
|
109
109
|
"main.7ea79dc8.css.map": "/.well-known/service/static/static/css/main.7ea79dc8.css.map",
|
|
110
|
-
"main.
|
|
111
|
-
"4716.
|
|
110
|
+
"main.3cf7fedb.js.map": "/.well-known/service/static/static/js/main.3cf7fedb.js.map",
|
|
111
|
+
"4716.1ecc2bb6.chunk.js.map": "/.well-known/service/static/static/js/4716.1ecc2bb6.chunk.js.map",
|
|
112
112
|
"4076.e73cb63a.chunk.js.map": "/.well-known/service/static/static/js/4076.e73cb63a.chunk.js.map",
|
|
113
113
|
"6658.0a27e04e.chunk.js.map": "/.well-known/service/static/static/js/6658.0a27e04e.chunk.js.map",
|
|
114
114
|
"3025.e2b1dac4.chunk.js.map": "/.well-known/service/static/static/js/3025.e2b1dac4.chunk.js.map",
|
|
@@ -192,6 +192,6 @@
|
|
|
192
192
|
},
|
|
193
193
|
"entrypoints": [
|
|
194
194
|
"static/css/main.7ea79dc8.css",
|
|
195
|
-
"static/js/main.
|
|
195
|
+
"static/js/main.3cf7fedb.js"
|
|
196
196
|
]
|
|
197
197
|
}
|
package/build/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico?imageFilter=resize&w=32"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#000000"/><title>Blocklet Service</title><link rel="manifest" href="/.well-known/service/manifest.json"/><script src="/.well-known/service/api/env"></script><script src="/__blocklet__.js"></script><script defer="defer" src="/.well-known/service/static/static/js/main.
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico?imageFilter=resize&w=32"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#000000"/><title>Blocklet Service</title><link rel="manifest" href="/.well-known/service/manifest.json"/><script src="/.well-known/service/api/env"></script><script src="/__blocklet__.js"></script><script defer="defer" src="/.well-known/service/static/static/js/main.3cf7fedb.js"></script><link href="/.well-known/service/static/static/css/main.7ea79dc8.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|