update readme;

optimize logic code;
This commit is contained in:
杨黄林
2023-09-17 11:35:06 +08:00
parent 7c30c6d150
commit 59af75a785
12 changed files with 233 additions and 190 deletions

View File

@@ -36,62 +36,60 @@ frp version >= v0.31.0
### Usage ### Usage
1. Create file `frps-panel.ini` including all support usernames and tokens. 1. Create file `frps-panel.toml` including common config.
```ini ```toml
#frps-panel.toml
[common] [common]
;plugin listen ip # frps panel config info
plugin_addr = 127.0.0.1 plugin_addr = "127.0.0.1" #aadr
;plugin listen port
plugin_port = 7200 plugin_port = 7200
;the username of manage ui,optional #admin_user = "admin"
admin_user = admin #admin_pwd = "admin"
;the password of manage ui,optional # specified login state keep time
admin_pwd = admin
;specified login state keep time in seconds.0 - before the browser completely exit, don't need to re-login,greater than 0: when Idle time exceeds this value,you should re-login
admin_keep_time = 0 admin_keep_time = 0
; enable tls # enable tls
tls_mode = false tls_mode = false
; tls_cert_file = cert.crt # tls_cert_file = cert.crt
; tls_key_file = cert.key # tls_key_file = cert.key
; frp dashboard info # frp dashboard info
dashboard_addr = 127.0.0.1 dashboard_addr = "127.0.0.1"
dashboard_port = 7500 dashboard_port = 7500
dashboard_user = admin dashboard_user = "admin"
dashboard_pwd = admin dashboard_pwd = "admin"
[users]
;user user1 with meta_token 123
user1 = 123
;user user2 with meta_token abc
user2 = abc
[ports]
;user1 can only use ports 8080,9090 to 9010 ,other ports will fail to create proxy (frpc can normally startup)
user1=8080,9090-9010
[domains]
;user1 can only use domain web01.user1.com ,other domain will fail to create proxy (frpc can normally startup)
user1=web01.user1.com
[subdomains]
;user1 can only use subdomain web01 ,other subdomain will fail to create proxy (frpc can normally startup)
user1=web01
[disabled]
;user2 is disabled,when frpc use this user to connect with frps,if frpc is not startup,it cannot startup,if it's already startup,it will always show error logs on console
user2 = disable
``` ```
One user each line. Username and token are split by `=`. 2. Create file `frps-tokens.toml` to save users,it should be the same place with `frps-panel.toml`.this file will auto create by system.
2. Run frps-panel: ```toml
#frps-tokens.toml
[tokens]
[tokens.user1]
user = "user1"
token = "token1"
comment = "user1 with token1"
ports = [8080, "10000-10200"]
domains = ["web01.domain.com", "web02.domain.com"]
subdomains = ["web01", "web02"]
enable = true
[tokens.user2]
user = "user2"
token = "token2"
comment = "user2 with token2"
ports = [9080]
domains = ["web11.domain.com", "web12.domain.com"]
subdomains = ["web11", "web12"]
enable = false
```
`./frps-panel -c ./frps-panel.ini`
3. Register plugin in frps. 3. Run frps-panel:
`./frps-panel -c ./frps-panel.toml`
4. Register plugin in frps.
```ini ```ini
# frps.ini # frps.ini
@@ -105,7 +103,7 @@ path = /handler
ops = Login,NewWorkConn,NewUserConn,NewProxy,Ping ops = Login,NewWorkConn,NewUserConn,NewProxy,Ping
``` ```
4. Specify username and meta_token in frpc configure file. 5. Specify username and meta_token in frpc configure file.
For user1: For user1:
@@ -139,7 +137,7 @@ local_port = 22
remote_port = 6000 remote_port = 6000
``` ```
5. Manage your users in browser via: http://127.0.0.1:7200 or https://127.0.0.1:7200 6. Manage your users in browser via: http://127.0.0.1:7200 or https://127.0.0.1:7200
## Run as service ## Run as service
@@ -155,8 +153,8 @@ Wants = network.target
[Service] [Service]
Type = simple Type = simple
# config of frps-panel.ini,you should change the file path # config of frps-panel.toml,you should change the file path
Environment=FRPS_PANEL_OPTS="-c /root/frps-panel/frps-panel.ini" Environment=FRPS_PANEL_OPTS="-c /root/frps-panel/frps-panel.toml"
# command of run frps-panel,you should change the file path # command of run frps-panel,you should change the file path
ExecStart = /root/frps-panel/frps-panel $FRPS_PANEL_OPTS ExecStart = /root/frps-panel/frps-panel $FRPS_PANEL_OPTS

View File

@@ -37,63 +37,59 @@ frps-panel 会以一个单独的进程运行,并接收 frps 发送过来的 HT
### 使用示例 ### 使用示例
1. 创建 `frps-panel.ini` 文件,内容为所有支持的用户名和 token 1. 创建 `frps-panel.toml` 文件,内容为基础配置
```ini ```toml
# frps-panel.toml
[common] [common]
;插件监听地址 # frps panel config info
;如果上面配置中 tls_mode = true, 则把plugin_addr的值改为 https://127.0.0.1:7200 plugin_addr = "127.0.0.1" #aadr
plugin_addr = 127.0.0.1
;插件端口
plugin_port = 7200 plugin_port = 7200
;插件管理页面账号,可选 #admin_user = "admin"
admin_user = admin #admin_pwd = "admin"
;插件管理页面密码,与账号一起进行鉴权,可选 # specified login state keep time
admin_pwd = admin
;登录状态空闲时间(秒):0-浏览器完全退出前不用重新登录,大于0-空闲超过此时间则需要重新登录.
admin_keep_time = 0 admin_keep_time = 0
; frps 面板页面是否启用https访问,如果为true,则只能通过https访问 # enable tls
tls_mode = false tls_mode = false
; tls_cert_file = cert.crt # tls_cert_file = cert.crt
; tls_key_file = cert.key # tls_key_file = cert.key
; frp服务器的看板页面信息必须配置且与frp服务器一致否则无法获取服务器信息 # frp dashboard info
dashboard_addr = 127.0.0.1 dashboard_addr = "127.0.0.1"
dashboard_port = 7500 dashboard_port = 7500
dashboard_user = admin dashboard_user = "admin"
dashboard_pwd = admin dashboard_pwd = "admin"
[users]
;user1的meta_token为123
user1 = 123
;user2的meta_token为abc
user2 = abc
[ports]
;user1只能使用8080,9090到9010端口,其他端口则建立连接时返回失败(不影响客户端启动)
user1=8080,9090-9010
[domains]
;user1只能使用web01.yyy.zzz域名,配置了其他域名则建立连接时返回失败(不影响客户端启动)
user1=web01.user1.com
[subdomains]
;user1只能使用web01.xxx.yyy.zzz域名,配置了其他三级域名则建立连接时返回失败(不影响客户端启动)
user1=web01
[disabled]
;user2被禁用,frpc使用此账户与frps通信时,如果未启动则无法启动,如果已启动,则会一直打印错误日志
user2 = disable
``` ```
每一个用户占一行,用户名和 token 之间以 `=` 号分隔 2. 创建`frps-tokens.toml`文件,其内容为系统中的用户,该文件位置和`frps-panel.toml`相同。如不创建此文件,在增加用户时会自动创建
2. 运行 frps-panel指定监听地址以及 token 存储文件路径。 ```toml
#frps-tokens.toml
[tokens]
[tokens.user1]
user = "user1"
token = "token1"
comment = "user1 with token1"
ports = [8080, "10000-10200"]
domains = ["web01.domain.com", "web02.domain.com"]
subdomains = ["web01", "web02"]
enable = true
[tokens.user2]
user = "user2"
token = "token2"
comment = "user2 with token2"
ports = [9080]
domains = ["web11.domain.com", "web12.domain.com"]
subdomains = ["web11", "web12"]
enable = false
```
`./frps-panel -c ./frps-panel.ini` 3. 运行 frps-panel,指定监听地址以及 token 存储文件路径。
3. 在 frps 的配置文件中注册插件,并启动。 `./frps-panel -c ./frps-panel.toml`
4. 在 frps 的配置文件中注册插件,并启动。
```ini ```ini
# frps.ini # frps.ini
@@ -106,7 +102,7 @@ path = /handler
ops = Login,NewWorkConn,NewUserConn,NewProxy,Ping ops = Login,NewWorkConn,NewUserConn,NewProxy,Ping
``` ```
4. 在 frpc 中指定用户名,在 meta 中指定 token用户名以及 `meta_token` 的内容需要和之前创建的 token 文件匹配。 5. 在 frpc 中指定用户名,在 meta 中指定 token用户名以及 `meta_token` 的内容需要和之前创建的 token 文件匹配。
user1 的配置: user1 的配置:
@@ -140,7 +136,7 @@ local_port = 22
remote_port = 6000 remote_port = 6000
``` ```
5.浏览器中输入地址: http://127.0.0.1:7200 或 https://127.0.0.1:7200 进入管理页面进行用户管理 6.浏览器中输入地址: http://127.0.0.1:7200 或 https://127.0.0.1:7200 进入管理页面进行用户管理
## 以服务的形式运行 ## 以服务的形式运行
@@ -156,8 +152,8 @@ Wants = network.target
[Service] [Service]
Type = simple Type = simple
# 启动frps-panel的配置文件路径需修改为您的frps-panel.ini的路径 # 启动frps-panel的配置文件路径需修改为您的frps-panel.toml的路径
Environment=FRPS_PANEL_OPTS="-c /root/frps-panel/frps-panel.ini" Environment=FRPS_PANEL_OPTS="-c /root/frps-panel/frps-panel.toml"
# 启动frps-panel的命令需修改为您的frps-panel的安装路径 # 启动frps-panel的命令需修改为您的frps-panel的安装路径
ExecStart = /root/frps-panel/frps-panel $FRPS_PANEL_OPTS ExecStart = /root/frps-panel/frps-panel $FRPS_PANEL_OPTS

View File

@@ -50,7 +50,7 @@
background-color: #79bbff; background-color: #79bbff;
} }
.layui-form-checkbox[lay-skin=primary]>.layui-icon-indeterminate{ .layui-form-checkbox[lay-skin=primary] > .layui-icon-indeterminate {
border-color: #79bbff; border-color: #79bbff;
} }
@@ -71,6 +71,11 @@
border-color: #79bbff; border-color: #79bbff;
} }
.layui-table-checked.layui-table-click,
.layui-table-checked.layui-table-hover {
background-color: #d9ecff;
}
.layui-nav-tree .layui-nav-child dd.layui-this, .layui-nav-tree .layui-nav-child dd.layui-this,
.layui-nav-tree .layui-nav-child dd.layui-this a, .layui-nav-tree .layui-nav-child dd.layui-this a,
.layui-nav-tree .layui-this, .layui-nav-tree .layui-this,
@@ -185,7 +190,7 @@ section.proxy-list .proxy-info .layui-row .layui-row > div:first-child {
background-color: #5f5f60; background-color: #5f5f60;
} }
.layui-form-checkbox[lay-skin=primary]>.layui-icon-indeterminate{ .layui-form-checkbox[lay-skin=primary] > .layui-icon-indeterminate {
border-color: #5f5f60; border-color: #5f5f60;
} }
@@ -206,6 +211,11 @@ section.proxy-list .proxy-info .layui-row .layui-row > div:first-child {
border-color: #5f5f60; border-color: #5f5f60;
} }
.layui-table-checked.layui-table-click,
.layui-table-checked.layui-table-hover {
background-color: #5f5f60;
}
.layui-nav-tree .layui-nav-child dd.layui-this, .layui-nav-tree .layui-nav-child dd.layui-this,
.layui-nav-tree .layui-nav-child dd.layui-this a, .layui-nav-tree .layui-nav-child dd.layui-this a,
.layui-nav-tree .layui-this, .layui-nav-tree .layui-this,

View File

