mirror of
https://github.com/yhl452493373/frps-panel.git
synced 2026-04-04 06:16:59 +08:00
update readme;
optimize logic code;
This commit is contained in:
92
README.md
92
README.md
@@ -36,62 +36,60 @@ frp version >= v0.31.0
|
||||
|
||||
### 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]
|
||||
;plugin listen ip
|
||||
plugin_addr = 127.0.0.1
|
||||
;plugin listen port
|
||||
# frps panel config info
|
||||
plugin_addr = "127.0.0.1" #aadr
|
||||
plugin_port = 7200
|
||||
;the username of manage ui,optional
|
||||
admin_user = admin
|
||||
;the password of manage ui,optional
|
||||
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_user = "admin"
|
||||
#admin_pwd = "admin"
|
||||
# specified login state keep time
|
||||
admin_keep_time = 0
|
||||
|
||||
; enable tls
|
||||
# enable tls
|
||||
tls_mode = false
|
||||
; tls_cert_file = cert.crt
|
||||
; tls_key_file = cert.key
|
||||
# tls_cert_file = cert.crt
|
||||
# tls_key_file = cert.key
|
||||
|
||||
; frp dashboard info
|
||||
dashboard_addr = 127.0.0.1
|
||||
# frp dashboard info
|
||||
dashboard_addr = "127.0.0.1"
|
||||
dashboard_port = 7500
|
||||
dashboard_user = 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
|
||||
dashboard_user = "admin"
|
||||
dashboard_pwd = "admin"
|
||||
```
|
||||
|
||||
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
|
||||
# frps.ini
|
||||
@@ -105,7 +103,7 @@ path = /handler
|
||||
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:
|
||||
|
||||
@@ -139,7 +137,7 @@ local_port = 22
|
||||
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
|
||||
|
||||
@@ -155,8 +153,8 @@ Wants = network.target
|
||||
|
||||
[Service]
|
||||
Type = simple
|
||||
# config of frps-panel.ini,you should change the file path
|
||||
Environment=FRPS_PANEL_OPTS="-c /root/frps-panel/frps-panel.ini"
|
||||
# config of frps-panel.toml,you should change the file path
|
||||
Environment=FRPS_PANEL_OPTS="-c /root/frps-panel/frps-panel.toml"
|
||||
# command of run frps-panel,you should change the file path
|
||||
ExecStart = /root/frps-panel/frps-panel $FRPS_PANEL_OPTS
|
||||
|
||||
|
||||
92
README_zh.md
92
README_zh.md
@@ -37,63 +37,59 @@ frps-panel 会以一个单独的进程运行,并接收 frps 发送过来的 HT
|
||||
|
||||
### 使用示例
|
||||
|
||||
1. 创建 `frps-panel.ini` 文件,内容为所有支持的用户名和 token。
|
||||
1. 创建 `frps-panel.toml` 文件,内容为基础配置。
|
||||
|
||||
```ini
|
||||
```toml
|
||||
# frps-panel.toml
|
||||
[common]
|
||||
;插件监听地址
|
||||
;如果上面配置中 tls_mode = true, 则把plugin_addr的值改为 https://127.0.0.1:7200
|
||||
plugin_addr = 127.0.0.1
|
||||
;插件端口
|
||||
# frps panel config info
|
||||
plugin_addr = "127.0.0.1" #aadr
|
||||
plugin_port = 7200
|
||||
;插件管理页面账号,可选
|
||||
admin_user = admin
|
||||
;插件管理页面密码,与账号一起进行鉴权,可选
|
||||
admin_pwd = admin
|
||||
;登录状态空闲时间(秒):0-浏览器完全退出前不用重新登录,大于0-空闲超过此时间则需要重新登录.
|
||||
#admin_user = "admin"
|
||||
#admin_pwd = "admin"
|
||||
# specified login state keep time
|
||||
admin_keep_time = 0
|
||||
|
||||
; frps 面板页面是否启用https访问,如果为true,则只能通过https访问
|
||||
# enable tls
|
||||
tls_mode = false
|
||||
; tls_cert_file = cert.crt
|
||||
; tls_key_file = cert.key
|
||||
# tls_cert_file = cert.crt
|
||||
# tls_key_file = cert.key
|
||||
|
||||
; frp服务器的看板页面信息,必须配置,且与frp服务器一致,否则无法获取服务器信息
|
||||
dashboard_addr = 127.0.0.1
|
||||
# frp dashboard info
|
||||
dashboard_addr = "127.0.0.1"
|
||||
dashboard_port = 7500
|
||||
dashboard_user = 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
|
||||
dashboard_user = "admin"
|
||||
dashboard_pwd = "admin"
|
||||
```
|
||||
|
||||
每一个用户占一行,用户名和 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
|
||||
# frps.ini
|
||||
@@ -106,7 +102,7 @@ path = /handler
|
||||
ops = Login,NewWorkConn,NewUserConn,NewProxy,Ping
|
||||
```
|
||||
|
||||
4. 在 frpc 中指定用户名,在 meta 中指定 token,用户名以及 `meta_token` 的内容需要和之前创建的 token 文件匹配。
|
||||
5. 在 frpc 中指定用户名,在 meta 中指定 token,用户名以及 `meta_token` 的内容需要和之前创建的 token 文件匹配。
|
||||
|
||||
user1 的配置:
|
||||
|
||||
@@ -140,7 +136,7 @@ local_port = 22
|
||||
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]
|
||||
Type = simple
|
||||
# 启动frps-panel的配置文件路径,需修改为您的frps-panel.ini的路径
|
||||
Environment=FRPS_PANEL_OPTS="-c /root/frps-panel/frps-panel.ini"
|
||||
# 启动frps-panel的配置文件路径,需修改为您的frps-panel.toml的路径
|
||||
Environment=FRPS_PANEL_OPTS="-c /root/frps-panel/frps-panel.toml"
|
||||
# 启动frps-panel的命令,需修改为您的frps-panel的安装路径
|
||||
ExecStart = /root/frps-panel/frps-panel $FRPS_PANEL_OPTS
|
||||
|
||||
|
||||
@@ -71,6 +71,11 @@
|
||||
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 a,
|
||||
.layui-nav-tree .layui-this,
|
||||
@@ -206,6 +211,11 @@ section.proxy-list .proxy-info .layui-row .layui-row > div:first-child {
|
||||
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 a,
|
||||
.layui-nav-tree .layui-this,
|
||||
|
||||
@@ -97,7 +97,7 @@ var loadUserList = (function ($) {
|
||||
}
|
||||
return {
|
||||
valid: valid,
|
||||
trim: username
|
||||
trim: username.trim()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ var loadUserList = (function ($) {
|
||||
}
|
||||
return {
|
||||
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
|
||||
*/
|
||||
(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: 'subdomains', title: i18n['AllowedSubdomains'], sort: true, edit: 'textarea'},
|
||||
{
|
||||
field: 'status',
|
||||
field: 'enable',
|
||||
title: i18n['Status'],
|
||||
width: 100,
|
||||
templet: '<span>{{d.status? "' + i18n['Enable'] + '":"' + i18n['Disable'] + '"}}</span>',
|
||||
templet: '<span>{{d.enable? "' + i18n['Enable'] + '":"' + i18n['Disable'] + '"}}</span>',
|
||||
sort: true
|
||||
},
|
||||
{title: i18n['Operation'], width: 150, toolbar: '#userListOperationTemplate'}
|
||||
@@ -371,6 +371,12 @@ var loadUserList = (function ($) {
|
||||
|
||||
data.forEach(function (temp) {
|
||||
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.subdomains = temp.subdomains.split(',')
|
||||
});
|
||||
@@ -395,6 +401,11 @@ var loadUserList = (function ($) {
|
||||
var data = obj.data;
|
||||
|
||||
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.subdomains = data.subdomains.split(',')
|
||||
switch (obj.event) {
|
||||
@@ -438,6 +449,11 @@ var loadUserList = (function ($) {
|
||||
var formData = layui.form.val('addUserForm');
|
||||
if (formData.ports != null) {
|
||||
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) {
|
||||
formData.domains = formData.domains.split(',')
|
||||
@@ -456,7 +472,7 @@ var loadUserList = (function ($) {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function add(data, index) {
|
||||
@@ -485,10 +501,20 @@ var loadUserList = (function ($) {
|
||||
|
||||
/**
|
||||
* update user action
|
||||
* @param before {{user:string, token:string, comment:string, status:boolean, ports:[string], 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 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, enable:boolean, ports:[string|number], domains:[string], subdomains:[string]}} data after update
|
||||
*/
|
||||
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();
|
||||
$.ajax({
|
||||
url: '/update',
|
||||
@@ -513,7 +539,7 @@ var loadUserList = (function ($) {
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if (data.length === 0) {
|
||||
@@ -530,7 +556,7 @@ var loadUserList = (function ($) {
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if (data.length === 0) {
|
||||
@@ -547,7 +573,7 @@ var loadUserList = (function ($) {
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if (data.length === 0) {
|
||||
@@ -564,7 +590,7 @@ var loadUserList = (function ($) {
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
layui.layer.confirm(i18n['ConfirmRemoveUser'], {
|
||||
@@ -577,7 +603,7 @@ var loadUserList = (function ($) {
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
layui.layer.confirm(i18n['ConfirmDisableUser'], {
|
||||
@@ -590,7 +616,7 @@ var loadUserList = (function ($) {
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
layui.layer.confirm(i18n['ConfirmEnableUser'], {
|
||||
@@ -604,7 +630,7 @@ var loadUserList = (function ($) {
|
||||
/**
|
||||
* operate actions
|
||||
* @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
|
||||
*/
|
||||
function operate(type, data, index) {
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>${ .FrpsPanel }</title>
|
||||
<link rel="stylesheet" href="./static/lib/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="./static/css/layui-theme-dark.css">
|
||||
<link rel="stylesheet" href="./static/css/index.css">
|
||||
<link rel="stylesheet" href="./static/css/color.css">
|
||||
<script src="./static/lib/layui/layui.js"></script>
|
||||
<script src="./static/lib/echarts.min.js"></script>
|
||||
<script src="./static/lib/filesize.min.js"></script>
|
||||
<script src="./static/js/index-server-info.js"></script>
|
||||
<script src="./static/js/index-user-list.js"></script>
|
||||
<script src="./static/js/index-proxy-list.js"></script>
|
||||
<script src="./static/js/index.js"></script>
|
||||
<link rel="stylesheet" href="./static/lib/layui/css/layui.css?v=${ .version }">
|
||||
<link rel="stylesheet" href="./static/css/layui-theme-dark.css?v=${ .version }">
|
||||
<link rel="stylesheet" href="./static/css/index.css?v=${ .version }">
|
||||
<link rel="stylesheet" href="./static/css/color.css?v=${ .version }">
|
||||
<script src="./static/lib/layui/layui.js?v=${ .version }"></script>
|
||||
<script src="./static/lib/echarts.min.js?v=${ .version }"></script>
|
||||
<script src="./static/lib/filesize.min.js?v=${ .version }"></script>
|
||||
<script src="./static/js/index-server-info.js?v=${ .version }"></script>
|
||||
<script src="./static/js/index-user-list.js?v=${ .version }"></script>
|
||||
<script src="./static/js/index-proxy-list.js?v=${ .version }"></script>
|
||||
<script src="./static/js/index.js?v=${ .version }"></script>
|
||||
<style>
|
||||
section.user-list .layui-table-cell:empty::after {
|
||||
content: '${ .NotLimit }';
|
||||
@@ -214,7 +214,7 @@
|
||||
<script type="text/html" id="userListOperationTemplate">
|
||||
<div class="layui-clear-space">
|
||||
<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>
|
||||
{{# } else { }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="enable">${ .Enable }</a>
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
<html lang="">
|
||||
<head>
|
||||
<title>Login</title>
|
||||
<link rel="stylesheet" href="./static/lib/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="./static/css/layui-theme-dark.css">
|
||||
<link rel="stylesheet" href="./static/css/color.css">
|
||||
<link rel="stylesheet" href="./static/css/login.css">
|
||||
<script src="./static/lib/layui/layui.js"></script>
|
||||
<script src="./static/js/login.js"></script>
|
||||
<link rel="stylesheet" href="./static/lib/layui/css/layui.css?v=${ .version }">
|
||||
<link rel="stylesheet" href="./static/css/layui-theme-dark.css?v=${ .version }">
|
||||
<link rel="stylesheet" href="./static/css/color.css?v=${ .version }">
|
||||
<link rel="stylesheet" href="./static/css/login.css?v=${ .version }">
|
||||
<script src="./static/lib/layui/layui.js?v=${ .version }"></script>
|
||||
<script src="./static/js/login.js?v=${ .version }"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-title">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"frps-panel/pkg/server"
|
||||
"frps-panel/pkg/server/controller"
|
||||
"github.com/BurntSushi/toml"
|
||||
@@ -11,7 +12,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const version = "1.6.0"
|
||||
const version = "1.7.0"
|
||||
|
||||
var (
|
||||
showVersion bool
|
||||
@@ -79,8 +80,12 @@ func parseConfigFile(configFile, tokensFile string) (controller.HandleController
|
||||
|
||||
_, err = toml.DecodeFile(tokensFile, &tokens)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
common.Common.DashboardTls = strings.HasPrefix("https://", strings.ToLower(common.Common.DashboardAddr))
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -290,7 +290,7 @@ func (c *HandleController) MakeQueryTokensFunc() func(context *gin.Context) {
|
||||
func (c *HandleController) MakeAddTokenFunc() func(context *gin.Context) {
|
||||
return func(context *gin.Context) {
|
||||
info := TokenInfo{
|
||||
Status: true,
|
||||
Enable: true,
|
||||
}
|
||||
response := OperationResponse{
|
||||
Success: true,
|
||||
@@ -315,7 +315,7 @@ func (c *HandleController) MakeAddTokenFunc() func(context *gin.Context) {
|
||||
}
|
||||
|
||||
info.Comment = cleanString(info.Comment)
|
||||
info.Ports = cleanStrings(info.Ports)
|
||||
info.Ports = cleanPorts(info.Ports)
|
||||
info.Domains = cleanStrings(info.Domains)
|
||||
info.Subdomains = cleanStrings(info.Subdomains)
|
||||
|
||||
@@ -373,7 +373,7 @@ func (c *HandleController) MakeUpdateTokensFunc() func(context *gin.Context) {
|
||||
}
|
||||
|
||||
after.Comment = cleanString(after.Comment)
|
||||
after.Ports = cleanStrings(after.Ports)
|
||||
after.Ports = cleanPorts(after.Ports)
|
||||
after.Domains = cleanStrings(after.Domains)
|
||||
after.Subdomains = cleanStrings(after.Subdomains)
|
||||
|
||||
@@ -467,7 +467,7 @@ func (c *HandleController) MakeDisableTokensFunc() func(context *gin.Context) {
|
||||
|
||||
for _, user := range disable.Users {
|
||||
token := c.Tokens[user.User]
|
||||
token.Status = false
|
||||
token.Enable = false
|
||||
c.Tokens[user.User] = token
|
||||
}
|
||||
|
||||
@@ -515,7 +515,7 @@ func (c *HandleController) MakeEnableTokensFunc() func(context *gin.Context) {
|
||||
|
||||
for _, user := range enable.Users {
|
||||
token := c.Tokens[user.User]
|
||||
token.Status = true
|
||||
token.Enable = true
|
||||
c.Tokens[user.User] = token
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ func (c *HandleController) JudgeToken(user string, token string) plugin.Response
|
||||
res.Reject = true
|
||||
res.RejectReason = "user or meta token can not be empty"
|
||||
} else if info, exist := c.Tokens[user]; exist {
|
||||
if !info.Status {
|
||||
if !info.Enable {
|
||||
res.Reject = true
|
||||
res.RejectReason = fmt.Sprintf("user [%s] is disabled", user)
|
||||
} else {
|
||||
@@ -77,7 +77,6 @@ func (c *HandleController) JudgePort(content *plugin.NewProxyContent) plugin.Res
|
||||
"tcp", "tcpmux", "udp", "http", "https",
|
||||
}
|
||||
proxyType := content.ProxyType
|
||||
|
||||
if stringContains(proxyType, supportProxyTypes) {
|
||||
log.Printf("proxy type [%v] not support, plugin do nothing", proxyType)
|
||||
res.Unchange = true
|
||||
@@ -94,8 +93,9 @@ func (c *HandleController) JudgePort(content *plugin.NewProxyContent) plugin.Res
|
||||
portAllowed = false
|
||||
if token, exist := c.Tokens[user]; exist {
|
||||
for _, port := range token.Ports {
|
||||
if strings.Contains(port, "-") {
|
||||
allowedRanges := strings.Split(port, "-")
|
||||
if str, ok := port.(string); ok {
|
||||
if strings.Contains(str, "-") {
|
||||
allowedRanges := strings.Split(str, "-")
|
||||
if len(allowedRanges) != 2 {
|
||||
portErr = fmt.Errorf("user [%v] port range [%v] format error", user, port)
|
||||
break
|
||||
@@ -115,7 +115,7 @@ func (c *HandleController) JudgePort(content *plugin.NewProxyContent) plugin.Res
|
||||
break
|
||||
}
|
||||
} else {
|
||||
allowed, err := strconv.Atoi(port)
|
||||
allowed, err := strconv.Atoi(str)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
}
|
||||
} else {
|
||||
allowed := port
|
||||
if allowed == userPort {
|
||||
portAllowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
portAllowed = true
|
||||
|
||||
@@ -121,7 +121,8 @@ func (c *HandleController) verifyToken(token TokenInfo, operate int) OperationRe
|
||||
|
||||
if validatePorts {
|
||||
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) {
|
||||
response.Success = false
|
||||
response.Code = PortsFormatError
|
||||
@@ -131,6 +132,7 @@ func (c *HandleController) verifyToken(token TokenInfo, operate int) OperationRe
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if validateDomains {
|
||||
for _, domain := range token.Domains {
|
||||
@@ -161,6 +163,19 @@ func (c *HandleController) verifyToken(token TokenInfo, operate int) OperationRe
|
||||
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 {
|
||||
cleanedStrings := make([]string, len(originalStrings))
|
||||
for i, str := range originalStrings {
|
||||
@@ -170,7 +185,7 @@ func cleanStrings(originalStrings []string) []string {
|
||||
}
|
||||
|
||||
func cleanString(originalString string) string {
|
||||
return trimAllSpace.ReplaceAllString(originalString, "")
|
||||
return trimString(originalString)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
if err = tokenFile.Close(); err != nil {
|
||||
|
||||
@@ -84,10 +84,10 @@ type TokenInfo struct {
|
||||
User string `toml:"user" json:"user" form:"user"`
|
||||
Token string `toml:"token" json:"token" form:"token"`
|
||||
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"`
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user