4c8b7b5188
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 四
66 lines
2.6 KiB
JavaScript
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 |