Skip to content

Commit

Permalink
🐛 Some fixes to API server (#1723)
Browse files Browse the repository at this point in the history
  • Loading branch information
SPGoding authored Jan 19, 2025
1 parent a864eb9 commit d15d19f
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 7 deletions.
2 changes: 1 addition & 1 deletion ansible/roles/api-server/templates/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ export SPYGLASSMC_API_SERVER_DIR="/var/lib/api-server"
export SPYGLASSMC_API_SERVER_WEBHOOK_SECRET="{{ api_server_webhook_secret }}"
export SPYGLASSMC_API_SERVER_PORT="{{ api_server_port }}"

/usr/local/bin/spyglassmc-web-api-server
/usr/local/bin/spyglassmc-web-api-server --color
14 changes: 13 additions & 1 deletion packages/web-api-server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,21 @@ const app = express()
'ETag',
'RateLimit-Limit',
'RateLimit-Remaining',
'RateLimit-Reset',
'Retry-After',
],
}))
.use((_req, res, next) => {
// 'max-age=0' instead of 'no-cache' is used, as 'no-cache' disallows the use of stale
// response in cases where the origin server is unreachable.
res.setHeader('Cache-Control', 'max-age=0')

res.contentType('application/json')
res.appendHeader('X-Content-Type-Options', 'nosniff')
res.appendHeader('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload')

next()
})
.use(logger)
.use(userAgentEnforcer)
.use(slowDown({
Expand Down Expand Up @@ -106,7 +118,7 @@ const app = express()
)
.get('/favicon.ico', cheapRateLimiter, (_req, res) => {
res.contentType('image/x-icon')
res.appendHeader('Cache-Control', 'public, max-age=604800')
res.setHeader('Cache-Control', 'max-age=604800, public')
res.sendFile(fileURLToPath(new URL('../favicon.ico', import.meta.url)))
})
.all('*catchall', cheapRateLimiter, (_req, res) => {
Expand Down
15 changes: 10 additions & 5 deletions packages/web-api-server/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ export async function sendGitFile(
// since the same value is used for different representations of the same resource (e.g. gzip
// compressed v.s. no compression). It can only guarantee semantic equivalence, not byte-for-byte
// equivalence.
res.setHeader('ETag', `W/"${hash}"`)
if (req.headers['if-none-match'] === hash) {
const etag = `W/"${hash}"`
res.setHeader('ETag', etag)
if (req.headers['if-none-match'] === etag) {
res.status(304).end()
await rateLimiter.reward(req.ip!, CHEAP_REQUEST_POINTS)
} else {
Expand All @@ -122,8 +123,9 @@ export async function sendGitTarball(
) {
const hash = (await git.log(['--format=%H', '-1', branch])).latest!.hash
// See comments in sendGitFile() for why this is a weak validator.
res.setHeader('ETag', `W/"${hash}"`)
if (req.headers['if-none-match'] === hash) {
const etag = `W/"${hash}"`
res.setHeader('ETag', etag)
if (req.headers['if-none-match'] === etag) {
res.status(304).end()
await rateLimiter.reward(req.ip!, EXPENSIVE_REQUEST_POINTS)
} else {
Expand Down Expand Up @@ -171,7 +173,6 @@ export const loggerMiddleware = (req: Request, res: Response, next: NextFunction
}...`,
),
)
res.contentType('application/json')
res.on('finish', () => {
const end = new Date()
const message =
Expand Down Expand Up @@ -214,6 +215,10 @@ const getRateLimiter =
try {
const result = await rateLimiter.consume(req.ip!, points)
res.appendHeader('RateLimit-Remaining', `${result.remainingPoints}`)
res.appendHeader(
'RateLimit-Reset',
`${new Date(Date.now() + result.msBeforeNext).toUTCString()}`,
)
next()
} catch (e) {
if (e instanceof RateLimiterRes) {
Expand Down

0 comments on commit d15d19f

Please sign in to comment.