2025-07-01 22:37:29 -04:00
|
|
|
import fs from 'fs';
|
|
|
|
|
import path from 'path';
|
|
|
|
|
import axios from 'axios';
|
|
|
|
|
import { logger } from '@librechat/data-schemas';
|
|
|
|
|
|
|
|
|
|
export interface GoogleServiceKey {
|
|
|
|
|
type?: string;
|
|
|
|
|
project_id?: string;
|
|
|
|
|
private_key_id?: string;
|
|
|
|
|
private_key?: string;
|
|
|
|
|
client_email?: string;
|
|
|
|
|
client_id?: string;
|
|
|
|
|
auth_uri?: string;
|
|
|
|
|
token_uri?: string;
|
|
|
|
|
auth_provider_x509_cert_url?: string;
|
|
|
|
|
client_x509_cert_url?: string;
|
|
|
|
|
[key: string]: unknown;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-07-08 21:07:33 -04:00
|
|
|
* Load Google service key from file path, URL, or stringified JSON
|
|
|
|
|
* @param keyPath - The path to the service key file, URL to fetch it from, or stringified JSON
|
2025-07-01 22:37:29 -04:00
|
|
|
* @returns The parsed service key object or null if failed
|
|
|
|
|
*/
|
|
|
|
|
export async function loadServiceKey(keyPath: string): Promise<GoogleServiceKey | null> {
|
|
|
|
|
if (!keyPath) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let serviceKey: unknown;
|
|
|
|
|
|
2025-07-08 21:07:33 -04:00
|
|
|
// Check if it's a stringified JSON (starts with '{')
|
|
|
|
|
if (keyPath.trim().startsWith('{')) {
|
|
|
|
|
try {
|
|
|
|
|
serviceKey = JSON.parse(keyPath);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error('Failed to parse service key from stringified JSON', error);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-01 22:37:29 -04:00
|
|
|
// Check if it's a URL
|
2025-07-08 21:07:33 -04:00
|
|
|
else if (/^https?:\/\//.test(keyPath)) {
|
2025-07-01 22:37:29 -04:00
|
|
|
try {
|
|
|
|
|
const response = await axios.get(keyPath);
|
|
|
|
|
serviceKey = response.data;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error(`Failed to fetch the service key from URL: ${keyPath}`, error);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// It's a file path
|
|
|
|
|
try {
|
|
|
|
|
const absolutePath = path.isAbsolute(keyPath) ? keyPath : path.resolve(keyPath);
|
|
|
|
|
const fileContent = fs.readFileSync(absolutePath, 'utf8');
|
|
|
|
|
serviceKey = JSON.parse(fileContent);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error(`Failed to load service key from file: ${keyPath}`, error);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the response is a string (e.g., from a URL that returns JSON as text), parse it
|
|
|
|
|
if (typeof serviceKey === 'string') {
|
|
|
|
|
try {
|
|
|
|
|
serviceKey = JSON.parse(serviceKey);
|
|
|
|
|
} catch (parseError) {
|
|
|
|
|
logger.error(`Failed to parse service key JSON from ${keyPath}`, parseError);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validate the service key has required fields
|
|
|
|
|
if (!serviceKey || typeof serviceKey !== 'object') {
|
|
|
|
|
logger.error(`Invalid service key format from ${keyPath}`);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return serviceKey as GoogleServiceKey;
|
|
|
|
|
}
|