extracted the config directory access
This commit is contained in:
parent
1dd99edc0d
commit
a32681e154
2 changed files with 169 additions and 98 deletions
146
src/lib/mcp-auth-config.ts
Normal file
146
src/lib/mcp-auth-config.ts
Normal file
|
@ -0,0 +1,146 @@
|
|||
import crypto from 'crypto'
|
||||
import path from 'path'
|
||||
import os from 'os'
|
||||
import fs from 'fs/promises'
|
||||
|
||||
/**
|
||||
* MCP Remote Authentication Configuration
|
||||
*
|
||||
* This module handles the storage and retrieval of authentication-related data for MCP Remote.
|
||||
*
|
||||
* Configuration directory structure:
|
||||
* - The config directory is determined by MCP_REMOTE_CONFIG_DIR env var or defaults to ~/.mcp-auth
|
||||
* - Each file is prefixed with a hash of the server URL to separate configurations for different servers
|
||||
*
|
||||
* Files stored in the config directory:
|
||||
* - {server_hash}_client_info.json: Contains OAuth client registration information
|
||||
* - Format: OAuthClientInformation object with client_id and other registration details
|
||||
* - {server_hash}_tokens.json: Contains OAuth access and refresh tokens
|
||||
* - Format: OAuthTokens object with access_token, refresh_token, and expiration information
|
||||
* - {server_hash}_code_verifier.txt: Contains the PKCE code verifier for the current OAuth flow
|
||||
* - Format: Plain text string used for PKCE verification
|
||||
*
|
||||
* All JSON files are stored with 2-space indentation for readability.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the configuration directory path
|
||||
* @returns The path to the configuration directory
|
||||
*/
|
||||
export function getConfigDir(): string {
|
||||
return process.env.MCP_REMOTE_CONFIG_DIR || path.join(os.homedir(), '.mcp-auth')
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the configuration directory exists
|
||||
*/
|
||||
export async function ensureConfigDir(): Promise<void> {
|
||||
try {
|
||||
const configDir = getConfigDir()
|
||||
await fs.mkdir(configDir, { recursive: true })
|
||||
} catch (error) {
|
||||
console.error('Error creating config directory:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a hash for the server URL to use in filenames
|
||||
* @param serverUrl The server URL to hash
|
||||
* @returns The hashed server URL
|
||||
*/
|
||||
export function getServerUrlHash(serverUrl: string): string {
|
||||
return crypto.createHash('md5').update(serverUrl).digest('hex')
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a JSON file and parses it with the provided schema
|
||||
* @param serverUrlHash The hash of the server URL
|
||||
* @param filename The name of the file to read
|
||||
* @param schema The schema to validate against
|
||||
* @returns The parsed file content or undefined if the file doesn't exist
|
||||
*/
|
||||
export async function readJsonFile<T>(
|
||||
serverUrlHash: string,
|
||||
filename: string,
|
||||
schema: any
|
||||
): Promise<T | undefined> {
|
||||
try {
|
||||
await ensureConfigDir()
|
||||
const configDir = getConfigDir()
|
||||
const filePath = path.join(configDir, `${serverUrlHash}_${filename}`)
|
||||
const content = await fs.readFile(filePath, 'utf-8')
|
||||
return await schema.parseAsync(JSON.parse(content))
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
||||
return undefined
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a JSON object to a file
|
||||
* @param serverUrlHash The hash of the server URL
|
||||
* @param filename The name of the file to write
|
||||
* @param data The data to write
|
||||
*/
|
||||
export async function writeJsonFile(
|
||||
serverUrlHash: string,
|
||||
filename: string,
|
||||
data: any
|
||||
): Promise<void> {
|
||||
try {
|
||||
await ensureConfigDir()
|
||||
const configDir = getConfigDir()
|
||||
const filePath = path.join(configDir, `${serverUrlHash}_${filename}`)
|
||||
await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8')
|
||||
} catch (error) {
|
||||
console.error(`Error writing ${filename}:`, error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a text file
|
||||
* @param serverUrlHash The hash of the server URL
|
||||
* @param filename The name of the file to read
|
||||
* @param errorMessage Optional custom error message
|
||||
* @returns The file content as a string
|
||||
*/
|
||||
export async function readTextFile(
|
||||
serverUrlHash: string,
|
||||
filename: string,
|
||||
errorMessage?: string
|
||||
): Promise<string> {
|
||||
try {
|
||||
await ensureConfigDir()
|
||||
const configDir = getConfigDir()
|
||||
const filePath = path.join(configDir, `${serverUrlHash}_${filename}`)
|
||||
return await fs.readFile(filePath, 'utf-8')
|
||||
} catch (error) {
|
||||
throw new Error(errorMessage || `Error reading ${filename}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a text string to a file
|
||||
* @param serverUrlHash The hash of the server URL
|
||||
* @param filename The name of the file to write
|
||||
* @param text The text to write
|
||||
*/
|
||||
export async function writeTextFile(
|
||||
serverUrlHash: string,
|
||||
filename: string,
|
||||
text: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
await ensureConfigDir()
|
||||
const configDir = getConfigDir()
|
||||
const filePath = path.join(configDir, `${serverUrlHash}_${filename}`)
|
||||
await fs.writeFile(filePath, text, 'utf-8')
|
||||
} catch (error) {
|
||||
console.error(`Error writing ${filename}:`, error)
|
||||
throw error
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue