mirror of
https://github.com/nezhahq/nezha.git
synced 2025-02-02 01:28:13 -05:00
parent
061a9992ff
commit
c3dcc721dc
@ -1,12 +1,15 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
"github.com/naiba/nezha/model"
|
"github.com/naiba/nezha/model"
|
||||||
"github.com/naiba/nezha/pkg/mygin"
|
"github.com/naiba/nezha/pkg/mygin"
|
||||||
@ -20,11 +23,63 @@ type commonPage struct {
|
|||||||
func (cp *commonPage) serve() {
|
func (cp *commonPage) serve() {
|
||||||
cr := cp.r.Group("")
|
cr := cp.r.Group("")
|
||||||
cr.Use(mygin.Authorize(mygin.AuthorizeOption{}))
|
cr.Use(mygin.Authorize(mygin.AuthorizeOption{}))
|
||||||
|
cr.POST("/view-password", cp.issueViewPassword)
|
||||||
|
cr.Use(cp.checkViewPassword) // 前端查看密码鉴权
|
||||||
cr.GET("/", cp.home)
|
cr.GET("/", cp.home)
|
||||||
cr.GET("/service", cp.service)
|
cr.GET("/service", cp.service)
|
||||||
cr.GET("/ws", cp.ws)
|
cr.GET("/ws", cp.ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type viewPasswordForm struct {
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *commonPage) issueViewPassword(c *gin.Context) {
|
||||||
|
var vpf viewPasswordForm
|
||||||
|
err := c.ShouldBind(&vpf)
|
||||||
|
var hash []byte
|
||||||
|
if err == nil && vpf.Password != dao.Conf.Site.ViewPassword {
|
||||||
|
err = errors.New("查看密码错误")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
hash, err = bcrypt.GenerateFromPassword([]byte(vpf.Password), bcrypt.DefaultCost)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
mygin.ShowErrorPage(c, mygin.ErrInfo{
|
||||||
|
Title: "出现错误",
|
||||||
|
Msg: fmt.Sprintf("请求错误:%s", err),
|
||||||
|
}, true)
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.SetCookie(dao.Conf.Site.CookieName+"-vp", string(hash), 60*60*24, "", "", false, false)
|
||||||
|
c.Redirect(http.StatusFound, c.Request.Referer())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *commonPage) checkViewPassword(c *gin.Context) {
|
||||||
|
if dao.Conf.Site.ViewPassword == "" {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, authorized := c.Get(model.CtxKeyAuthorizedUser); authorized {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证查看密码
|
||||||
|
viewPassword, _ := c.Cookie(dao.Conf.Site.CookieName + "-vp")
|
||||||
|
if err := bcrypt.CompareHashAndPassword([]byte(viewPassword), []byte(dao.Conf.Site.ViewPassword)); err != nil {
|
||||||
|
c.HTML(http.StatusOK, "theme-"+dao.Conf.Site.Theme+"/viewpassword", mygin.CommonEnvironment(c, gin.H{
|
||||||
|
"Title": "验证查看密码",
|
||||||
|
"CustomCode": dao.Conf.Site.CustomCode,
|
||||||
|
}))
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
|
||||||
type ServiceItem struct {
|
type ServiceItem struct {
|
||||||
Monitor model.Monitor
|
Monitor model.Monitor
|
||||||
TotalUp uint64
|
TotalUp uint64
|
||||||
|
@ -445,6 +445,7 @@ type settingForm struct {
|
|||||||
Admin string
|
Admin string
|
||||||
Theme string
|
Theme string
|
||||||
CustomCode string
|
CustomCode string
|
||||||
|
ViewPassword string
|
||||||
EnableIPChangeNotification string
|
EnableIPChangeNotification string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,6 +462,7 @@ func (ma *memberAPI) updateSetting(c *gin.Context) {
|
|||||||
dao.Conf.Site.Brand = sf.Title
|
dao.Conf.Site.Brand = sf.Title
|
||||||
dao.Conf.Site.Theme = sf.Theme
|
dao.Conf.Site.Theme = sf.Theme
|
||||||
dao.Conf.Site.CustomCode = sf.CustomCode
|
dao.Conf.Site.CustomCode = sf.CustomCode
|
||||||
|
dao.Conf.Site.ViewPassword = sf.ViewPassword
|
||||||
dao.Conf.GitHub.Admin = sf.Admin
|
dao.Conf.GitHub.Admin = sf.Admin
|
||||||
if err := dao.Conf.Save(); err != nil {
|
if err := dao.Conf.Save(); err != nil {
|
||||||
c.JSON(http.StatusOK, model.Response{
|
c.JSON(http.StatusOK, model.Response{
|
||||||
|
@ -40,6 +40,9 @@ func init() {
|
|||||||
if dao.Conf.Debug {
|
if dao.Conf.Debug {
|
||||||
dao.DB = dao.DB.Debug()
|
dao.DB = dao.DB.Debug()
|
||||||
}
|
}
|
||||||
|
if dao.Conf.GRPCPort == 0 {
|
||||||
|
dao.Conf.GRPCPort = 5555
|
||||||
|
}
|
||||||
dao.Cache = cache.New(5*time.Minute, 10*time.Minute)
|
dao.Cache = cache.New(5*time.Minute, 10*time.Minute)
|
||||||
|
|
||||||
initSystem()
|
initSystem()
|
||||||
@ -105,7 +108,7 @@ func loadCrons() {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
go controller.ServeWeb(dao.Conf.HTTPPort)
|
go controller.ServeWeb(dao.Conf.HTTPPort)
|
||||||
go rpc.ServeRPC(5555)
|
go rpc.ServeRPC(dao.Conf.GRPCPort)
|
||||||
go rpc.DispatchTask(time.Minute * 3)
|
go rpc.DispatchTask(time.Minute * 3)
|
||||||
dao.AlertSentinelStart()
|
dao.AlertSentinelStart()
|
||||||
}
|
}
|
||||||
|
1
go.mod
1
go.mod
@ -20,6 +20,7 @@ require (
|
|||||||
github.com/shirou/gopsutil/v3 v3.20.11
|
github.com/shirou/gopsutil/v3 v3.20.11
|
||||||
github.com/spf13/viper v1.7.1
|
github.com/spf13/viper v1.7.1
|
||||||
github.com/stretchr/testify v1.6.1
|
github.com/stretchr/testify v1.6.1
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
|
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
|
||||||
google.golang.org/grpc v1.33.1
|
google.golang.org/grpc v1.33.1
|
||||||
google.golang.org/protobuf v1.25.0
|
google.golang.org/protobuf v1.25.0
|
||||||
|
@ -13,10 +13,11 @@ import (
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
Debug bool
|
Debug bool
|
||||||
Site struct {
|
Site struct {
|
||||||
Brand string // 站点名称
|
Brand string // 站点名称
|
||||||
CookieName string // 浏览器 Cookie 名称
|
CookieName string // 浏览器 Cookie 名称
|
||||||
Theme string
|
Theme string
|
||||||
CustomCode string
|
CustomCode string
|
||||||
|
ViewPassword string // 前台查看密码
|
||||||
}
|
}
|
||||||
GitHub struct {
|
GitHub struct {
|
||||||
Admin string // 管理员ID列表
|
Admin string // 管理员ID列表
|
||||||
@ -24,6 +25,7 @@ type Config struct {
|
|||||||
ClientSecret string
|
ClientSecret string
|
||||||
}
|
}
|
||||||
HTTPPort uint
|
HTTPPort uint
|
||||||
|
GRPCPort uint
|
||||||
EnableIPChangeNotification bool
|
EnableIPChangeNotification bool
|
||||||
|
|
||||||
v *viper.Viper
|
v *viper.Viper
|
||||||
|
@ -26,6 +26,7 @@ func Authorize(opt AuthorizeOption) func(*gin.Context) {
|
|||||||
if opt.Guest {
|
if opt.Guest {
|
||||||
code = http.StatusBadRequest
|
code = http.StatusBadRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
commonErr := ErrInfo{
|
commonErr := ErrInfo{
|
||||||
Title: "访问受限",
|
Title: "访问受限",
|
||||||
Code: code,
|
Code: code,
|
||||||
@ -36,6 +37,7 @@ func Authorize(opt AuthorizeOption) func(*gin.Context) {
|
|||||||
|
|
||||||
var isLogin bool
|
var isLogin bool
|
||||||
|
|
||||||
|
// 用户鉴权
|
||||||
token, _ := c.Cookie(dao.Conf.Site.CookieName)
|
token, _ := c.Cookie(dao.Conf.Site.CookieName)
|
||||||
token = strings.TrimSpace(token)
|
token = strings.TrimSpace(token)
|
||||||
if token != "" {
|
if token != "" {
|
||||||
|
@ -23,6 +23,10 @@
|
|||||||
<label>自定义代码(style、script 都可以)</label>
|
<label>自定义代码(style、script 都可以)</label>
|
||||||
<textarea name="CustomCode">{{.Conf.Site.CustomCode}}</textarea>
|
<textarea name="CustomCode">{{.Conf.Site.CustomCode}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>前台查看密码</label>
|
||||||
|
<input type="text" name="ViewPassword" placeholder="" value="{{.Conf.Site.ViewPassword}}">
|
||||||
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui nf-ssl checkbox">
|
<div class="ui nf-ssl checkbox">
|
||||||
<input name="EnableIPChangeNotification" type="checkbox" tabindex="0" class="hidden">
|
<input name="EnableIPChangeNotification" type="checkbox" tabindex="0" class="hidden">
|
||||||
|
25
resource/template/theme-daynight/viewpassword.html
vendored
Normal file
25
resource/template/theme-daynight/viewpassword.html
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{{define "theme-daynight/viewpassword"}}
|
||||||
|
{{template "common/header" .}}
|
||||||
|
{{if ts .CustomCode}}
|
||||||
|
{{.CustomCode|safe}}
|
||||||
|
{{end}}
|
||||||
|
<div class="login nb-container">
|
||||||
|
<div class="ui center aligned grid">
|
||||||
|
<div class="column">
|
||||||
|
<h2 class="ui teal image header">
|
||||||
|
<img src="static/logo.png" class="image">
|
||||||
|
<div class="content">
|
||||||
|
验证查看密码
|
||||||
|
</div>
|
||||||
|
</h2>
|
||||||
|
<form action="/view-password" method="POST" class="ui form">
|
||||||
|
<div class="field">
|
||||||
|
<input type="password" name="Password">
|
||||||
|
</div>
|
||||||
|
<button class="ui button" type="submit">确认</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{template "common/footer" .}}
|
||||||
|
{{end}}
|
25
resource/template/theme-default/viewpassword.html
vendored
Normal file
25
resource/template/theme-default/viewpassword.html
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{{define "theme-default/viewpassword"}}
|
||||||
|
{{template "common/header" .}}
|
||||||
|
{{if ts .CustomCode}}
|
||||||
|
{{.CustomCode|safe}}
|
||||||
|
{{end}}
|
||||||
|
<div class="login nb-container">
|
||||||
|
<div class="ui center aligned grid">
|
||||||
|
<div class="column">
|
||||||
|
<h2 class="ui teal image header">
|
||||||
|
<img src="static/logo.png" class="image">
|
||||||
|
<div class="content">
|
||||||
|
验证查看密码
|
||||||
|
</div>
|
||||||
|
</h2>
|
||||||
|
<form action="/view-password" method="POST" class="ui form">
|
||||||
|
<div class="field">
|
||||||
|
<input type="password" name="Password">
|
||||||
|
</div>
|
||||||
|
<button class="ui button" type="submit">确认</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{template "common/footer" .}}
|
||||||
|
{{end}}
|
25
resource/template/theme-hotaru/viewpassword.html
vendored
Normal file
25
resource/template/theme-hotaru/viewpassword.html
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{{define "theme-horaru/viewpassword"}}
|
||||||
|
{{template "common/header" .}}
|
||||||
|
{{if ts .CustomCode}}
|
||||||
|
{{.CustomCode|safe}}
|
||||||
|
{{end}}
|
||||||
|
<div class="login nb-container">
|
||||||
|
<div class="ui center aligned grid">
|
||||||
|
<div class="column">
|
||||||
|
<h2 class="ui teal image header">
|
||||||
|
<img src="static/logo.png" class="image">
|
||||||
|
<div class="content">
|
||||||
|
验证查看密码
|
||||||
|
</div>
|
||||||
|
</h2>
|
||||||
|
<form action="/view-password" method="POST" class="ui form">
|
||||||
|
<div class="field">
|
||||||
|
<input type="password" name="Password">
|
||||||
|
</div>
|
||||||
|
<button class="ui button" type="submit">确认</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{template "common/footer" .}}
|
||||||
|
{{end}}
|
@ -8,4 +8,4 @@ services:
|
|||||||
- ./data:/dashboard/data
|
- ./data:/dashboard/data
|
||||||
ports:
|
ports:
|
||||||
- nz_site_port:80
|
- nz_site_port:80
|
||||||
- nz_rpc_port:5555
|
- nz_grpc_port:5555
|
||||||
|
@ -202,7 +202,7 @@ modify_agent_config() {
|
|||||||
|
|
||||||
echo "请先在管理面板上添加Agent,记录下密钥" &&
|
echo "请先在管理面板上添加Agent,记录下密钥" &&
|
||||||
read -p "请输入一个解析到面板所在IP的域名(不可套CDN): " nz_rpc_host &&
|
read -p "请输入一个解析到面板所在IP的域名(不可套CDN): " nz_rpc_host &&
|
||||||
read -p "请输入面板RPC端口: (5555)" nz_rpc_port &&
|
read -p "请输入面板RPC端口: (5555)" nz_grpc_port &&
|
||||||
read -p "请输入Agent 密钥: " nezha_client_secret
|
read -p "请输入Agent 密钥: " nezha_client_secret
|
||||||
if [[ -z "${nz_rpc_host}" || -z "${nezha_client_secret}" ]]; then
|
if [[ -z "${nz_rpc_host}" || -z "${nezha_client_secret}" ]]; then
|
||||||
echo -e "${red}所有选项都不能为空${plain}"
|
echo -e "${red}所有选项都不能为空${plain}"
|
||||||
@ -210,12 +210,12 @@ modify_agent_config() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "${nz_rpc_port}" ]]; then
|
if [[ -z "${nz_grpc_port}" ]]; then
|
||||||
nz_rpc_port=5555
|
nz_grpc_port=5555
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sed -i "s/nz_rpc_host/${nz_rpc_host}/" ${NZ_AGENT_SERVICE}
|
sed -i "s/nz_rpc_host/${nz_rpc_host}/" ${NZ_AGENT_SERVICE}
|
||||||
sed -i "s/nz_rpc_port/${nz_rpc_port}/" ${NZ_AGENT_SERVICE}
|
sed -i "s/nz_grpc_port/${nz_grpc_port}/" ${NZ_AGENT_SERVICE}
|
||||||
sed -i "s/nezha_client_secret/${nezha_client_secret}/" ${NZ_AGENT_SERVICE}
|
sed -i "s/nezha_client_secret/${nezha_client_secret}/" ${NZ_AGENT_SERVICE}
|
||||||
|
|
||||||
echo -e "Agent配置 ${green}修改成功,请稍等重启生效${plain}"
|
echo -e "Agent配置 ${green}修改成功,请稍等重启生效${plain}"
|
||||||
@ -254,7 +254,7 @@ modify_dashboard_config() {
|
|||||||
read -p "请输入 GitHub Oauth2 应用的 Client Secret: " nz_github_oauth_client_secret &&
|
read -p "请输入 GitHub Oauth2 应用的 Client Secret: " nz_github_oauth_client_secret &&
|
||||||
read -p "请输入站点标题: " nz_site_title &&
|
read -p "请输入站点标题: " nz_site_title &&
|
||||||
read -p "请输入站点访问端口: (8008)" nz_site_port &&
|
read -p "请输入站点访问端口: (8008)" nz_site_port &&
|
||||||
read -p "请输入用于 Agent 接入的 RPC 端口: (5555)" nz_rpc_port
|
read -p "请输入用于 Agent 接入的 RPC 端口: (5555)" nz_grpc_port
|
||||||
if [[ -z "${nz_admin_ids}" || -z "${nz_github_oauth_client_id}" || -z "${nz_github_oauth_client_secret}" || -z "${nz_site_title}" ]]; then
|
if [[ -z "${nz_admin_ids}" || -z "${nz_github_oauth_client_id}" || -z "${nz_github_oauth_client_secret}" || -z "${nz_site_title}" ]]; then
|
||||||
echo -e "${red}所有选项都不能为空${plain}"
|
echo -e "${red}所有选项都不能为空${plain}"
|
||||||
before_show_menu
|
before_show_menu
|
||||||
@ -264,8 +264,8 @@ modify_dashboard_config() {
|
|||||||
if [[ -z "${nz_site_port}" ]]; then
|
if [[ -z "${nz_site_port}" ]]; then
|
||||||
nz_site_port=8008
|
nz_site_port=8008
|
||||||
fi
|
fi
|
||||||
if [[ -z "${nz_rpc_port}" ]]; then
|
if [[ -z "${nz_grpc_port}" ]]; then
|
||||||
nz_rpc_port=5555
|
nz_grpc_port=5555
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sed -i "s/nz_admin_ids/${nz_admin_ids}/" ${NZ_DASHBOARD_PATH}/data/config.yaml
|
sed -i "s/nz_admin_ids/${nz_admin_ids}/" ${NZ_DASHBOARD_PATH}/data/config.yaml
|
||||||
@ -273,7 +273,7 @@ modify_dashboard_config() {
|
|||||||
sed -i "s/nz_github_oauth_client_secret/${nz_github_oauth_client_secret}/" ${NZ_DASHBOARD_PATH}/data/config.yaml
|
sed -i "s/nz_github_oauth_client_secret/${nz_github_oauth_client_secret}/" ${NZ_DASHBOARD_PATH}/data/config.yaml
|
||||||
sed -i "s/nz_site_title/${nz_site_title}/" ${NZ_DASHBOARD_PATH}/data/config.yaml
|
sed -i "s/nz_site_title/${nz_site_title}/" ${NZ_DASHBOARD_PATH}/data/config.yaml
|
||||||
sed -i "s/nz_site_port/${nz_site_port}/" ${NZ_DASHBOARD_PATH}/docker-compose.yaml
|
sed -i "s/nz_site_port/${nz_site_port}/" ${NZ_DASHBOARD_PATH}/docker-compose.yaml
|
||||||
sed -i "s/nz_rpc_port/${nz_rpc_port}/" ${NZ_DASHBOARD_PATH}/docker-compose.yaml
|
sed -i "s/nz_grpc_port/${nz_grpc_port}/" ${NZ_DASHBOARD_PATH}/docker-compose.yaml
|
||||||
|
|
||||||
echo -e "面板配置 ${green}修改成功,请稍等重启生效${plain}"
|
echo -e "面板配置 ${green}修改成功,请稍等重启生效${plain}"
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ Type=simple
|
|||||||
User=root
|
User=root
|
||||||
Group=root
|
Group=root
|
||||||
WorkingDirectory=/opt/nezha/agent/
|
WorkingDirectory=/opt/nezha/agent/
|
||||||
ExecStart=/opt/nezha/agent/nezha-agent -d -s nz_rpc_host:nz_rpc_port -p nezha_client_secret
|
ExecStart=/opt/nezha/agent/nezha-agent -d -s nz_rpc_host:nz_grpc_port -p nezha_client_secret
|
||||||
Restart=always
|
Restart=always
|
||||||
#Environment=DEBUG=true
|
#Environment=DEBUG=true
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user