@abtnode/webapp 1.8.63-beta-a36b5e1a → 1.8.63
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/blocklet.yml +6 -3
- package/build/asset-manifest.json +93 -0
- package/build/favicon.ico +0 -0
- package/build/icons/css/all.css +5919 -0
- package/build/icons/css/brands.css +14 -0
- package/build/icons/css/brands.min.css +12 -0
- package/build/icons/css/fontawesome.css +7816 -0
- package/build/icons/css/fontawesome.min.css +5864 -0
- package/build/icons/css/light.css +15 -0
- package/build/icons/css/light.min.css +13 -0
- package/build/icons/webfonts/fa-brands-400.eot +0 -0
- package/build/icons/webfonts/fa-brands-400.svg +1256 -0
- package/build/icons/webfonts/fa-brands-400.ttf +0 -0
- package/build/icons/webfonts/fa-brands-400.woff +0 -0
- package/build/icons/webfonts/fa-brands-400.woff2 +0 -0
- package/build/icons/webfonts/fa-light-300.eot +0 -0
- package/build/icons/webfonts/fa-light-300.svg +4445 -0
- package/build/icons/webfonts/fa-light-300.ttf +0 -0
- package/build/icons/webfonts/fa-light-300.woff +0 -0
- package/build/icons/webfonts/fa-light-300.woff2 +0 -0
- package/build/images/blocklet.png +0 -0
- package/build/images/blocklets-00c2c4.png +0 -0
- package/build/images/blocklets-222222.png +0 -0
- package/build/images/celebrate.png +0 -0
- package/build/images/community.svg +6 -0
- package/build/images/console-00c2c4.png +0 -0
- package/build/images/console-222222.png +0 -0
- package/build/images/dashboard-00c2c4.png +0 -0
- package/build/images/dashboard-222222.png +0 -0
- package/build/images/doc-222222.png +0 -0
- package/build/images/hourglass-222222.png +0 -0
- package/build/images/https-certificate-icon.png +0 -0
- package/build/images/labs-00c2c4.png +0 -0
- package/build/images/labs-222222.png +0 -0
- package/build/images/log-00c2c4.png +0 -0
- package/build/images/log-222222.png +0 -0
- package/build/images/member-222222.png +0 -0
- package/build/images/node.png +0 -0
- package/build/images/official.svg +1 -0
- package/build/images/private-222222.png +0 -0
- package/build/images/public-222222.png +0 -0
- package/build/images/public_avatar.png +0 -0
- package/build/images/router-00c2c4.png +0 -0
- package/build/images/router-222222.png +0 -0
- package/build/images/settings-00c2c4.png +0 -0
- package/build/images/settings-222222.png +0 -0
- package/build/images/slack.png +0 -0
- package/build/images/storage-222222.png +0 -0
- package/build/images/store-00c2c4.png +0 -0
- package/build/images/store-222222.png +0 -0
- package/build/images/team-00c2c4.png +0 -0
- package/build/images/team-222222.png +0 -0
- package/build/images/time-222222.png +0 -0
- package/build/images/upgrade.png +0 -0
- package/build/index.html +1 -0
- package/build/manifest.json +15 -0
- package/build/static/css/4381.5ade355d.chunk.css +1 -0
- package/build/static/css/4691.56c2f951.chunk.css +1 -0
- package/build/static/css/5245.5d6e9197.chunk.css +1 -0
- package/build/static/css/8213.f696fdbf.chunk.css +1 -0
- package/build/static/css/9779.f696fdbf.chunk.css +1 -0
- package/build/static/css/main.c9e90622.css +1 -0
- package/build/static/images/logo.png +0 -0
- package/build/static/js/1057.8280393f.chunk.js +1 -0
- package/build/static/js/1361.85e46159.chunk.js +1 -0
- package/build/static/js/1366.2f174c9b.chunk.js +2 -0
- package/build/static/js/1366.2f174c9b.chunk.js.LICENSE.txt +37 -0
- package/build/static/js/154.94956824.chunk.js +1 -0
- package/build/static/js/1826.07c285de.chunk.js +1 -0
- package/build/static/js/2129.120e36ae.chunk.js +1 -0
- package/build/static/js/2308.b65bc299.chunk.js +1 -0
- package/build/static/js/2564.eef717f3.chunk.js +1 -0
- package/build/static/js/2657.d3c62d57.chunk.js +1 -0
- package/build/static/js/2720.26eb1788.chunk.js +1 -0
- package/build/static/js/2828.4f318970.chunk.js +1 -0
- package/build/static/js/2878.5626558d.chunk.js +1 -0
- package/build/static/js/3111.84e02823.chunk.js +1 -0
- package/build/static/js/3476.c0b3411b.chunk.js +1 -0
- package/build/static/js/3633.8c7cf02d.chunk.js +1 -0
- package/build/static/js/3732.f5d8b39b.chunk.js +1 -0
- package/build/static/js/3776.1490b0f7.chunk.js +1 -0
- package/build/static/js/3829.b6d6cf45.chunk.js +1 -0
- package/build/static/js/4074.19db40ec.chunk.js +1 -0
- package/build/static/js/4104.b47ae0e1.chunk.js +1 -0
- package/build/static/js/4241.83e4f741.chunk.js +1 -0
- package/build/static/js/4274.e18ffddd.chunk.js +1 -0
- package/build/static/js/4349.7c2f6507.chunk.js +1 -0
- package/build/static/js/4381.631ef61d.chunk.js +2 -0
- package/build/static/js/4381.631ef61d.chunk.js.LICENSE.txt +22 -0
- package/build/static/js/4557.3907550e.chunk.js +1 -0
- package/build/static/js/4590.5a14012c.chunk.js +1 -0
- package/build/static/js/4633.9f946ed5.chunk.js +1 -0
- package/build/static/js/4691.550fcb40.chunk.js +2 -0
- package/build/static/js/4691.550fcb40.chunk.js.LICENSE.txt +8 -0
- package/build/static/js/5074.9ea094a9.chunk.js +1 -0
- package/build/static/js/5082.18d16cb9.chunk.js +1 -0
- package/build/static/js/519.adae6e43.chunk.js +1 -0
- package/build/static/js/556.381dcbd8.chunk.js +1 -0
- package/build/static/js/5984.25af6288.chunk.js +1 -0
- package/build/static/js/6158.8a43296d.chunk.js +1 -0
- package/build/static/js/6189.d6d74d14.chunk.js +1 -0
- package/build/static/js/6239.5a873a03.chunk.js +2 -0
- package/build/static/js/6239.5a873a03.chunk.js.LICENSE.txt +14 -0
- package/build/static/js/629.1a7f2553.chunk.js +1 -0
- package/build/static/js/6413.ab4a8e01.chunk.js +1 -0
- package/build/static/js/6602.c417a217.chunk.js +1 -0
- package/build/static/js/6780.64314507.chunk.js +1 -0
- package/build/static/js/6830.88b993a0.chunk.js +1 -0
- package/build/static/js/6866.2131ea60.chunk.js +2 -0
- package/build/static/js/6866.2131ea60.chunk.js.LICENSE.txt +8 -0
- package/build/static/js/6898.6fe0c32d.chunk.js +2 -0
- package/build/static/js/6898.6fe0c32d.chunk.js.LICENSE.txt +5 -0
- package/build/static/js/7016.835958ef.chunk.js +1 -0
- package/build/static/js/7298.a7286c09.chunk.js +1 -0
- package/build/static/js/7327.56a5e016.chunk.js +1 -0
- package/build/static/js/744.8b656dd2.chunk.js +1 -0
- package/build/static/js/7652.722b9180.chunk.js +1 -0
- package/build/static/js/8034.c4dcdeff.chunk.js +1 -0
- package/build/static/js/8058.0b2d4727.chunk.js +1 -0
- package/build/static/js/8213.09f25083.chunk.js +1 -0
- package/build/static/js/8235.add24931.chunk.js +1 -0
- package/build/static/js/8249.63c55b3a.chunk.js +1 -0
- package/build/static/js/8262.869cc799.chunk.js +1 -0
- package/build/static/js/8352.b57b0e44.chunk.js +1 -0
- package/build/static/js/8464.b4b82828.chunk.js +1 -0
- package/build/static/js/8606.66db67e2.chunk.js +1 -0
- package/build/static/js/9038.2908c176.chunk.js +1 -0
- package/build/static/js/9076.c77366bc.chunk.js +1 -0
- package/build/static/js/9301.a65db324.chunk.js +2 -0
- package/build/static/js/9301.a65db324.chunk.js.LICENSE.txt +8 -0
- package/build/static/js/9575.36f3de5b.chunk.js +2 -0
- package/build/static/js/9575.36f3de5b.chunk.js.LICENSE.txt +194 -0
- package/build/static/js/9779.bbf0dd81.chunk.js +1 -0
- package/build/static/js/main.cb5d8d67.js +2 -0
- package/build/static/js/main.cb5d8d67.js.LICENSE.txt +159 -0
- package/build/static/media/iconify.32b54549e843e448ee9b.cjs +2 -0
- package/build/static/media/iconify.32b54549e843e448ee9b.cjs.LICENSE.txt +13 -0
- package/build/static/media/lato-all-400-normal.3dc1eff492ab1f598560.woff +0 -0
- package/build/static/media/lato-all-700-normal.1e7707c9ec98d9b97e7f.woff +0 -0
- package/build/static/media/lato-latin-400-normal.be36596da218e1eec01c.woff2 +0 -0
- package/build/static/media/lato-latin-700-normal.8f28e0e1fdb195149f1c.woff2 +0 -0
- package/build/static/media/lato-latin-ext-400-normal.361f3dbb9db6a5980326.woff2 +0 -0
- package/build/static/media/lato-latin-ext-700-normal.9c8812eaec45956201e1.woff2 +0 -0
- package/build/static/media/logo.60f66bbe1ce9674a4df4e374c9d97fc4.svg +16 -0
- package/build/static/media/ubuntu-mono-all-400-normal.c879328bc62e9c68268f.woff +0 -0
- package/build/static/media/ubuntu-mono-cyrillic-400-normal.c367f416832eb8f1b846.woff2 +0 -0
- package/build/static/media/ubuntu-mono-cyrillic-ext-400-normal.eda1c4946b1f7bf58386.woff2 +0 -0
- package/build/static/media/ubuntu-mono-greek-400-normal.22f3bfc91f79c342bdf4.woff2 +0 -0
- package/build/static/media/ubuntu-mono-greek-ext-400-normal.b3459900ea8a25d1f7c2.woff2 +0 -0
- package/build/static/media/ubuntu-mono-latin-400-normal.18e32d9d743af28f913e.woff2 +0 -0
- package/build/static/media/ubuntu-mono-latin-ext-400-normal.b56e2315611d10838ad5.woff2 +0 -0
- package/package.json +1 -1
- package/api/gql/config.js +0 -392
- package/api/gql/index.js +0 -102
- package/api/gql/middlewares/create-audit-log.js +0 -3
- package/api/gql/middlewares/get-blocklet-list.js +0 -14
- package/api/gql/middlewares/install-blocklet.js +0 -13
- package/api/gql/middlewares/verify-blocklet.js +0 -21
- package/api/gql/middlewares/verify-team.js +0 -9
- package/api/index.js +0 -249
- package/api/libs/auth.js +0 -78
- package/api/libs/env.js +0 -3
- package/api/libs/login.js +0 -212
- package/api/libs/security.js +0 -90
- package/api/libs/storage.js +0 -69
- package/api/middlewares/mutate-blocklet-permission.js +0 -18
- package/api/routes/auth/accept-server.js +0 -28
- package/api/routes/auth/connect-owner.js +0 -143
- package/api/routes/auth/delegate-transfer-owner-nft.js +0 -86
- package/api/routes/auth/invite.js +0 -93
- package/api/routes/auth/issue-passport.js +0 -61
- package/api/routes/auth/launch-free-blocklet-by-nft.js +0 -9
- package/api/routes/auth/launch-free-blocklet.js +0 -9
- package/api/routes/auth/launch-paid-blocklet-by-nft.js +0 -9
- package/api/routes/auth/launch-paid-blocklet.js +0 -9
- package/api/routes/auth/login.js +0 -63
- package/api/routes/auth/lost-passport-issue.js +0 -5
- package/api/routes/auth/lost-passport-list.js +0 -5
- package/api/routes/auth/switch-passport.js +0 -47
- package/api/routes/auth/switch-profile.js +0 -69
- package/api/routes/auth/util.js +0 -135
- package/api/routes/auth/verify-owner.js +0 -39
- package/api/routes/auth/verify-purchase.js +0 -185
- package/api/routes/blocklet-info.js +0 -246
- package/api/routes/blocklet-preference.js +0 -161
- package/api/routes/blocklet-proxy.js +0 -220
- package/api/routes/did-resolver.js +0 -38
- package/api/routes/dns-resolver.js +0 -73
- package/api/routes/log.js +0 -31
- package/api/routes/passport.js +0 -19
- package/api/routes/session.js +0 -61
- package/api/routes/user.js +0 -38
- package/api/util/find-routing-rule.js +0 -95
- package/api/util/get-configs.js +0 -31
- package/api/util/index.js +0 -5
- package/api/util/navigation.js +0 -84
- package/api/webpack.blocklet.js +0 -43
- package/api/ws/index.js +0 -146
package/api/index.js
DELETED
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const cors = require('cors');
|
|
3
|
-
const compression = require('compression');
|
|
4
|
-
const morgan = require('morgan');
|
|
5
|
-
const express = require('express');
|
|
6
|
-
require('express-async-errors');
|
|
7
|
-
const cookieParser = require('cookie-parser');
|
|
8
|
-
const bodyParser = require('body-parser');
|
|
9
|
-
const bearerToken = require('express-bearer-token');
|
|
10
|
-
const fallback = require('express-history-api-fallback');
|
|
11
|
-
const graphqlUploadExpress = require('graphql-upload/graphqlUploadExpress.js');
|
|
12
|
-
const joinUrl = require('url-join');
|
|
13
|
-
const getRouterAdapter = require('@abtnode/router-adapter');
|
|
14
|
-
const get502Template = require('@abtnode/router-templates/lib/502');
|
|
15
|
-
const getBlockletNotRunningTemplate = require('@abtnode/router-templates/lib/blocklet-not-running');
|
|
16
|
-
const {
|
|
17
|
-
MAX_UPLOAD_FILE_SIZE,
|
|
18
|
-
DEFAULT_ADMIN_PATH,
|
|
19
|
-
USER_AVATAR_URL_PREFIX,
|
|
20
|
-
USER_AVATAR_PATH_PREFIX,
|
|
21
|
-
} = require('@abtnode/constant');
|
|
22
|
-
const http = require('http');
|
|
23
|
-
const { setUserInfoHeaders } = require('@abtnode/auth/lib/auth');
|
|
24
|
-
const log = require('@abtnode/logger');
|
|
25
|
-
const certificateManager = require('@abtnode/certificate-manager');
|
|
26
|
-
const createInvite = require('@abtnode/auth/lib/invitation');
|
|
27
|
-
|
|
28
|
-
const { authWithJwt, authWithAccessKey, authWithVcPresentation } = require('./libs/login');
|
|
29
|
-
const { context, handlers } = require('./libs/auth');
|
|
30
|
-
const { protectGQL } = require('./libs/security');
|
|
31
|
-
const gql = require('./gql');
|
|
32
|
-
const createWebSocketServer = require('./ws');
|
|
33
|
-
|
|
34
|
-
const logger = log('webapp:index');
|
|
35
|
-
|
|
36
|
-
const createLoginAuth = require('./routes/auth/login');
|
|
37
|
-
const createSwitchProfileAuth = require('./routes/auth/switch-profile');
|
|
38
|
-
const createSwitchPassportAuth = require('./routes/auth/switch-passport');
|
|
39
|
-
const createConnectOwnerAuth = require('./routes/auth/connect-owner');
|
|
40
|
-
const createVerifyOwnerAuth = require('./routes/auth/verify-owner');
|
|
41
|
-
const createAcceptServerAuth = require('./routes/auth/accept-server');
|
|
42
|
-
const createVerifyPurchaseAuth = require('./routes/auth/verify-purchase');
|
|
43
|
-
const createIssuePassportAuth = require('./routes/auth/issue-passport');
|
|
44
|
-
const createLostPassportListAuth = require('./routes/auth/lost-passport-list');
|
|
45
|
-
const createLostPassportIssueAuth = require('./routes/auth/lost-passport-issue');
|
|
46
|
-
const createInviteAuth = require('./routes/auth/invite');
|
|
47
|
-
const createLaunchFreeBlockletAuth = require('./routes/auth/launch-free-blocklet');
|
|
48
|
-
const createLaunchPaidBlockletAuth = require('./routes/auth/launch-paid-blocklet');
|
|
49
|
-
const createLaunchFreeBlockletByNFTAuth = require('./routes/auth/launch-free-blocklet-by-nft');
|
|
50
|
-
const createLaunchPaidBlockletByNFTAuth = require('./routes/auth/launch-paid-blocklet-by-nft');
|
|
51
|
-
const createDelegateTransferOwnerNFTAuth = require('./routes/auth/delegate-transfer-owner-nft');
|
|
52
|
-
const sessionRoutes = require('./routes/session');
|
|
53
|
-
const blockletInfoRoutes = require('./routes/blocklet-info');
|
|
54
|
-
const blockletPreferenceRoutes = require('./routes/blocklet-preference');
|
|
55
|
-
const blockletProxyRoutes = require('./routes/blocklet-proxy');
|
|
56
|
-
const passportRoutes = require('./routes/passport');
|
|
57
|
-
const didResolverRoutes = require('./routes/did-resolver');
|
|
58
|
-
const dnsResolverRoutes = require('./routes/dns-resolver');
|
|
59
|
-
const userRoutes = require('./routes/user');
|
|
60
|
-
const logRoutes = require('./routes/log');
|
|
61
|
-
|
|
62
|
-
const MAX_FILE_SIZE = Number(process.env.MAX_UPLOAD_FILE_SIZE || MAX_UPLOAD_FILE_SIZE) * 1024 * 1024;
|
|
63
|
-
|
|
64
|
-
module.exports = function createServer(node) {
|
|
65
|
-
const isTestBuild = process.env.TEST_BUILD && JSON.parse(process.env.TEST_BUILD);
|
|
66
|
-
const isProduction = process.env.NODE_ENV === 'production' || isTestBuild;
|
|
67
|
-
|
|
68
|
-
if (!process.env.ABT_NODE_DATA_DIR) {
|
|
69
|
-
throw new Error('Cannot start application without process.env.ABT_NODE_DATA_DIR');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
context.set('node', node);
|
|
73
|
-
|
|
74
|
-
// Create and config express application
|
|
75
|
-
const app = express();
|
|
76
|
-
|
|
77
|
-
app.set('trust proxy', 'loopback');
|
|
78
|
-
app.disable('x-powered-by');
|
|
79
|
-
|
|
80
|
-
app.use(compression());
|
|
81
|
-
app.use(cookieParser());
|
|
82
|
-
app.use(bodyParser.json({ limit: '4mb' }));
|
|
83
|
-
app.use(bodyParser.urlencoded({ extended: true, limit: '2mb' }));
|
|
84
|
-
app.use(cors());
|
|
85
|
-
|
|
86
|
-
app.get('/error/502', async (req, res) => {
|
|
87
|
-
try {
|
|
88
|
-
res.type('html');
|
|
89
|
-
res.status(502);
|
|
90
|
-
|
|
91
|
-
const blockletDid = req.get('x-did');
|
|
92
|
-
const nodeInfo = await node.getNodeInfo();
|
|
93
|
-
const info = { version: nodeInfo.version, mode: nodeInfo.mode };
|
|
94
|
-
|
|
95
|
-
if (blockletDid) {
|
|
96
|
-
const blocklet = await node.getBlocklet({ did: blockletDid, attachConfig: false });
|
|
97
|
-
if (!blocklet) {
|
|
98
|
-
return res.send(get502Template(info));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return res.send(getBlockletNotRunningTemplate(blocklet, nodeInfo));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return res.send(get502Template(info));
|
|
105
|
-
} catch (error) {
|
|
106
|
-
logger.error('render 502 page failed', { error });
|
|
107
|
-
return res.send('502 Error');
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
if (isProduction) {
|
|
112
|
-
// format:
|
|
113
|
-
// :remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"
|
|
114
|
-
app.use(morgan('combined', { stream: log.getAccessLogStream(process.env.ABT_NODE_LOG_DIR) }));
|
|
115
|
-
} else {
|
|
116
|
-
app.use(
|
|
117
|
-
morgan((tokens, req, res) => {
|
|
118
|
-
const format = [
|
|
119
|
-
tokens.method(req, res),
|
|
120
|
-
tokens.url(req, res),
|
|
121
|
-
tokens.status(req, res),
|
|
122
|
-
tokens.res(req, res, 'content-length'),
|
|
123
|
-
'-',
|
|
124
|
-
tokens['response-time'](req, res),
|
|
125
|
-
'ms',
|
|
126
|
-
].join(' ');
|
|
127
|
-
|
|
128
|
-
return format;
|
|
129
|
-
})
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
app.use(bearerToken());
|
|
134
|
-
app.use(async (req, res, next) => {
|
|
135
|
-
try {
|
|
136
|
-
const { token, headers, body } = req;
|
|
137
|
-
if (token) {
|
|
138
|
-
// request by login user
|
|
139
|
-
const user = await authWithJwt(token, node);
|
|
140
|
-
|
|
141
|
-
// parse user avatar
|
|
142
|
-
if (user && user.avatar && user.avatar.startsWith(USER_AVATAR_URL_PREFIX)) {
|
|
143
|
-
const nodeInfo = await node.getNodeInfo();
|
|
144
|
-
|
|
145
|
-
const adminPath =
|
|
146
|
-
process.env.NODE_ENV === 'development' ? '' : nodeInfo.routing?.adminPath || DEFAULT_ADMIN_PATH;
|
|
147
|
-
|
|
148
|
-
user.avatar = joinUrl(adminPath, USER_AVATAR_PATH_PREFIX, nodeInfo.did, user.avatar.split('/').slice(-1)[0]);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
req.user = user;
|
|
152
|
-
} else if (headers['x-access-key-id'] && headers['x-access-stamp'] && headers['x-access-signature']) {
|
|
153
|
-
// request by accessKey
|
|
154
|
-
const user = await authWithAccessKey({
|
|
155
|
-
keyId: headers['x-access-key-id'],
|
|
156
|
-
stamp: headers['x-access-stamp'],
|
|
157
|
-
signature: headers['x-access-signature'],
|
|
158
|
-
node,
|
|
159
|
-
blockletDid: headers['x-access-blocklet'],
|
|
160
|
-
});
|
|
161
|
-
req.user = user;
|
|
162
|
-
} else if (body['x-authenticate'] && body['x-authenticate'].vcPresentation) {
|
|
163
|
-
req.user = await authWithVcPresentation({
|
|
164
|
-
node,
|
|
165
|
-
vcPresentation: body['x-authenticate'].vcPresentation,
|
|
166
|
-
challenge: body['x-authenticate'].challenge,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
} catch (error) {
|
|
170
|
-
// Do nothing
|
|
171
|
-
}
|
|
172
|
-
next();
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
app.use(async (req, res, next) => {
|
|
176
|
-
setUserInfoHeaders(req);
|
|
177
|
-
next();
|
|
178
|
-
});
|
|
179
|
-
app.use(certificateManager.createRoutes(node.dataDirs.certManagerModule));
|
|
180
|
-
|
|
181
|
-
const router = express.Router();
|
|
182
|
-
|
|
183
|
-
handlers.attach(Object.assign({ app: router }, createLoginAuth(node)));
|
|
184
|
-
handlers.attach(Object.assign({ app: router }, createSwitchProfileAuth(node)));
|
|
185
|
-
handlers.attach(Object.assign({ app: router }, createSwitchPassportAuth(node)));
|
|
186
|
-
handlers.attach(Object.assign({ app: router }, createConnectOwnerAuth(node)));
|
|
187
|
-
handlers.attach(Object.assign({ app: router }, createVerifyOwnerAuth(node)));
|
|
188
|
-
handlers.attach(Object.assign({ app: router }, createAcceptServerAuth(node)));
|
|
189
|
-
handlers.attach(Object.assign({ app: router }, createVerifyPurchaseAuth(node)));
|
|
190
|
-
handlers.attach(Object.assign({ app: router }, createIssuePassportAuth(node)));
|
|
191
|
-
handlers.attach(Object.assign({ app: router }, createLostPassportListAuth(node)));
|
|
192
|
-
handlers.attach(Object.assign({ app: router }, createLostPassportIssueAuth(node)));
|
|
193
|
-
handlers.attach(Object.assign({ app: router }, createInviteAuth(node)));
|
|
194
|
-
handlers.attach(Object.assign({ app: router }, createLaunchFreeBlockletAuth(node)));
|
|
195
|
-
handlers.attach(Object.assign({ app: router }, createLaunchPaidBlockletAuth(node)));
|
|
196
|
-
handlers.attach(Object.assign({ app: router }, createLaunchFreeBlockletByNFTAuth(node)));
|
|
197
|
-
handlers.attach(Object.assign({ app: router }, createLaunchPaidBlockletByNFTAuth(node)));
|
|
198
|
-
handlers.attach(Object.assign({ app: router }, createDelegateTransferOwnerNFTAuth(node)));
|
|
199
|
-
|
|
200
|
-
sessionRoutes.init(router, node);
|
|
201
|
-
blockletInfoRoutes.init(router, node);
|
|
202
|
-
blockletPreferenceRoutes.init(router, node);
|
|
203
|
-
blockletProxyRoutes.init(router, node);
|
|
204
|
-
passportRoutes.init(router, node);
|
|
205
|
-
didResolverRoutes.init(router, node);
|
|
206
|
-
dnsResolverRoutes.init(router, node);
|
|
207
|
-
createInvite.init(app, node, { prefix: '/api' });
|
|
208
|
-
userRoutes.init(router, node);
|
|
209
|
-
logRoutes.init(router, node);
|
|
210
|
-
|
|
211
|
-
// serve abt node gql
|
|
212
|
-
const gqlConfig = gql.genConfig(node);
|
|
213
|
-
app.use(
|
|
214
|
-
'/api/gql',
|
|
215
|
-
graphqlUploadExpress({ maxFileSize: MAX_FILE_SIZE, maxFiles: 10 }),
|
|
216
|
-
protectGQL(node, gqlConfig),
|
|
217
|
-
gql(gqlConfig, !isProduction)
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
if (isProduction) {
|
|
221
|
-
app.use(router);
|
|
222
|
-
|
|
223
|
-
const staticDir = path.resolve(__dirname, './build');
|
|
224
|
-
|
|
225
|
-
app.use(getRouterAdapter());
|
|
226
|
-
app.use(express.static(staticDir, { maxAge: '365d', index: false }));
|
|
227
|
-
app.use(fallback('index.html', { root: staticDir }));
|
|
228
|
-
|
|
229
|
-
app.use((req, res) => {
|
|
230
|
-
res.status(404).send('404 NOT FOUND');
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
// eslint-disable-next-line no-unused-vars
|
|
234
|
-
app.use((err, req, res, next) => {
|
|
235
|
-
logger.error('Something broke', { error: err });
|
|
236
|
-
res.status(500).send(`Daemon: Something broke! ${err.message}`);
|
|
237
|
-
});
|
|
238
|
-
} else {
|
|
239
|
-
app.use(router);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const httpServer = http.createServer(app);
|
|
243
|
-
const wsServer = createWebSocketServer(node);
|
|
244
|
-
wsServer.attach(httpServer);
|
|
245
|
-
|
|
246
|
-
httpServer.app = app;
|
|
247
|
-
|
|
248
|
-
return httpServer;
|
|
249
|
-
};
|
package/api/libs/auth.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const joinUrl = require('url-join');
|
|
3
|
-
const Mcrypto = require('@ocap/mcrypto');
|
|
4
|
-
const DiskStorage = require('@arcblock/did-auth-storage-nedb');
|
|
5
|
-
const { fromSecretKey, WalletType } = require('@ocap/wallet');
|
|
6
|
-
const { WalletAuthenticator } = require('@arcblock/did-auth');
|
|
7
|
-
const { DEFAULT_SERVICE_PATH, WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
|
|
8
|
-
const WalletHandlers = require('@blocklet/sdk/lib/wallet-handler');
|
|
9
|
-
const { sendToUser } = require('@blocklet/sdk/lib/util/send-notification');
|
|
10
|
-
|
|
11
|
-
const env = require('./env');
|
|
12
|
-
|
|
13
|
-
const type = WalletType({
|
|
14
|
-
role: Mcrypto.types.RoleType.ROLE_APPLICATION,
|
|
15
|
-
pk: Mcrypto.types.KeyType.ED25519,
|
|
16
|
-
hash: Mcrypto.types.HashType.SHA3,
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const wallet = fromSecretKey(process.env.ABT_NODE_SK, type);
|
|
20
|
-
|
|
21
|
-
const context = (() => {
|
|
22
|
-
const store = {};
|
|
23
|
-
return {
|
|
24
|
-
get: key => store[key],
|
|
25
|
-
set: (key, value) => {
|
|
26
|
-
store[key] = value;
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
})();
|
|
30
|
-
|
|
31
|
-
const authenticator = new WalletAuthenticator({
|
|
32
|
-
wallet,
|
|
33
|
-
baseUrl: env.baseUrl,
|
|
34
|
-
appInfo: async ({ baseUrl }) => {
|
|
35
|
-
const info = await context.get('node').getNodeInfo();
|
|
36
|
-
return {
|
|
37
|
-
name: info.name,
|
|
38
|
-
description: info.description,
|
|
39
|
-
icon: `${env.baseUrl || baseUrl}/images/node.png?version=${info.version}`,
|
|
40
|
-
link: env.baseUrl || baseUrl,
|
|
41
|
-
updateSubEndpoint: true,
|
|
42
|
-
subscriptionEndpoint: joinUrl(DEFAULT_SERVICE_PATH, WELLKNOWN_SERVICE_PATH_PREFIX, 'websocket'),
|
|
43
|
-
nodeDid: info.did,
|
|
44
|
-
};
|
|
45
|
-
},
|
|
46
|
-
chainInfo: {
|
|
47
|
-
host: 'none',
|
|
48
|
-
id: 'none',
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const handlers = new WalletHandlers({
|
|
53
|
-
authenticator,
|
|
54
|
-
tokenStorage: new DiskStorage({
|
|
55
|
-
dbPath: path.join(process.env.ABT_NODE_DATA_DIR, 'auth.db'),
|
|
56
|
-
dbPort: process.env.NODE_ENV === 'test' ? null : Number(process.env.NEDB_MULTI_PORT),
|
|
57
|
-
onload: err => {
|
|
58
|
-
if (err) {
|
|
59
|
-
// eslint-disable-next-line no-console
|
|
60
|
-
console.error(`Failed to load database from ${path.join(process.env.ABT_NODE_DATA_DIR, 'auth.db')}`, err);
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
}),
|
|
64
|
-
sendNotificationFn: (connectedDid, message) => {
|
|
65
|
-
const sender = {
|
|
66
|
-
appDid: wallet.address,
|
|
67
|
-
appSk: wallet.secretKey,
|
|
68
|
-
};
|
|
69
|
-
return sendToUser(connectedDid, message, sender, process.env.ABT_NODE_SERVICE_PORT);
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
module.exports = {
|
|
74
|
-
authenticator,
|
|
75
|
-
handlers,
|
|
76
|
-
wallet,
|
|
77
|
-
context,
|
|
78
|
-
};
|
package/api/libs/env.js
DELETED
package/api/libs/login.js
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/* eslint-disable implicit-arrow-linebreak */
|
|
2
|
-
/* eslint-disable no-underscore-dangle */
|
|
3
|
-
const jwt = require('jsonwebtoken');
|
|
4
|
-
const get = require('lodash/get');
|
|
5
|
-
const { fromPublicKey } = require('@ocap/wallet');
|
|
6
|
-
const getBlockletInfo = require('@blocklet/meta/lib/info');
|
|
7
|
-
const { VC_TYPE_NODE_PASSPORT, SERVER_ROLES, AUTH_CERT_TYPE } = require('@abtnode/constant');
|
|
8
|
-
const { createAuthToken } = require('@abtnode/auth/lib/auth');
|
|
9
|
-
const { isUserPassportRevoked, getRoleFromLocalPassport, isPassportAvailable } = require('@abtnode/auth/lib/passport');
|
|
10
|
-
const { getVcFromPresentation } = require('@abtnode/util/lib/vc');
|
|
11
|
-
const { verifyPresentation } = require('@arcblock/vc');
|
|
12
|
-
|
|
13
|
-
const logger = require('../../../auth/lib/logger');
|
|
14
|
-
|
|
15
|
-
if (!process.env.ABT_NODE_SESSION_SECRET) {
|
|
16
|
-
throw new Error('ABT_NODE_SESSION_SECRET must be set to start the node');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const secret = process.env.ABT_NODE_SESSION_SECRET;
|
|
20
|
-
// @link checkout https://github.com/auth0/node-jsonwebtoken#usage for ttl syntax
|
|
21
|
-
const ttl = Number(process.env.ABT_NODE_SESSION_TTL) ? Number(process.env.ABT_NODE_SESSION_TTL) : '1d';
|
|
22
|
-
|
|
23
|
-
async function getUser(node, did) {
|
|
24
|
-
const user = await node.getNodeUser({ did });
|
|
25
|
-
if (user && user.approved) {
|
|
26
|
-
return user;
|
|
27
|
-
}
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const createSessionToken = async (did, { passport, role } = {}) =>
|
|
32
|
-
createAuthToken({
|
|
33
|
-
did,
|
|
34
|
-
passport,
|
|
35
|
-
role,
|
|
36
|
-
secret,
|
|
37
|
-
expiresIn: ttl,
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
const parseUserByDecodedJwtToken = async ({ data = {}, node } = {}) => {
|
|
41
|
-
const { did } = data;
|
|
42
|
-
if (!did) {
|
|
43
|
-
throw new Error('Invalid jwt token: invalid did');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (data.type === AUTH_CERT_TYPE.OWNERSHIP_NFT) {
|
|
47
|
-
return { role: data.role, did: data.did };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (data.type === AUTH_CERT_TYPE.BLOCKLET_USER) {
|
|
51
|
-
return {
|
|
52
|
-
did: data.did,
|
|
53
|
-
role: `blocklet-${data.role}`,
|
|
54
|
-
blockletDid: data.blockletDid,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (data.type === AUTH_CERT_TYPE.BLOCKLET_CONTROLLER) {
|
|
59
|
-
return {
|
|
60
|
-
role: SERVER_ROLES.EXTERNAL_BLOCKLET_CONTROLLER,
|
|
61
|
-
did: data.did,
|
|
62
|
-
controller: data.controller,
|
|
63
|
-
|
|
64
|
-
// just for frond-end display
|
|
65
|
-
passports: [{ name: SERVER_ROLES.EXTERNAL_BLOCKLET_CONTROLLER, title: 'External' }],
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const { role, passport } = data;
|
|
70
|
-
|
|
71
|
-
const user = await getUser(node, did);
|
|
72
|
-
if (!user) {
|
|
73
|
-
throw new Error('Invalid jwt token: user not in whitelist');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (passport && passport.id && isUserPassportRevoked(user, passport)) {
|
|
77
|
-
throw new Error(`Passport ${passport.name} has been revoked`);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
user.role = role;
|
|
81
|
-
if (passport) {
|
|
82
|
-
user.passportId = passport.id;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return user;
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
function authWithJwt(token, node) {
|
|
89
|
-
return new Promise((resolve, reject) => {
|
|
90
|
-
jwt.verify(token, secret, async (err, decoded) => {
|
|
91
|
-
if (err) {
|
|
92
|
-
return reject(err);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return resolve(parseUserByDecodedJwtToken({ data: decoded, node }));
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
async function authWithAccessKey({ keyId, stamp, signature, node, blockletDid }) {
|
|
101
|
-
// request from blocklet
|
|
102
|
-
if (blockletDid) {
|
|
103
|
-
const [blocklet, info] = await Promise.all([
|
|
104
|
-
node.getBlocklet({ did: blockletDid, attachRuntimeInfo: false }),
|
|
105
|
-
node.getNodeInfo(),
|
|
106
|
-
]);
|
|
107
|
-
if (!blocklet) {
|
|
108
|
-
throw new Error(`blocklet is not valid: ${blockletDid}`);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const { wallet, name } = getBlockletInfo(blocklet, info.sk);
|
|
112
|
-
if (wallet.address !== keyId) {
|
|
113
|
-
throw new Error(`keyId is not valid: ${keyId}`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (!wallet.verify(`${stamp}-${keyId}`, signature)) {
|
|
117
|
-
throw new Error(`verify failed. keyId: ${keyId}, stamp: ${stamp}, signature: ${signature}`);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
did: blockletDid,
|
|
122
|
-
role: SERVER_ROLES.BLOCKLET_SDK,
|
|
123
|
-
blockletDid,
|
|
124
|
-
fullName: name,
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const accessKey = await node.getAccessKey({ accessKeyId: keyId });
|
|
129
|
-
if (!accessKey) {
|
|
130
|
-
throw new Error(`Access Key ${keyId} does not exist`);
|
|
131
|
-
}
|
|
132
|
-
const { accessKeyPublic, passport, remark } = accessKey;
|
|
133
|
-
|
|
134
|
-
const role = getRoleFromLocalPassport({ name: passport });
|
|
135
|
-
const wallet = fromPublicKey(accessKeyPublic);
|
|
136
|
-
if (!wallet.verify(`${stamp}-${keyId}`, signature)) {
|
|
137
|
-
throw new Error(`verify failed. keyId: ${keyId}, stamp: ${stamp}, signature: ${signature}`);
|
|
138
|
-
}
|
|
139
|
-
await node.refreshLastUsed(keyId);
|
|
140
|
-
return {
|
|
141
|
-
did: keyId,
|
|
142
|
-
fullName: remark || keyId,
|
|
143
|
-
role,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const authWithVcPresentation = async ({ node, vcPresentation, challenge }) => {
|
|
148
|
-
const vc = getVcFromPresentation(vcPresentation);
|
|
149
|
-
|
|
150
|
-
if (vc.type.includes(VC_TYPE_NODE_PASSPORT)) {
|
|
151
|
-
const { did } = await node.getNodeInfo();
|
|
152
|
-
// FIXME: 这个地方需要考虑外部 Passport(trustedPassports) 的权限
|
|
153
|
-
verifyPresentation({ presentation: vcPresentation, trustedIssuers: [did], challenge });
|
|
154
|
-
|
|
155
|
-
const userDid = get(vc, 'credentialSubject.id');
|
|
156
|
-
const user = await node.getNodeUser(userDid);
|
|
157
|
-
if (!user) {
|
|
158
|
-
throw new Error('The user of verifiable credential presentation does not exist');
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const passport = user.passports.find(x => x.id === vc.id);
|
|
162
|
-
if (!passport) {
|
|
163
|
-
throw new Error('The user does not match the passport');
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (!isPassportAvailable(passport)) {
|
|
167
|
-
throw new Error('The passport is no longer available');
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return {
|
|
171
|
-
did: user.did,
|
|
172
|
-
role: passport.name,
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (vc.type.includes('ServiceOwnershipCredential')) {
|
|
177
|
-
// FIXME: 这里的 trustedIssuers 相当于相信任何 VC,需要想更安全的方法
|
|
178
|
-
verifyPresentation({ presentation: vcPresentation, trustedIssuers: [get(vc, 'issuer.id')], challenge });
|
|
179
|
-
|
|
180
|
-
const { did: abtnodeDid, ownerNft } = await node.getNodeInfo();
|
|
181
|
-
const abtnodeDidInVc = get(vc, 'credentialSubject.isOwnerOf.abtnode.id');
|
|
182
|
-
if (abtnodeDidInVc !== abtnodeDid) {
|
|
183
|
-
logger.error('Invalid ownership vc: ABT Node DID not matched the DID in VC');
|
|
184
|
-
throw new Error('Invalid Ownership VC');
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const userDid = get(vc, 'credentialSubject.id');
|
|
188
|
-
const abtnodeHolder = get(ownerNft, 'holder');
|
|
189
|
-
|
|
190
|
-
if (userDid !== abtnodeHolder) {
|
|
191
|
-
logger.error('Invalid ownership vc: ABT Node holder not matched the owner DID in VC');
|
|
192
|
-
throw new Error('Invalid Ownership VC');
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return {
|
|
196
|
-
did: userDid,
|
|
197
|
-
role: SERVER_ROLES.OWNER,
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
throw new Error('Invalid verifiable credential presentation');
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
module.exports = {
|
|
205
|
-
createSessionToken,
|
|
206
|
-
authWithJwt,
|
|
207
|
-
authWithAccessKey,
|
|
208
|
-
authWithVcPresentation,
|
|
209
|
-
getUser,
|
|
210
|
-
secret,
|
|
211
|
-
parseUserByDecodedJwtToken,
|
|
212
|
-
};
|
package/api/libs/security.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
const get = require('lodash/get');
|
|
2
|
-
const { parse } = require('graphql');
|
|
3
|
-
const { NODE_MODES, ROLES } = require('@abtnode/constant');
|
|
4
|
-
|
|
5
|
-
const isDebugMode = info => info.enableWelcomePage && info.mode === NODE_MODES.DEBUG;
|
|
6
|
-
|
|
7
|
-
const whiteList = {
|
|
8
|
-
getNodeInfo: true,
|
|
9
|
-
getBlockletMetaFromUrl: true,
|
|
10
|
-
getBlocklets: info => isDebugMode(info),
|
|
11
|
-
getRoutingSites: info => isDebugMode(info),
|
|
12
|
-
resetNode: () => process.env.NODE_ENV === 'e2e',
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const protectGQL = (instance, gqlConfig) => async (req, res, next) => {
|
|
16
|
-
const query = req.query.query || req.body.query;
|
|
17
|
-
if (query) {
|
|
18
|
-
const info = await instance.states.node.read();
|
|
19
|
-
try {
|
|
20
|
-
const { definitions } = parse(query);
|
|
21
|
-
|
|
22
|
-
// get operations that need checked, excluded by whitelist
|
|
23
|
-
const operations = definitions
|
|
24
|
-
.map(x => {
|
|
25
|
-
const selections = get(x, 'selectionSet.selections') || [];
|
|
26
|
-
const names = selections.map(y => get(y, 'name.value'));
|
|
27
|
-
return names;
|
|
28
|
-
})
|
|
29
|
-
.reduce((arr, names) => {
|
|
30
|
-
arr.push(...names);
|
|
31
|
-
return arr;
|
|
32
|
-
}, [])
|
|
33
|
-
.filter(d => d !== '__schema')
|
|
34
|
-
.filter(name => {
|
|
35
|
-
if (typeof whiteList[name] === 'function') {
|
|
36
|
-
return !whiteList[name](info);
|
|
37
|
-
}
|
|
38
|
-
return !whiteList[name];
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// check auth
|
|
42
|
-
if (!req.user && operations.length) {
|
|
43
|
-
return res.status(401).json({ code: 'forbidden', error: 'not allowed' });
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// check batch mutation
|
|
47
|
-
const isBatchMutation = definitions.filter(x => x.operation === 'mutation').length > 1;
|
|
48
|
-
if (isBatchMutation) {
|
|
49
|
-
return res.status(403).json({ code: 'forbidden', error: 'batch mutation not allowed' });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// check maintenance
|
|
53
|
-
const hasMutation = definitions.some(x => x.operation === 'mutation');
|
|
54
|
-
if (hasMutation && [NODE_MODES.MAINTENANCE].includes(info.mode)) {
|
|
55
|
-
return res.status(503).json({ code: 'under maintenance', error: 'Blocklet server is under maintenance' });
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// check permission
|
|
59
|
-
if (req.user && req.user.role !== ROLES.OWNER && operations.length) {
|
|
60
|
-
const rbac = await instance.getRBAC();
|
|
61
|
-
|
|
62
|
-
const results = await Promise.all(
|
|
63
|
-
operations.map(async apiName => {
|
|
64
|
-
if (!gqlConfig[apiName]) {
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return !!(await rbac.canAny(
|
|
69
|
-
req.user.role,
|
|
70
|
-
gqlConfig[apiName].permissions.map(p => p.split('_'))
|
|
71
|
-
));
|
|
72
|
-
})
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
const can = results.every(Boolean);
|
|
76
|
-
if (!can) {
|
|
77
|
-
return res.status(403).json({ code: 'forbidden', error: 'no permission' });
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
} catch (err) {
|
|
81
|
-
// eslint-disable-next-line no-console
|
|
82
|
-
console.error('Failed to validate query', { err, query });
|
|
83
|
-
return res.json({ code: 'internal', error: err.message });
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return next();
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
module.exports = { protectGQL };
|