Add custom image handling and access policy management

- Implement tests for custom KVM and LXC image creation, ensuring invalid sources and architecture mismatches are rejected.
- Introduce access policy management in CLI, allowing configuration of allowed sources and trusted proxies.
- Add NAT network configuration with validation for RFC1918 compliance and subnet parsing.
- Create panel access policy management, including normalization and evaluation of access decisions based on client IPs and forwarded headers.
- Develop middleware for enforcing access policies in the server, returning appropriate responses for allowed and denied requests.
- Enhance custom image downloading and validation, ensuring integrity and security of downloaded root filesystem archives.
- Include comprehensive tests for all new functionalities to ensure reliability and correctness.
This commit is contained in:
MengMengCode
2026-07-26 04:04:45 +08:00
parent 8283b88ded
commit 38debab1aa
49 changed files with 4504 additions and 246 deletions
+63 -2
View File
@@ -21,10 +21,15 @@ api.interceptors.request.use((config) => {
api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
const requestURL = String(error.config?.url || '')
const isLoginRequest = ['/login', '/sub-user/login', '/sub-user/access']
.some((path) => requestURL === path || requestURL.endsWith(path))
if (error.response?.status === 401 && !isLoginRequest) {
localStorage.removeItem('clicd_token')
localStorage.removeItem('clicd_username')
window.location.href = '/login'
if (window.location.pathname !== '/login') {
window.location.href = '/login'
}
}
return Promise.reject(error)
}
@@ -548,6 +553,21 @@ export const getWebSSHOriginSettings = () =>
export const updateWebSSHOriginSettings = (origins: string[]) =>
api.put<APIResponse<WebSSHOriginSettings>>('/webssh-origins', { origins })
export interface PanelAccessPolicy {
enabled: boolean
allowed_sources: string[]
trusted_proxies: string[]
current_source: string
direct_source: string
using_forwarded: boolean
}
export const getPanelAccessPolicy = () =>
api.get<APIResponse<PanelAccessPolicy>>('/access-policy')
export const updatePanelAccessPolicy = (data: Pick<PanelAccessPolicy, 'enabled' | 'allowed_sources' | 'trusted_proxies'>) =>
api.put<APIResponse<PanelAccessPolicy>>('/access-policy', data)
// Containers
export const getContainers = () =>
api.get<APIResponse<Container[]>>('/containers')
@@ -717,6 +737,11 @@ export interface IPv6Route {
export interface RoutingInfo {
nat4: RouteCapacity
nat4_port_range: NAT4PortRange
nat4_next_port: number
nat4_networks: {
lxc: NATNetworkInfo
kvm: NATNetworkInfo
}
ipv4: RouteCapacity
lan_dhcp: RouteCapacity
ipv6: RouteCapacity
@@ -774,11 +799,37 @@ export interface ImageInfo {
size_bytes: number
manual_path?: string
desktop?: string
provisioner?: string
custom?: boolean
sha256?: string
}
export interface CustomKVMImageInput {
type: 'lxc' | 'kvm'
name: string
description: string
distro: string
release: string
arch: string
url: string
provisioner?: 'linux-cloud-init' | 'windows-10' | 'windows-11' | 'lxc-rootfs'
sha256?: string
}
export interface CustomKVMImage extends CustomKVMImageInput {
id: string
created_at: string
}
export const getImages = () =>
api.get<APIResponse<ImageInfo[]>>('/images')
export const createCustomKVMImage = (payload: CustomKVMImageInput) =>
api.post<APIResponse<CustomKVMImage>>('/images/custom', payload)
export const removeCustomKVMImage = (id: string) =>
api.delete<APIResponse>('/images/custom', { data: { id } })
export const downloadImage = (templateId: string) =>
api.post<APIResponse>('/images/download', { template_id: templateId })
@@ -923,6 +974,16 @@ export interface SubUser {
created_at: string
}
export interface NATNetworkInfo {
subnet: string
gateway: string
netmask: string
dhcp_start: string
dhcp_end: string
dhcp_max: number
prefix_bits: number
}
export const createSubUser = (containerId: ContainerIdentifier) =>
api.post<APIResponse<SubUser>>('/sub-user/create', { container_name: String(containerId) })