-
-
Notifications
You must be signed in to change notification settings - Fork 83
Expand file tree
/
Copy pathapollo.js
More file actions
110 lines (98 loc) · 2.97 KB
/
apollo.js
File metadata and controls
110 lines (98 loc) · 2.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// @ts-check
const { expressMiddleware } = require('@as-integrations/express5')
const { ApolloServerErrorCode } = require('@apollo/server/errors')
const { GraphQLError } = require('graphql')
const { parse } = require('graphql')
const { state } = require('../services/state')
const { version } = require('../../../package.json')
const { DataLimitCheck } = require('../services/DataLimitCheck')
/**
*
* @param {Awaited<ReturnType<import('../graphql/server')['startApollo']>>} server
* @returns
*/
function apolloMiddleware(server) {
return expressMiddleware(server, {
context: async ({ req, res }) => {
const perms = req.user ? req.user.perms : req.session.perms
const username = req?.user?.username || ''
const id = req?.user?.id || 0
const clientVHeader = req.headers['apollographql-client-version']
const clientV =
(typeof clientVHeader === 'string' && clientVHeader.trim()) ||
version ||
1
const serverV = version || 1
const definition =
/** @type {import('graphql').OperationDefinitionNode} */ (
parse(req.body.query).definitions.find(
(d) => d.kind === 'OperationDefinition',
)
)
const endpoint = definition?.name?.value || ''
const userDataLimit = new DataLimitCheck(req)
const errorCtx = {
id,
user: username,
clientV,
serverV,
endpoint: userDataLimit.category,
}
// Allow the hot-reload dev client to bypass strict version matching
const isDevClient = clientV === 'development'
if (clientV && serverV && clientV !== serverV && !isDevClient) {
throw new GraphQLError('old_client', {
extensions: {
...errorCtx,
http: { status: 464 },
code: ApolloServerErrorCode.BAD_USER_INPUT,
},
})
}
if (!perms && endpoint !== 'Locales') {
throw new GraphQLError('session_expired', {
extensions: {
...errorCtx,
http: { status: 511 },
code: 'EXPIRED',
},
})
}
if (
definition?.operation === 'mutation' &&
!id &&
endpoint !== 'SetTutorial'
) {
throw new GraphQLError('unauthenticated', {
extensions: {
...errorCtx,
http: { status: 401 },
code: 'UNAUTHENTICATED',
},
})
}
if (await userDataLimit.isOverLimit()) {
throw new GraphQLError('data_limit_reached', {
extensions: {
...errorCtx,
until: userDataLimit.until,
http: { status: 429 },
code: ApolloServerErrorCode.BAD_REQUEST,
},
})
}
return {
userId: id,
username,
req,
res,
Db: state.db,
Event: state.event,
perms,
token: req.headers.token,
operation: definition?.operation,
}
},
})
}
module.exports = { apolloMiddleware }