* feat: implement OAuth client provider and lockfile management * feat: implement OAuth callback server and refactor authentication flow * fix(McpService): restrict command handling to 'npx' for improved clarity * refactor: make callbackPort optional in OAuthProviderOptions and clean up MCPService * refactor: restructure OAuth handling by creating separate callback and provider classes, and remove unused utility functions
77 lines
2.1 KiB
TypeScript
77 lines
2.1 KiB
TypeScript
import Logger from 'electron-log'
|
|
import EventEmitter from 'events'
|
|
import http from 'http'
|
|
import { URL } from 'url'
|
|
|
|
import { OAuthCallbackServerOptions } from './types'
|
|
|
|
export class CallBackServer {
|
|
private server: Promise<http.Server>
|
|
private events: EventEmitter
|
|
|
|
constructor(options: OAuthCallbackServerOptions) {
|
|
const { port, path, events } = options
|
|
this.events = events
|
|
this.server = this.initialize(port, path)
|
|
}
|
|
|
|
initialize(port: number, path: string): Promise<http.Server> {
|
|
const server = http.createServer((req, res) => {
|
|
// Only handle requests to the callback path
|
|
if (req.url?.startsWith(path)) {
|
|
try {
|
|
// Parse the URL to extract the authorization code
|
|
const url = new URL(req.url, `http://localhost:${port}`)
|
|
const code = url.searchParams.get('code')
|
|
if (code) {
|
|
// Emit the code event
|
|
this.events.emit('auth-code-received', code)
|
|
}
|
|
} catch (error) {
|
|
Logger.error('Error processing OAuth callback:', error)
|
|
res.writeHead(500, { 'Content-Type': 'text/plain' })
|
|
res.end('Internal Server Error')
|
|
}
|
|
} else {
|
|
// Not a callback request
|
|
res.writeHead(404, { 'Content-Type': 'text/plain' })
|
|
res.end('Not Found')
|
|
}
|
|
})
|
|
|
|
// Handle server errors
|
|
server.on('error', (error) => {
|
|
Logger.error('OAuth callback server error:', error)
|
|
})
|
|
|
|
const runningServer = new Promise<http.Server>((resolve, reject) => {
|
|
server.listen(port, () => {
|
|
Logger.info(`OAuth callback server listening on port ${port}`)
|
|
resolve(server)
|
|
})
|
|
|
|
server.on('error', (error) => {
|
|
reject(error)
|
|
})
|
|
})
|
|
return runningServer
|
|
}
|
|
|
|
get getServer(): Promise<http.Server> {
|
|
return this.server
|
|
}
|
|
|
|
async close() {
|
|
const server = await this.server
|
|
server.close()
|
|
}
|
|
|
|
async waitForAuthCode(): Promise<string> {
|
|
return new Promise((resolve) => {
|
|
this.events.once('auth-code-received', (code) => {
|
|
resolve(code)
|
|
})
|
|
})
|
|
}
|
|
}
|