mirror of
https://github.com/ellite/Wallos.git
synced 2026-04-18 22:20:54 -04:00
fix: ai recommendation numbering when deleting a recommendation feat: mask ai api key on the settings page fix: unicode character on the css file fix: retain first and last name when switching language during registration fix: calendar ocurrences to respect subscriptions start date fix: ssrf vulnerability on several endpoints fix: logo search fix: xss vulnerability on payment method rename endpoint fix: set login cookie to httponly
146 lines
4.9 KiB
PHP
146 lines
4.9 KiB
PHP
<?php
|
|
|
|
require_once '../../includes/connect_endpoint.php';
|
|
require_once '../../includes/validate_endpoint.php';
|
|
require_once '../../includes/ssrf_helper.php';
|
|
|
|
$chatgptModelsApiUrl = 'https://api.openai.com/v1/models';
|
|
$geminiModelsApiUrl = 'https://generativelanguage.googleapis.com/v1beta/models';
|
|
$openrouterModelsApiUrl = 'https://openrouter.ai/api/v1/models';
|
|
|
|
$input = file_get_contents('php://input');
|
|
$data = json_decode($input, true);
|
|
// Check if ai-type and ai-api-key are set
|
|
$aiType = isset($data["type"]) ? trim($data["type"]) : '';
|
|
$aiApiKey = isset($data["api_key"]) ? trim($data["api_key"]) : '';
|
|
$aiOllamaHost = isset($data["ollama_host"]) ? trim($data["ollama_host"]) : '';
|
|
|
|
// Validate ai-type
|
|
if (!in_array($aiType, ['chatgpt', 'gemini', 'openrouter', 'ollama'])) {
|
|
$response = [
|
|
"success" => false,
|
|
"message" => translate('error', $i18n)
|
|
];
|
|
echo json_encode($response);
|
|
exit;
|
|
}
|
|
|
|
// Validate ai-api-key and fetch models if ai-type is chatgpt, gemini or openrouter
|
|
if ($aiType === 'chatgpt' || $aiType === 'gemini' || $aiType === 'openrouter') {
|
|
if (empty($aiApiKey)) {
|
|
$response = [
|
|
"success" => false,
|
|
"message" => translate('invalid_api_key', $i18n)
|
|
];
|
|
echo json_encode($response);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// Prepare the request headers
|
|
$headers = [
|
|
'Content-Type: application/json',
|
|
];
|
|
if ($aiType === 'chatgpt') {
|
|
$headers[] = 'Authorization: Bearer ' . $aiApiKey;
|
|
$apiUrl = $chatgptModelsApiUrl;
|
|
} elseif ($aiType === 'gemini') {
|
|
$apiUrl = $geminiModelsApiUrl . '?key=' . urlencode($aiApiKey);
|
|
} elseif ($aiType === 'openrouter') {
|
|
$headers[] = 'Authorization: Bearer ' . $aiApiKey;
|
|
$apiUrl = $openrouterModelsApiUrl;
|
|
} else {
|
|
// For ollama, no API key is needed
|
|
// Check for ollama host
|
|
if (empty($aiOllamaHost)) {
|
|
$response = [
|
|
"success" => false,
|
|
"message" => translate('invalid_host', $i18n)
|
|
];
|
|
echo json_encode($response);
|
|
exit;
|
|
}
|
|
|
|
// Scheme check
|
|
$parsedUrl = parse_url($aiOllamaHost);
|
|
if (
|
|
!isset($parsedUrl['scheme']) ||
|
|
!in_array(strtolower($parsedUrl['scheme']), ['http', 'https']) ||
|
|
!filter_var($aiOllamaHost, FILTER_VALIDATE_URL)
|
|
) {
|
|
echo json_encode(["success" => false, "message" => translate('invalid_host', $i18n)]);
|
|
exit;
|
|
}
|
|
|
|
// SSRF check — dies automatically if private IP not in allowlist
|
|
$ssrf = validate_webhook_url_for_ssrf($aiOllamaHost, $db, $i18n);
|
|
|
|
$apiUrl = $aiOllamaHost . '/api/tags';
|
|
}
|
|
// Initialize cURL
|
|
$ch = curl_init($apiUrl);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 60); // Set a timeout for the request
|
|
// Execute the request
|
|
$response = curl_exec($ch);
|
|
// Check for cURL errors
|
|
if (curl_errno($ch)) {
|
|
$response = [
|
|
"success" => false,
|
|
"message" => ($aiType === 'ollama')
|
|
? translate('invalid_host', $i18n)
|
|
: translate('error', $i18n)
|
|
];
|
|
} else {
|
|
// Decode the response
|
|
$modelsData = json_decode($response, true);
|
|
if ($aiType === 'gemini' && isset($modelsData['models']) && is_array($modelsData['models'])) {
|
|
// Normalize Gemini response
|
|
$models = array_map(function ($model) {
|
|
return [
|
|
'id' => str_replace('models/', '', $model['name']),
|
|
'name' => $model['displayName'] ?? $model['name'],
|
|
];
|
|
}, $modelsData['models']);
|
|
$response = [
|
|
"success" => true,
|
|
"models" => $models
|
|
];
|
|
} elseif (isset($modelsData['data']) && is_array($modelsData['data'])) {
|
|
// OpenAI format
|
|
$models = array_map(function ($model) {
|
|
return [
|
|
'id' => $model['id'],
|
|
'name' => $model['name'] ?? $model['id'],
|
|
];
|
|
}, $modelsData['data']);
|
|
$response = [
|
|
"success" => true,
|
|
"models" => $models
|
|
];
|
|
} elseif ($aiType === 'ollama' && isset($modelsData['models']) && is_array($modelsData['models'])) {
|
|
// Normalize Ollama response
|
|
$models = array_map(function ($model) {
|
|
return [
|
|
'id' => $model['name'],
|
|
'name' => $model['name'],
|
|
];
|
|
}, $modelsData['models']);
|
|
$response = [
|
|
"success" => true,
|
|
"models" => $models
|
|
];
|
|
} else {
|
|
$response = [
|
|
"success" => false,
|
|
"message" => ($aiType === 'ollama')
|
|
? translate('invalid_host', $i18n)
|
|
: translate('invalid_api_key', $i18n)
|
|
];
|
|
}
|
|
}
|
|
// Close cURL session
|
|
curl_close($ch);
|
|
// Return the response as JSON
|
|
echo json_encode($response); |