init claude-code
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* OAuth redirect port helpers — extracted from auth.ts to break the
|
||||
* auth.ts ↔ xaaIdpLogin.ts circular dependency.
|
||||
*/
|
||||
import { createServer } from 'http'
|
||||
import { getPlatform } from '../../utils/platform.js'
|
||||
|
||||
// Windows dynamic port range 49152-65535 is reserved
|
||||
const REDIRECT_PORT_RANGE =
|
||||
getPlatform() === 'windows'
|
||||
? { min: 39152, max: 49151 }
|
||||
: { min: 49152, max: 65535 }
|
||||
const REDIRECT_PORT_FALLBACK = 3118
|
||||
|
||||
/**
|
||||
* Builds a redirect URI on localhost with the given port and a fixed `/callback` path.
|
||||
*
|
||||
* RFC 8252 Section 7.3 (OAuth for Native Apps): loopback redirect URIs match any
|
||||
* port as long as the path matches.
|
||||
*/
|
||||
export function buildRedirectUri(
|
||||
port: number = REDIRECT_PORT_FALLBACK,
|
||||
): string {
|
||||
return `http://localhost:${port}/callback`
|
||||
}
|
||||
|
||||
function getMcpOAuthCallbackPort(): number | undefined {
|
||||
const port = parseInt(process.env.MCP_OAUTH_CALLBACK_PORT || '', 10)
|
||||
return port > 0 ? port : undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an available port in the specified range for OAuth redirect
|
||||
* Uses random selection for better security
|
||||
*/
|
||||
export async function findAvailablePort(): Promise<number> {
|
||||
// First, try the configured port if specified
|
||||
const configuredPort = getMcpOAuthCallbackPort()
|
||||
if (configuredPort) {
|
||||
return configuredPort
|
||||
}
|
||||
|
||||
const { min, max } = REDIRECT_PORT_RANGE
|
||||
const range = max - min + 1
|
||||
const maxAttempts = Math.min(range, 100) // Don't try forever
|
||||
|
||||
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
||||
const port = min + Math.floor(Math.random() * range)
|
||||
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const testServer = createServer()
|
||||
testServer.once('error', reject)
|
||||
testServer.listen(port, () => {
|
||||
testServer.close(() => resolve())
|
||||
})
|
||||
})
|
||||
return port
|
||||
} catch {
|
||||
// Port in use, try another random port
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// If random selection failed, try the fallback port
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const testServer = createServer()
|
||||
testServer.once('error', reject)
|
||||
testServer.listen(REDIRECT_PORT_FALLBACK, () => {
|
||||
testServer.close(() => resolve())
|
||||
})
|
||||
})
|
||||
return REDIRECT_PORT_FALLBACK
|
||||
} catch {
|
||||
throw new Error(`No available ports for OAuth redirect`)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user