use regex + static method to centralize hashedfavicon URL behavior
This commit is contained in:
parent
15814cf86b
commit
04d94a9461
@ -1,4 +1,5 @@
|
|||||||
const http = require('http')
|
const http = require('http')
|
||||||
|
const format = require('util').format
|
||||||
|
|
||||||
const WebSocket = require('ws')
|
const WebSocket = require('ws')
|
||||||
const finalHttpHandler = require('finalhandler')
|
const finalHttpHandler = require('finalhandler')
|
||||||
@ -6,14 +7,18 @@ const serveStatic = require('serve-static')
|
|||||||
|
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
|
|
||||||
const HASHED_FAVICON_URL = '/hashedfavicon_'
|
const HASHED_FAVICON_URL_REGEX = /hashedfavicon_([a-z0-9]{32}).png/g
|
||||||
const HASHED_FAVICON_EXTENSION = '.png'
|
|
||||||
|
|
||||||
function getRemoteAddr (req) {
|
function getRemoteAddr (req) {
|
||||||
return req.headers['cf-connecting-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress
|
return req.headers['cf-connecting-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
class Server {
|
class Server {
|
||||||
|
static getHashedFaviconUrl (hash) {
|
||||||
|
// Format must be compatible with HASHED_FAVICON_URL_REGEX
|
||||||
|
return format('/hashedfavicon_%s.png', hash)
|
||||||
|
}
|
||||||
|
|
||||||
constructor (app) {
|
constructor (app) {
|
||||||
this._app = app
|
this._app = app
|
||||||
|
|
||||||
@ -28,24 +33,26 @@ class Server {
|
|||||||
this._http = http.createServer((req, res) => {
|
this._http = http.createServer((req, res) => {
|
||||||
logger.log('info', '%s requested: %s', getRemoteAddr(req), req.url)
|
logger.log('info', '%s requested: %s', getRemoteAddr(req), req.url)
|
||||||
|
|
||||||
if (req.url.startsWith(HASHED_FAVICON_URL) && req.url.endsWith(HASHED_FAVICON_EXTENSION)) {
|
// Test the URL against a regex for hashed favicon URLs
|
||||||
this.handleFaviconRequest(req, res)
|
// Require only 1 match ([0]) and test its first captured group ([1])
|
||||||
} else {
|
// Any invalid value or hit miss will pass into static handlers below
|
||||||
// Attempt to handle req using distServeStatic, otherwise fail over to faviconServeStatic
|
const faviconHash = [...req.url.matchAll(HASHED_FAVICON_URL_REGEX)]
|
||||||
// If faviconServeStatic fails, pass to finalHttpHandler to terminate
|
|
||||||
distServeStatic(req, res, () => {
|
if (faviconHash.length === 1 && this.handleFaviconRequest(res, faviconHash[0][1])) {
|
||||||
faviconsServeStatic(req, res, finalHttpHandler(req, res))
|
return
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attempt to handle req using distServeStatic, otherwise fail over to faviconServeStatic
|
||||||
|
// If faviconServeStatic fails, pass to finalHttpHandler to terminate
|
||||||
|
distServeStatic(req, res, () => {
|
||||||
|
faviconsServeStatic(req, res, finalHttpHandler(req, res))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFaviconRequest = (req, res) => {
|
handleFaviconRequest = (res, faviconHash) => {
|
||||||
let hash = req.url.substring(HASHED_FAVICON_URL.length)
|
|
||||||
hash = hash.substring(0, hash.length - HASHED_FAVICON_EXTENSION.length)
|
|
||||||
|
|
||||||
for (const serverRegistration of this._app.serverRegistrations) {
|
for (const serverRegistration of this._app.serverRegistrations) {
|
||||||
if (serverRegistration.faviconHash && serverRegistration.faviconHash === hash) {
|
if (serverRegistration.faviconHash && serverRegistration.faviconHash === faviconHash) {
|
||||||
const buf = Buffer.from(serverRegistration.lastFavicon.split(',')[1], 'base64')
|
const buf = Buffer.from(serverRegistration.lastFavicon.split(',')[1], 'base64')
|
||||||
|
|
||||||
res.writeHead(200, {
|
res.writeHead(200, {
|
||||||
@ -54,13 +61,11 @@ class Server {
|
|||||||
'Cache-Control': 'max-age=604800' // Cache hashed favicon for 7 days
|
'Cache-Control': 'max-age=604800' // Cache hashed favicon for 7 days
|
||||||
}).end(buf)
|
}).end(buf)
|
||||||
|
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terminate request, no match
|
return false
|
||||||
res.writeHead(404)
|
|
||||||
res.end()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createWebSocketServer () {
|
createWebSocketServer () {
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
|
|
||||||
const TimeTracker = require('./time')
|
const TimeTracker = require('./time')
|
||||||
|
const Server = require('./server')
|
||||||
|
|
||||||
const config = require('../config')
|
const config = require('../config')
|
||||||
const minecraftVersions = require('../minecraft_versions')
|
const minecraftVersions = require('../minecraft_versions')
|
||||||
|
|
||||||
const HASHED_FAVICON_URL = '/hashedfavicon_'
|
|
||||||
const HASHED_FAVICON_EXTENSION = '.png'
|
|
||||||
|
|
||||||
class ServerRegistration {
|
class ServerRegistration {
|
||||||
serverId
|
serverId
|
||||||
lastFavicon
|
lastFavicon
|
||||||
@ -233,16 +231,18 @@ class ServerRegistration {
|
|||||||
if (!this._faviconHasher) {
|
if (!this._faviconHasher) {
|
||||||
this._faviconHasher = crypto.createHash('md5')
|
this._faviconHasher = crypto.createHash('md5')
|
||||||
}
|
}
|
||||||
|
|
||||||
this.faviconHash = this._faviconHasher.update(favicon).digest('hex').toString()
|
this.faviconHash = this._faviconHasher.update(favicon).digest('hex').toString()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
getFaviconUrl () {
|
getFaviconUrl () {
|
||||||
if (this.faviconHash) {
|
if (this.faviconHash) {
|
||||||
return HASHED_FAVICON_URL + this.faviconHash + HASHED_FAVICON_EXTENSION
|
return Server.getHashedFaviconUrl(this.faviconHash)
|
||||||
} else if (this.data.favicon) {
|
} else if (this.data.favicon) {
|
||||||
return this.data.favicon
|
return this.data.favicon
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user