@@ -97,7 +97,7 @@ var loadUserList = (function ($) {
} }
return { return {
valid: valid, valid: valid,
trim: username trim: username.trim()
}; };
} }
@@ -129,7 +129,7 @@ var loadUserList = (function ($) {
} }
return { return {
valid: valid, valid: valid,
trim: comment.replace(/[\n\t\r]/g, '') trim: comment.trim().replace(/[\n\t\r]/g, '')
}; };
} }
@@ -227,7 +227,7 @@ var loadUserList = (function ($) {
* set verify rule of layui.form * set verify rule of layui.form
*/ */
(function setFormVerifyRule() { (function setFormVerifyRule() {
// layui.form.verify(verifyRules); layui.form.verify(verifyRules);
})(); })();
/** /**
@@ -265,10 +265,10 @@ var loadUserList = (function ($) {
{field: 'domains', title: i18n['AllowedDomains'], sort: true, edit: 'textarea'}, {field: 'domains', title: i18n['AllowedDomains'], sort: true, edit: 'textarea'},
{field: 'subdomains', title: i18n['AllowedSubdomains'], sort: true, edit: 'textarea'}, {field: 'subdomains', title: i18n['AllowedSubdomains'], sort: true, edit: 'textarea'},
{ {
field: 'status', field: 'enable',
title: i18n['Status'], title: i18n['Status'],
width: 100, width: 100,
templet: '<span>{{d.status? "' + i18n['Enable'] + '":"' + i18n['Disable'] + '"}}</span>', templet: '<span>{{d.enable? "' + i18n['Enable'] + '":"' + i18n['Disable'] + '"}}</span>',
sort: true sort: true
}, },
{title: i18n['Operation'], width: 150, toolbar: '#userListOperationTemplate'} {title: i18n['Operation'], width: 150, toolbar: '#userListOperationTemplate'}
@@ -371,6 +371,12 @@ var loadUserList = (function ($) {
data.forEach(function (temp) { data.forEach(function (temp) {
temp.ports = temp.ports.split(',') temp.ports = temp.ports.split(',')
temp.ports.forEach(function (port, index) {
if (/^\d+$/.test(String(port))) {
temp.ports[index] = parseInt(String(port));
}
});
temp.domains = temp.domains.split(',') temp.domains = temp.domains.split(',')
temp.subdomains = temp.subdomains.split(',') temp.subdomains = temp.subdomains.split(',')
}); });
@@ -395,6 +401,11 @@ var loadUserList = (function ($) {
var data = obj.data; var data = obj.data;
data.ports = data.ports.split(',') data.ports = data.ports.split(',')
data.ports.forEach(function (port, index) {
if (/^\d+$/.test(String(port))) {
data.ports[index] = parseInt(String(port));
}
});
data.domains = data.domains.split(',') data.domains = data.domains.split(',')
data.subdomains = data.subdomains.split(',') data.subdomains = data.subdomains.split(',')
switch (obj.event) { switch (obj.event) {
@@ -438,6 +449,11 @@ var loadUserList = (function ($) {
var formData = layui.form.val('addUserForm'); var formData = layui.form.val('addUserForm');
if (formData.ports != null) { if (formData.ports != null) {
formData.ports = formData.ports.split(',') formData.ports = formData.ports.split(',')
formData.ports.forEach(function (port, index) {
if (/^\d+$/.test(String(port))) {
formData.ports[index] = parseInt(String(port));
}
})
} }
if (formData.domains != null) { if (formData.domains != null) {
formData.domains = formData.domains.split(',') formData.domains = formData.domains.split(',')
@@ -456,7 +472,7 @@ var loadUserList = (function ($) {
/** /**
* add user action * add user action
* @param data {{user:string, token:string, comment:string, status:boolean, ports:[string], domains:[string], subdomains:[string]}} user data * @param data {{user:string, token:string, comment:string, enable:boolean, ports:[string|number], domains:[string], subdomains:[string]}} user data
* @param index popup index * @param index popup index
*/ */
function add(data, index) { function add(data, index) {
@@ -485,10 +501,20 @@ var loadUserList = (function ($) {
/** /**
* update user action * update user action
* @param before {{user:string, token:string, comment:string, status:boolean, ports:[string], domains:[string], subdomains:[string]}} data before update * @param before {{user:string, token:string, comment:string, enable:boolean, ports:[string|number], domains:[string], subdomains:[string]}} data before update
* @param after {{user:string, token:string, comment:string, status:boolean, ports:[string], domains:[string], subdomains:[string]}} data after update * @param after {{user:string, token:string, comment:string, enable:boolean, ports:[string|number], domains:[string], subdomains:[string]}} data after update
*/ */
function update(before, after) { function update(before, after) {
before.ports.forEach(function (port, index) {
if (/^\d+$/.test(String(port))) {
before.ports[index] = parseInt(String(port));
}
});
after.ports.forEach(function (port, index) {
if (/^\d+$/.test(String(port)) && typeof port === "string") {
after.ports[index] = parseInt(String(port));
}
});
var loading = layui.layer.load(); var loading = layui.layer.load();
$.ajax({ $.ajax({
url: '/update', url: '/update',
@@ -513,7 +539,7 @@ var loadUserList = (function ($) {
/** /**
* batch remove user popup * batch remove user popup
* @param data {[{user:string, token:string, comment:string, status:boolean, ports:[string], domains:[string], subdomains:[string]}]} user data list * @param data {[{user:string, token:string, comment:string, enable:boolean, ports:[string|number], domains:[string], subdomains:[string]}]} user data list
*/ */
function batchRemovePopup(data) { function batchRemovePopup(data) {
if (data.length === 0) { if (data.length === 0) {
@@ -530,7 +556,7 @@ var loadUserList = (function ($) {
/** /**
* batch disable user popup * batch disable user popup
* @param data {[{user:string, token:string, comment:string, status:boolean, ports:[string], domains:[string], subdomains:[string]}]} user data list * @param data {[{user:string, token:string, comment:string, enable:boolean, ports:[string|number], domains:[string], subdomains:[string]}]} user data list
*/ */
function batchDisablePopup(data) { function batchDisablePopup(data) {
if (data.length === 0) { if (data.length === 0) {
@@ -547,7 +573,7 @@ var loadUserList = (function ($) {
/** /**
* batch enable user popup * batch enable user popup
* @param data {[{user:string, token:string, comment:string, status:boolean, ports:[string], domains:[string], subdomains:[string]}]} user data list * @param data {[{user:string, token:string, comment:string, enable:boolean, ports:[string|number], domains:[string], subdomains:[string]}]} user data list
*/ */
function batchEnablePopup(data) { function batchEnablePopup(data) {
if (data.length === 0) { if (data.length === 0) {
@@ -564,7 +590,7 @@ var loadUserList = (function ($) {
/** /**
* remove one user popup * remove one user popup
* @param data {{user:string, token:string, comment:string, status:boolean, ports:[string], domains:[string], subdomains:[string]}} user data * @param data {{user:string, token:string, comment:string, enable:boolean, ports:[string|number], domains:[string], subdomains:[string]}} user data
*/ */
function removePopup(data) { function removePopup(data) {
layui.layer.confirm(i18n['ConfirmRemoveUser'], { layui.layer.confirm(i18n['ConfirmRemoveUser'], {
@@ -577,7 +603,7 @@ var loadUserList = (function ($) {
/** /**
* disable one user popup * disable one user popup
* @param data {{user:string, token:string, comment:string, status:boolean, ports:[string], domains:[string], subdomains:[string]}} user data * @param data {{user:string, token:string, comment:string, enable:boolean, ports:[string|number], domains:[string], subdomains:[string]}} user data
*/ */
function disablePopup(data) { function disablePopup(data) {
layui.layer.confirm(i18n['ConfirmDisableUser'], { layui.layer.confirm(i18n['ConfirmDisableUser'], {
@@ -590,7 +616,7 @@ var loadUserList = (function ($) {
/** /**
* enable one user popup * enable one user popup
* @param data {{user:string, token:string, comment:string, status:boolean, ports:[string], domains:[string], subdomains:[string]}} user data * @param data {{user:string, token:string, comment:string, enable:boolean, ports:[string|number], domains:[string], subdomains:[string]}} user data
*/ */
function enablePopup(data) { function enablePopup(data) {
layui.layer.confirm(i18n['ConfirmEnableUser'], { layui.layer.confirm(i18n['ConfirmEnableUser'], {
@@ -604,7 +630,7 @@ var loadUserList = (function ($) {
/** /**
* operate actions * operate actions
* @param type {apiType} action type * @param type {apiType} action type
* @param data {[{user:string, token:string, comment:string, status:boolean, ports:[string], domains:[string], subdomains:[string]}]} user data list * @param data {[{user:string, token:string, comment:string, enable:boolean, ports:[string|number], domains:[string], subdomains:[string]}]} user data list
* @param index popup index * @param index popup index
*/ */
function operate(type, data, index) { function operate(type, data, index) {

View File

@@ -2,17 +2,17 @@
<html lang="en"> <html lang="en">
<head> <head>
<title>${ .FrpsPanel }</title> <title>${ .FrpsPanel }</title>
<link rel="stylesheet" href="./static/lib/layui/css/layui.css"> <link rel="stylesheet" href="./static/lib/layui/css/layui.css?v=${ .version }">
<link rel="stylesheet" href="./static/css/layui-theme-dark.css"> <link rel="stylesheet" href="./static/css/layui-theme-dark.css?v=${ .version }">
<link rel="stylesheet" href="./static/css/index.css"> <link rel="stylesheet" href="./static/css/index.css?v=${ .version }">
<link rel="stylesheet" href="./static/css/color.css"> <link rel="stylesheet" href="./static/css/color.css?v=${ .version }">
<script src="./static/lib/layui/layui.js"></script> <script src="./static/lib/layui/layui.js?v=${ .version }"></script>
<script src="./static/lib/echarts.min.js"></script> <script src="./static/lib/echarts.min.js?v=${ .version }"></script>
<script src="./static/lib/filesize.min.js"></script> <script src="./static/lib/filesize.min.js?v=${ .version }"></script>
<script src="./static/js/index-server-info.js"></script> <script src="./static/js/index-server-info.js?v=${ .version }"></script>
<script src="./static/js/index-user-list.js"></script> <script src="./static/js/index-user-list.js?v=${ .version }"></script>
<script src="./static/js/index-proxy-list.js"></script> <script src="./static/js/index-proxy-list.js?v=${ .version }"></script>
<script src="./static/js/index.js"></script> <script src="./static/js/index.js?v=${ .version }"></script>
<style> <style>
section.user-list .layui-table-cell:empty::after { section.user-list .layui-table-cell:empty::after {
content: '${ .NotLimit }'; content: '${ .NotLimit }';
@@ -214,7 +214,7 @@
<script type="text/html" id="userListOperationTemplate"> <script type="text/html" id="userListOperationTemplate">
<div class="layui-clear-space"> <div class="layui-clear-space">
<a class="layui-btn layui-btn-xs" lay-event="remove">${ .Remove }</a> <a class="layui-btn layui-btn-xs" lay-event="remove">${ .Remove }</a>
{{# if (d.status) { }} {{# if (d.enable) { }}
<a class="layui-btn layui-btn-xs" lay-event="disable">${ .Disable }</a> <a class="layui-btn layui-btn-xs" lay-event="disable">${ .Disable }</a>
{{# } else { }} {{# } else { }}
<a class="layui-btn layui-btn-xs" lay-event="enable">${ .Enable }</a> <a class="layui-btn layui-btn-xs" lay-event="enable">${ .Enable }</a>

View File

@@ -2,12 +2,12 @@
<html lang=""> <html lang="">
<head> <head>
<title>Login</title> <title>Login</title>
<link rel="stylesheet" href="./static/lib/layui/css/layui.css"> <link rel="stylesheet" href="./static/lib/layui/css/layui.css?v=${ .version }">
<link rel="stylesheet" href="./static/css/layui-theme-dark.css"> <link rel="stylesheet" href="./static/css/layui-theme-dark.css?v=${ .version }">
<link rel="stylesheet" href="./static/css/color.css"> <link rel="stylesheet" href="./static/css/color.css?v=${ .version }">
<link rel="stylesheet" href="./static/css/login.css"> <link rel="stylesheet" href="./static/css/login.css?v=${ .version }">
<script src="./static/lib/layui/layui.js"></script> <script src="./static/lib/layui/layui.js?v=${ .version }"></script>
<script src="./static/js/login.js"></script> <script src="./static/js/login.js?v=${ .version }"></script>
</head> </head>
<body> <body>
<div class="login-title"> <div class="login-title">

View File

@@ -1,6 +1,7 @@
package main package main
import ( import (
"errors"
"frps-panel/pkg/server" "frps-panel/pkg/server"
"frps-panel/pkg/server/controller" "frps-panel/pkg/server/controller"
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
@@ -11,7 +12,7 @@ import (
"strings" "strings"
) )
const version = "1.6.0" const version = "1.7.0"
var ( var (
showVersion bool showVersion bool
@@ -79,8 +80,12 @@ func parseConfigFile(configFile, tokensFile string) (controller.HandleController
_, err = toml.DecodeFile(tokensFile, &tokens) _, err = toml.DecodeFile(tokensFile, &tokens)
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) {
tokens = controller.Tokens{Tokens: make(map[string]controller.TokenInfo)}
} else {
log.Fatalf("decode token file %v error: %v", tokensFile, err) log.Fatalf("decode token file %v error: %v", tokensFile, err)
} }
}
common.Common.DashboardTls = strings.HasPrefix("https://", strings.ToLower(common.Common.DashboardAddr)) common.Common.DashboardTls = strings.HasPrefix("https://", strings.ToLower(common.Common.DashboardAddr))

View File

@@ -1,17 +0,0 @@
[tokens]
[tokens.user1]
user = "user1"
token = "token1"
comment = "张三"
ports = [""]
domains = [""]
subdomains = [""]
status = true
[tokens.user2]
user = "user2"
token = "token2"
comment = "李四"
ports = [""]
domains = [""]
subdomains = [""]
status = true

View File

@@ -290,7 +290,7 @@ func (c *HandleController) MakeQueryTokensFunc() func(context *gin.Context) {
func (c *HandleController) MakeAddTokenFunc() func(context *gin.Context) { func (c *HandleController) MakeAddTokenFunc() func(context *gin.Context) {
return func(context *gin.Context) { return func(context *gin.Context) {
info := TokenInfo{ info := TokenInfo{
Status: true, Enable: true,
} }
response := OperationResponse{ response := OperationResponse{
Success: true, Success: true,
@@ -315,7 +315,7 @@ func (c *HandleController) MakeAddTokenFunc() func(context *gin.Context) {
} }
info.Comment = cleanString(info.Comment) info.Comment = cleanString(info.Comment)
info.Ports = cleanStrings(info.Ports) info.Ports = cleanPorts(info.Ports)
info.Domains = cleanStrings(info.Domains) info.Domains = cleanStrings(info.Domains)
info.Subdomains = cleanStrings(info.Subdomains) info.Subdomains = cleanStrings(info.Subdomains)
@@ -373,7 +373,7 @@ func (c *HandleController) MakeUpdateTokensFunc() func(context *gin.Context) {
} }
after.Comment = cleanString(after.Comment) after.Comment = cleanString(after.Comment)
after.Ports = cleanStrings(after.Ports) after.Ports = cleanPorts(after.Ports)
after.Domains = cleanStrings(after.Domains) after.Domains = cleanStrings(after.Domains)
after.Subdomains = cleanStrings(after.Subdomains) after.Subdomains = cleanStrings(after.Subdomains)
@@ -467,7 +467,7 @@ func (c *HandleController) MakeDisableTokensFunc() func(context *gin.Context) {
for _, user := range disable.Users { for _, user := range disable.Users {
token := c.Tokens[user.User] token := c.Tokens[user.User]
token.Status = false token.Enable = false
c.Tokens[user.User] = token c.Tokens[user.User] = token
} }
@@ -515,7 +515,7 @@ func (c *HandleController) MakeEnableTokensFunc() func(context *gin.Context) {
for _, user := range enable.Users { for _, user := range enable.Users {
token := c.Tokens[user.User] token := c.Tokens[user.User]
token.Status = true token.Enable = true
c.Tokens[user.User] = token c.Tokens[user.User] = token
} }

View File

@@ -50,7 +50,7 @@ func (c *HandleController) JudgeToken(user string, token string) plugin.Response
res.Reject = true res.Reject = true
res.RejectReason = "user or meta token can not be empty" res.RejectReason = "user or meta token can not be empty"
} else if info, exist := c.Tokens[user]; exist { } else if info, exist := c.Tokens[user]; exist {
if !info.Status { if !info.Enable {
res.Reject = true res.Reject = true
res.RejectReason = fmt.Sprintf("user [%s] is disabled", user) res.RejectReason = fmt.Sprintf("user [%s] is disabled", user)
} else { } else {
@@ -77,7 +77,6 @@ func (c *HandleController) JudgePort(content *plugin.NewProxyContent) plugin.Res
"tcp", "tcpmux", "udp", "http", "https", "tcp", "tcpmux", "udp", "http", "https",
} }
proxyType := content.ProxyType proxyType := content.ProxyType
if stringContains(proxyType, supportProxyTypes) { if stringContains(proxyType, supportProxyTypes) {
log.Printf("proxy type [%v] not support, plugin do nothing", proxyType) log.Printf("proxy type [%v] not support, plugin do nothing", proxyType)
res.Unchange = true res.Unchange = true
@@ -94,8 +93,9 @@ func (c *HandleController) JudgePort(content *plugin.NewProxyContent) plugin.Res
portAllowed = false portAllowed = false
if token, exist := c.Tokens[user]; exist { if token, exist := c.Tokens[user]; exist {
for _, port := range token.Ports { for _, port := range token.Ports {
if strings.Contains(port, "-") { if str, ok := port.(string); ok {
allowedRanges := strings.Split(port, "-") if strings.Contains(str, "-") {
allowedRanges := strings.Split(str, "-")
if len(allowedRanges) != 2 { if len(allowedRanges) != 2 {
portErr = fmt.Errorf("user [%v] port range [%v] format error", user, port) portErr = fmt.Errorf("user [%v] port range [%v] format error", user, port)
break break
@@ -115,7 +115,7 @@ func (c *HandleController) JudgePort(content *plugin.NewProxyContent) plugin.Res
break break
} }
} else { } else {
allowed, err := strconv.Atoi(port) allowed, err := strconv.Atoi(str)
if err != nil { if err != nil {
portErr = fmt.Errorf("user [%v] allowed port [%v] is not a number", user, port) portErr = fmt.Errorf("user [%v] allowed port [%v] is not a number", user, port)
} }
@@ -124,6 +124,14 @@ func (c *HandleController) JudgePort(content *plugin.NewProxyContent) plugin.Res
break break
} }
} }
} else {
allowed := port
if allowed == userPort {
portAllowed = true
break
}
}
} }
} else { } else {
portAllowed = true portAllowed = true

View File

@@ -121,7 +121,8 @@ func (c *HandleController) verifyToken(token TokenInfo, operate int) OperationRe
if validatePorts { if validatePorts {
for _, port := range token.Ports { for _, port := range token.Ports {
trimmedPort := trimString(port) if str, ok := port.(string); ok {
trimmedPort := trimString(str)
if trimmedPort != "" && !portsFormatSingle.MatchString(trimmedPort) && !portsFormatRange.MatchString(trimmedPort) { if trimmedPort != "" && !portsFormatSingle.MatchString(trimmedPort) && !portsFormatRange.MatchString(trimmedPort) {
response.Success = false response.Success = false
response.Code = PortsFormatError response.Code = PortsFormatError
@@ -131,6 +132,7 @@ func (c *HandleController) verifyToken(token TokenInfo, operate int) OperationRe
} }
} }
} }
}
if validateDomains { if validateDomains {
for _, domain := range token.Domains { for _, domain := range token.Domains {
@@ -161,6 +163,19 @@ func (c *HandleController) verifyToken(token TokenInfo, operate int) OperationRe
return response return response
} }
func cleanPorts(ports []any) []any {
cleanedPorts := make([]any, len(ports))
for i, port := range ports {
if str, ok := port.(string); ok {
cleanedPorts[i] = cleanString(str)
} else {
//float64, for JSON numbers
cleanedPorts[i] = int(port.(float64))
}
}
return cleanedPorts
}
func cleanStrings(originalStrings []string) []string { func cleanStrings(originalStrings []string) []string {
cleanedStrings := make([]string, len(originalStrings)) cleanedStrings := make([]string, len(originalStrings))
for i, str := range originalStrings { for i, str := range originalStrings {
@@ -170,7 +185,7 @@ func cleanStrings(originalStrings []string) []string {
} }
func cleanString(originalString string) string { func cleanString(originalString string) string {
return trimAllSpace.ReplaceAllString(originalString, "") return trimString(originalString)
} }
func stringContains(element string, data []string) bool { func stringContains(element string, data []string) bool {
@@ -194,7 +209,9 @@ func (c *HandleController) saveToken() error {
log.Printf("error to crate file %v: %v", c.TokensFile, err) log.Printf("error to crate file %v: %v", c.TokensFile, err)
} }
if err = toml.NewEncoder(tokenFile).Encode(tokensList(c.Tokens)); err != nil { encoder := toml.NewEncoder(tokenFile)
encoder.Indent = " "
if err = encoder.Encode(tokensList(c.Tokens)); err != nil {
log.Printf("error to encode tokens: %v", err) log.Printf("error to encode tokens: %v", err)
} }
if err = tokenFile.Close(); err != nil { if err = tokenFile.Close(); err != nil {

View File

@@ -84,10 +84,10 @@ type TokenInfo struct {
User string `toml:"user" json:"user" form:"user"` User string `toml:"user" json:"user" form:"user"`
Token string `toml:"token" json:"token" form:"token"` Token string `toml:"token" json:"token" form:"token"`
Comment string `toml:"comment" json:"comment" form:"comment"` Comment string `toml:"comment" json:"comment" form:"comment"`
Ports []string `toml:"ports" json:"ports" from:"ports"` Ports []any `toml:"ports" json:"ports" from:"ports"`
Domains []string `toml:"domains" json:"domains" from:"domains"` Domains []string `toml:"domains" json:"domains" from:"domains"`
Subdomains []string `toml:"subdomains" json:"subdomains" from:"subdomains"` Subdomains []string `toml:"subdomains" json:"subdomains" from:"subdomains"`
Status bool `toml:"status" json:"status" form:"status"` Enable bool `toml:"enable" json:"enable" form:"enable"`
} }
type TokenResponse struct { type TokenResponse struct {