✨ 支持面板配置IP白名单

This commit is contained in:
chaos-zhu
2025-03-29 00:51:53 +08:00
parent 50cca449c6
commit d43e1a3505
7 changed files with 72 additions and 23 deletions
+1
View File
@@ -4,6 +4,7 @@
* 新增服务器定时任务功能(TODO
* 连接服务器下拉菜单分组展示(TODO
* 增加升级更新内容展示(TODO
* 面板支持灵活配置IP白名单
## [3.0.4](https://github.com/chaos-zhu/easynode/releases) (2025-03-15)
+1 -1
View File
@@ -67,7 +67,7 @@ docker run -d -p 8082:8082 --restart=always -v /root/easynode/db:/easynode/app/d
```
环境变量:
- `DEBUG`: 启动debug日志 0:关闭 1:开启, 默认关闭
- `ALLOWED_IPS`: 可以访问服务的IP白名单, 多个使用逗号分隔, 支持填写部分ip前缀, 例如: `-e ALLOWED_IPS=127.0.0.1,196.168`
- `ALLOWED_IPS`: 可以访问服务的IP白名单, 多个使用逗号分隔, 支持填写部分ip前缀,支持在面板设置。例如: `-e ALLOWED_IPS=127.0.0.1,196.168`
## 监控服务安装
+15 -5
View File
@@ -1,17 +1,27 @@
const { LogDB } = require('../utils/db-class')
const { KeyDB, LogDB } = require('../utils/db-class')
const keyDB = new KeyDB().getInstance()
const logDB = new LogDB().getInstance()
let whiteList = process.env.ALLOWED_IPS ? process.env.ALLOWED_IPS.split(',') : []
async function getLog({ res }) {
let list = await logDB.findAsync({})
let { ipWhiteList } = await keyDB.findOneAsync({})
list = list.map(item => {
return { ...item, id: item._id }
})
list?.sort((a, b) => Number(b.date) - Number(a.date))
res.success({ data: { list, whiteList } })
res.success({ data: { list, ipWhiteList } })
}
const saveIpWhiteList = async ({ res, request }) => {
const { body: { ipWhiteList } } = request
console.log('ipWhiteList:', ipWhiteList)
if (!Array.isArray(ipWhiteList)) return res.fail({ msg: 'ip list输入非法' })
let { _id } = await keyDB.findOneAsync({})
await keyDB.updateAsync({ _id }, { $set: { ipWhiteList } })
res.success({ msg: 'success' })
}
module.exports = {
getLog
getLog,
saveIpWhiteList
}
+12 -2
View File
@@ -5,8 +5,18 @@ const { KeyDB, GroupDB, NotifyDB, NotifyConfigDB, ScriptGroupDB } = require('./u
async function initKeyDB() {
const keyDB = new KeyDB().getInstance()
let count = await keyDB.countAsync({})
if (count !== 0) return consola.info('公私钥已存在[重新生成会导致已保存的ssh密钥信息失效]')
let keyData = await keyDB.findOneAsync({})
if (keyData?.user) {
const { _id, ipWhiteList } = keyData
let allowedIPs = process.env.ALLOWED_IPS ? process.env.ALLOWED_IPS.split(',') : []
if (allowedIPs.length > 0) {
consola.info('[存在白名单IP环境变量,合并到本地数据库中]')
allowedIPs = [...new Set([...ipWhiteList, ...allowedIPs])].filter(item => item)
await keyDB.updateAsync({ _id }, { $set: { ipWhiteList: allowedIPs } })
}
consola.info('公私钥已存在[重新生成会导致已保存的ssh密钥信息失效]')
return
}
let newConfig = {
user: 'admin',
pwd: 'admin',
+6 -1
View File
@@ -6,7 +6,7 @@ const { getGroupList, addGroupList, updateGroupList, removeGroup } = require('..
const { getScriptList, getLocalScriptList, addScript, updateScriptList, removeScript, batchRemoveScript, importScript } = require('../controller/scripts')
const { getScriptGroupList, addScriptGroup, removeScriptGroup, updateScriptGroup } = require('../controller/script-group')
const { getOnekeyRecord, removeOnekeyRecord } = require('../controller/onekey')
const { getLog } = require('../controller/log')
const { getLog, saveIpWhiteList } = require('../controller/log')
const ssh = [
{
@@ -259,6 +259,11 @@ const log = [
method: 'get',
path: '/log',
controller: getLog
},
{
method: 'post',
path: '/ip-white-list',
controller: saveIpWhiteList
}
]
module.exports = [].concat(ssh, host, user, notify, group, scripts, scriptGroup, onekey, log)
+3
View File
@@ -58,6 +58,9 @@ export default {
getLoginRecord() {
return axios({ url: '/log', method: 'get' })
},
saveIpWhiteList(data) {
return axios({ url: '/ip-white-list', method: 'post', data })
},
updatePwd(data) {
return axios({ url: '/pwd', method: 'put', data })
},
+34 -14
View File
@@ -1,15 +1,21 @@
<template>
<el-alert v-if="allowedIPs" type="success" :closable="false">
<el-alert type="success" :closable="false">
<template #title>
<span style="letter-spacing: 2px;"> 登录白名单IP: </span>
<el-tag
v-for="(item, index) in allowedIPs"
:key="index"
class="allowed_ip_tag"
type="warning"
>
{{ item }}
</el-tag>
<span style="letter-spacing: 2px;"> 登录白名单IP设置: </span>
<el-tooltip placement="top">
<template #content>
<div class="ip_tips">
IP地址为包含匹配, 如输入: 192.168则匹配IP地址包含192.168的所有IP
</div>
</template>
<el-icon >
<InfoFilled />
</el-icon>
</el-tooltip>
<el-input-tag v-model="allowedIPs" tag-type="success" tag-effect="plain">
</el-input-tag>
<el-button style="margin-top: 6px;" type="success" :loading="btnLoading"
@click="handleSaveAllowedIPs">保存</el-button>
</template>
</el-alert>
<el-table v-loading="loading" :data="loginRecordList">
@@ -25,21 +31,23 @@
<script setup>
import { ref, onMounted, getCurrentInstance } from 'vue'
import { InfoFilled } from '@element-plus/icons-vue'
const { proxy: { $api, $tools } } = getCurrentInstance()
const { proxy: { $api, $tools, $message } } = getCurrentInstance()
const loginRecordList = ref([])
const loading = ref(false)
const btnLoading = ref(false)
const total = ref('')
const allowedIPs = ref('')
const allowedIPs = ref([])
const handleLookupLoginRecord = () => {
loading.value = true
$api.getLoginRecord()
.then(({ data }) => {
const { list, whiteList } = data
const { list, ipWhiteList } = data
total.value = list.length
allowedIPs.value = whiteList || []
allowedIPs.value = ipWhiteList || []
loginRecordList.value = list.map((item) => {
item.date = $tools.formatTimestamp(item.date)
return item
@@ -50,6 +58,18 @@ const handleLookupLoginRecord = () => {
})
}
const handleSaveAllowedIPs = async () => {
btnLoading.value = true
const ipWhiteList = [...new Set(allowedIPs.value)].filter(item => item)
try {
await $api.saveIpWhiteList({ ipWhiteList })
handleLookupLoginRecord()
$message.success('success')
} finally {
btnLoading.value = false
}
}
onMounted(() => {
handleLookupLoginRecord()
})