Files
openvpn-manager/frontend/src/api/index.js
T
cnbugs 4c8b7b5188 Add per-instance/user access whitelist
Features:
- New Instance.AccessMode: "open" (default) or "whitelist"
- New Instance.AllowNetworks + VPNUser.AllowNetworks: list of CIDRs
- Effective whitelist = instance allow_networks ∪ user allow_networks (dedup)
- Auto-generates client-connect.sh / client-disconnect.sh for OpenVPN:
    * Reads ccd/<cn> to extract CIDRs
    * Pushes "route <ip> <mask>" to client (client side)
    * Inserts iptables ACCEPT rules in FORWARD chain (server side, defense in depth)
    * Cleans up rules on disconnect
- server.conf auto-includes client-connect / client-disconnect directives
  and push "redirect-gateway def1 bypass-dhcp" in whitelist mode
- ccd/<cn> file format: first line ifconfig-push (static IP), then one CIDR per line
- Editing instance allow_networks refreshes all users' ccd automatically
- New PUT /api/instances/:id/users/:uid endpoint
- CIDR format validation; reject malformed inputs with friendly errors
- Dashboard shows whitelist_instances count and per-instance allow_networks table

Docs:
- README: new section "三、访问控制(白名单模式)" with usage, validation, pitfalls
- docs/API.md: updated Instance / VPNUser model + create/update payloads
- Renumbered client usage section as 四
2026-08-09 20:47:21 +08:00

66 lines
2.6 KiB
JavaScript

import axios from 'axios'
import { ElMessage } from 'element-plus'
import router from '@/router'
const api = axios.create({ baseURL: '/api', timeout: 30000 })
api.interceptors.request.use(cfg => {
const t = localStorage.getItem('token')
if (t) cfg.headers.Authorization = `Bearer ${t}`
return cfg
})
api.interceptors.response.use(
r => r,
err => {
if (err.response?.status === 401) {
localStorage.removeItem('token')
if (router.currentRoute.value.path !== '/login') {
router.replace('/login')
}
} else {
ElMessage.error(err.response?.data?.error || err.message || '请求失败')
}
return Promise.reject(err)
}
)
export const Auth = {
login: (username, password) => api.post('/login', { username, password }).then(r => r.data),
me: () => api.get('/me').then(r => r.data),
logout: () => api.post('/logout').then(r => r.data),
}
export const Dash = {
get: () => api.get('/dashboard').then(r => r.data),
}
export const Inst = {
list: () => api.get('/instances').then(r => r.data),
get: id => api.get(`/instances/${id}`).then(r => r.data),
create: data => api.post('/instances', data).then(r => r.data),
update: (id, data) => api.put(`/instances/${id}`, data).then(r => r.data),
delete: id => api.delete(`/instances/${id}`).then(r => r.data),
start: id => api.post(`/instances/${id}/start`).then(r => r.data),
stop: id => api.post(`/instances/${id}/stop`).then(r => r.data),
online: id => api.get(`/instances/${id}/online`).then(r => r.data),
listUsers: id => api.get(`/instances/${id}/users`).then(r => r.data),
createUser: (id, data) => api.post(`/instances/${id}/users`, data).then(r => r.data),
updateUser: (id, uid, data) => api.put(`/instances/${id}/users/${uid}`, data).then(r => r.data),
revokeUser: (id, uid) => api.post(`/instances/${id}/users/${uid}/revoke`).then(r => r.data),
deleteUser: (id, uid) => api.delete(`/instances/${id}/users/${uid}`).then(r => r.data),
ovpnUrl: (id, uid, host) => `/api/instances/${id}/users/${uid}/ovpn?host=${encodeURIComponent(host||'')}`,
}
export const Certs = {
list: () => api.get('/certs').then(r => r.data),
}
export const Logs = {
conns: instanceId => api.get('/connlogs', { params: { instance: instanceId || '' }}).then(r => r.data),
audits: () => api.get('/audits').then(r => r.data),
}
export const Backup = {
list: () => api.get('/backups').then(r => r.data),
create: note => api.post('/backups', { note }).then(r => r.data),
restore: id => api.post(`/backups/${id}/restore`).then(r => r.data),
delete: id => api.delete(`/backups/${id}`).then(r => r.data),
}
export default api