refac
This commit is contained in:
@@ -269,6 +269,51 @@ async def set_terminal_servers_config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@router.post('/terminal_servers/verify')
|
||||||
|
async def verify_terminal_server_connection(
|
||||||
|
request: Request, form_data: TerminalServerConnection, user=Depends(get_admin_user)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Verify the connection to a terminal server by detecting its type.
|
||||||
|
|
||||||
|
Tries GET {url}/api/v1/policies (orchestrator) then GET {url}/api/config
|
||||||
|
(plain terminal). Returns ``{status: true, type: "orchestrator"|"terminal"}``.
|
||||||
|
"""
|
||||||
|
base_url = (form_data.url or '').rstrip('/')
|
||||||
|
if not base_url:
|
||||||
|
raise HTTPException(status_code=400, detail='Terminal server URL is required')
|
||||||
|
|
||||||
|
headers = {}
|
||||||
|
if form_data.auth_type == 'bearer' and form_data.key:
|
||||||
|
headers['Authorization'] = f'Bearer {form_data.key}'
|
||||||
|
|
||||||
|
try:
|
||||||
|
async with aiohttp.ClientSession(
|
||||||
|
trust_env=True,
|
||||||
|
timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT),
|
||||||
|
) as session:
|
||||||
|
# Orchestrators expose a policies API; plain terminals don't.
|
||||||
|
try:
|
||||||
|
async with session.get(f'{base_url}/api/v1/policies', headers=headers) as resp:
|
||||||
|
if resp.ok:
|
||||||
|
return {'status': True, 'type': 'orchestrator'}
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Fall back to open-terminal config endpoint.
|
||||||
|
try:
|
||||||
|
async with session.get(f'{base_url}/api/config', headers=headers) as resp:
|
||||||
|
if resp.ok:
|
||||||
|
return {'status': True, 'type': 'terminal'}
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log.debug(f'Failed to connect to the terminal server: {e}')
|
||||||
|
|
||||||
|
raise HTTPException(status_code=400, detail='Failed to connect to the terminal server')
|
||||||
|
|
||||||
|
|
||||||
@router.post('/tool_servers/verify')
|
@router.post('/tool_servers/verify')
|
||||||
async def verify_tool_servers_config(request: Request, form_data: ToolServerConnection, user=Depends(get_admin_user)):
|
async def verify_tool_servers_config(request: Request, form_data: ToolServerConnection, user=Depends(get_admin_user)):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -308,6 +308,40 @@ export const putOrchestratorPolicy = async (
|
|||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify a terminal server connection via the backend proxy.
|
||||||
|
* Used for system/admin connections to avoid CORS issues and API key exposure.
|
||||||
|
*/
|
||||||
|
export const verifyTerminalServerConnection = async (token: string, connection: object) => {
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
const res = await fetch(`${WEBUI_API_BASE_URL}/configs/terminal_servers/verify`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
...connection
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(async (res) => {
|
||||||
|
if (!res.ok) throw await res.json();
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
error = err.detail;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
export const verifyToolServerConnection = async (token: string, connection: object) => {
|
export const verifyToolServerConnection = async (token: string, connection: object) => {
|
||||||
let error = null;
|
let error = null;
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,12 @@
|
|||||||
import LockClosed from '$lib/components/icons/LockClosed.svelte';
|
import LockClosed from '$lib/components/icons/LockClosed.svelte';
|
||||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||||
import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
||||||
import { detectTerminalServerType, putOrchestratorPolicy } from '$lib/apis/configs';
|
import { detectTerminalServerType, verifyTerminalServerConnection, putOrchestratorPolicy } from '$lib/apis/configs';
|
||||||
import { getTerminalConfig } from '$lib/apis/terminal';
|
import { getTerminalConfig } from '$lib/apis/terminal';
|
||||||
|
|
||||||
export let show = false;
|
export let show = false;
|
||||||
export let edit = false;
|
export let edit = false;
|
||||||
export let admin = false;
|
export let direct = false;
|
||||||
export let connection = null;
|
export let connection = null;
|
||||||
|
|
||||||
export let onSubmit: Function = () => {};
|
export let onSubmit: Function = () => {};
|
||||||
@@ -110,9 +110,13 @@
|
|||||||
|
|
||||||
verifying = true;
|
verifying = true;
|
||||||
try {
|
try {
|
||||||
if (admin) {
|
if (!direct) {
|
||||||
// Admin: detect orchestrator vs terminal
|
// System connection: proxy through backend to avoid CORS / key exposure
|
||||||
const type = await detectTerminalServerType(_url, key);
|
const result = await verifyTerminalServerConnection(
|
||||||
|
localStorage.token,
|
||||||
|
{ url: _url, key, auth_type }
|
||||||
|
);
|
||||||
|
const type = result?.type ?? null;
|
||||||
|
|
||||||
if (type) {
|
if (type) {
|
||||||
serverType = type;
|
serverType = type;
|
||||||
@@ -137,7 +141,7 @@
|
|||||||
toast.error($i18n.t('Server connection failed'));
|
toast.error($i18n.t('Server connection failed'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Non-admin: simple terminal verification
|
// Direct connection: verify from browser
|
||||||
const res = await getTerminalConfig(_url, key);
|
const res = await getTerminalConfig(_url, key);
|
||||||
if (res) {
|
if (res) {
|
||||||
toast.success($i18n.t('Server connection verified'));
|
toast.success($i18n.t('Server connection verified'));
|
||||||
@@ -192,7 +196,7 @@
|
|||||||
url = url.replace(/\/$/, '');
|
url = url.replace(/\/$/, '');
|
||||||
|
|
||||||
// Save policy to orchestrator if applicable
|
// Save policy to orchestrator if applicable
|
||||||
if (serverType === 'orchestrator' && admin && policyId) {
|
if (serverType === 'orchestrator' && !direct && policyId) {
|
||||||
try {
|
try {
|
||||||
await putOrchestratorPolicy(url, key, policyId, buildPolicyData());
|
await putOrchestratorPolicy(url, key, policyId, buildPolicyData());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -202,7 +206,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
...(admin && id.trim() ? { id: id.trim() } : {}),
|
...(!direct && id.trim() ? { id: id.trim() } : {}),
|
||||||
url,
|
url,
|
||||||
key,
|
key,
|
||||||
name,
|
name,
|
||||||
@@ -210,7 +214,7 @@
|
|||||||
auth_type,
|
auth_type,
|
||||||
enabled: enabled,
|
enabled: enabled,
|
||||||
config: {
|
config: {
|
||||||
...(admin ? { access_grants: accessGrants } : {})
|
...(!direct ? { access_grants: accessGrants } : {})
|
||||||
},
|
},
|
||||||
// Policy fields
|
// Policy fields
|
||||||
...(serverType ? { server_type: serverType } : {}),
|
...(serverType ? { server_type: serverType } : {}),
|
||||||
@@ -270,7 +274,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if admin}
|
{#if !direct}
|
||||||
<div class="flex flex-col flex-1">
|
<div class="flex flex-col flex-1">
|
||||||
<div class="flex justify-between mb-0.5">
|
<div class="flex justify-between mb-0.5">
|
||||||
<label
|
<label
|
||||||
@@ -368,7 +372,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Policy section (orchestrator only, admin only) -->
|
<!-- Policy section (orchestrator only, admin only) -->
|
||||||
{#if serverType === 'orchestrator' && admin}
|
{#if serverType === 'orchestrator' && !direct}
|
||||||
<div class="flex gap-2 mt-2">
|
<div class="flex gap-2 mt-2">
|
||||||
<div class="flex flex-col w-full">
|
<div class="flex flex-col w-full">
|
||||||
<div class="flex justify-between mb-0.5">
|
<div class="flex justify-between mb-0.5">
|
||||||
@@ -580,7 +584,7 @@
|
|||||||
{$i18n.t('Advanced')}
|
{$i18n.t('Advanced')}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{#if admin}
|
{#if !direct}
|
||||||
<button
|
<button
|
||||||
class="bg-gray-50 hover:bg-gray-100 text-black dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-white transition px-2 py-1 object-cover rounded-full flex gap-1 items-center mt-2"
|
class="bg-gray-50 hover:bg-gray-100 text-black dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-white transition px-2 py-1 object-cover rounded-full flex gap-1 items-center mt-2"
|
||||||
type="button"
|
type="button"
|
||||||
@@ -662,7 +666,7 @@
|
|||||||
>
|
>
|
||||||
<option value="none">{$i18n.t('None')}</option>
|
<option value="none">{$i18n.t('None')}</option>
|
||||||
<option value="bearer">{$i18n.t('Bearer')}</option>
|
<option value="bearer">{$i18n.t('Bearer')}</option>
|
||||||
{#if admin}
|
{#if !direct}
|
||||||
<option value="session">{$i18n.t('Session')}</option>
|
<option value="session">{$i18n.t('Session')}</option>
|
||||||
<option value="system_oauth">{$i18n.t('OAuth')}</option>
|
<option value="system_oauth">{$i18n.t('OAuth')}</option>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -122,7 +122,6 @@
|
|||||||
<AddToolServerModal bind:show={showConnectionModal} onSubmit={addConnectionHandler} />
|
<AddToolServerModal bind:show={showConnectionModal} onSubmit={addConnectionHandler} />
|
||||||
|
|
||||||
<AddTerminalServerModal
|
<AddTerminalServerModal
|
||||||
admin
|
|
||||||
bind:show={showAddTerminalModal}
|
bind:show={showAddTerminalModal}
|
||||||
edit={editTerminalIdx !== null}
|
edit={editTerminalIdx !== null}
|
||||||
connection={editTerminalIdx !== null ? terminalConnections[editTerminalIdx] : null}
|
connection={editTerminalIdx !== null ? terminalConnections[editTerminalIdx] : null}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AddTerminalServerModal bind:show={showAddModal} onSubmit={(server) => addServer(server)} />
|
<AddTerminalServerModal direct bind:show={showAddModal} onSubmit={(server) => addServer(server)} />
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between items-center mb-1">
|
<div class="flex justify-between items-center mb-1">
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AddTerminalServerModal
|
<AddTerminalServerModal
|
||||||
|
direct
|
||||||
edit
|
edit
|
||||||
bind:show={showConfigModal}
|
bind:show={showConfigModal}
|
||||||
{connection}
|
{connection}
|
||||||
|
|||||||
Reference in New Issue
Block a user