feat: add desktop repo (#1071)
This commit is contained in:
115
packages/desktop/app/javascripts/Main/ExtensionsServer.ts
Normal file
115
packages/desktop/app/javascripts/Main/ExtensionsServer.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import fs from 'fs'
|
||||
import http, { IncomingMessage, ServerResponse } from 'http'
|
||||
import mime from 'mime-types'
|
||||
import path from 'path'
|
||||
import { URL } from 'url'
|
||||
import { FileDoesNotExist } from './Utils/FileUtils'
|
||||
import { Paths } from './Types/Paths'
|
||||
import { extensions as str } from './Strings'
|
||||
|
||||
const Protocol = 'http'
|
||||
|
||||
function logError(...message: any) {
|
||||
console.error('extServer:', ...message)
|
||||
}
|
||||
|
||||
function log(...message: any) {
|
||||
console.log('extServer:', ...message)
|
||||
}
|
||||
|
||||
export function normalizeFilePath(requestUrl: string, host: string): string {
|
||||
const isThirdPartyComponent = requestUrl.startsWith('/Extensions')
|
||||
const isNativeComponent = requestUrl.startsWith('/components')
|
||||
if (!isThirdPartyComponent && !isNativeComponent) {
|
||||
throw new Error(`URL '${requestUrl}' falls outside of the extensions/features domain.`)
|
||||
}
|
||||
|
||||
const removedPrefix = requestUrl.replace('/components', '').replace('/Extensions', '')
|
||||
|
||||
const base = `${Protocol}://${host}`
|
||||
const url = new URL(removedPrefix, base)
|
||||
|
||||
/**
|
||||
* Normalize path (parse '..' and '.') so that we prevent path traversal by
|
||||
* joining a fully resolved path to the Extensions dir.
|
||||
*/
|
||||
const modifiedReqUrl = path.normalize(url.pathname)
|
||||
if (isThirdPartyComponent) {
|
||||
return path.join(Paths.extensionsDir, modifiedReqUrl)
|
||||
} else {
|
||||
return path.join(Paths.components, modifiedReqUrl)
|
||||
}
|
||||
}
|
||||
|
||||
async function handleRequest(request: IncomingMessage, response: ServerResponse) {
|
||||
try {
|
||||
if (!request.url) {
|
||||
throw new Error('No url.')
|
||||
}
|
||||
if (!request.headers.host) {
|
||||
throw new Error('No `host` header.')
|
||||
}
|
||||
|
||||
const filePath = normalizeFilePath(request.url, request.headers.host)
|
||||
|
||||
const stat = await fs.promises.lstat(filePath)
|
||||
|
||||
if (!stat.isFile()) {
|
||||
throw new Error('Client requested something that is not a file.')
|
||||
}
|
||||
|
||||
const mimeType = mime.lookup(path.parse(filePath).ext)
|
||||
|
||||
response.setHeader('Access-Control-Allow-Origin', '*')
|
||||
response.setHeader('Cache-Control', 'max-age=604800')
|
||||
response.setHeader('Content-Type', `${mimeType}; charset=utf-8`)
|
||||
|
||||
const data = fs.readFileSync(filePath)
|
||||
|
||||
response.writeHead(200)
|
||||
|
||||
response.end(data)
|
||||
} catch (error: any) {
|
||||
onRequestError(error, response)
|
||||
}
|
||||
}
|
||||
|
||||
function onRequestError(error: Error | { code: string }, response: ServerResponse) {
|
||||
let responseCode: number
|
||||
let message: string
|
||||
|
||||
if ('code' in error && error.code === FileDoesNotExist) {
|
||||
responseCode = 404
|
||||
message = str().missingExtension
|
||||
} else {
|
||||
logError(error)
|
||||
responseCode = 500
|
||||
message = str().unableToLoadExtension
|
||||
}
|
||||
|
||||
response.writeHead(responseCode)
|
||||
response.end(message)
|
||||
}
|
||||
|
||||
export function createExtensionsServer(): string {
|
||||
const port = 45653
|
||||
const ip = '127.0.0.1'
|
||||
const host = `${Protocol}://${ip}:${port}`
|
||||
|
||||
const initCallback = () => {
|
||||
log(`Server started at ${host}`)
|
||||
}
|
||||
|
||||
try {
|
||||
http
|
||||
.createServer(handleRequest)
|
||||
.listen(port, ip, initCallback)
|
||||
.on('error', (err) => {
|
||||
console.error('Error listening on extServer', err)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error creating ext server', error)
|
||||
}
|
||||
|
||||
return host
|
||||
}
|
||||
Reference in New Issue
Block a user