mirror of https://github.com/ouqiang/gocron
新增HTTP中间件-限制客户端IP访问
parent
90322c1230
commit
d3d7350fc7
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/ouqiang/gocron/modules/logger"
|
"github.com/ouqiang/gocron/modules/logger"
|
||||||
"github.com/ouqiang/gocron/service"
|
"github.com/ouqiang/gocron/service"
|
||||||
"github.com/ouqiang/gocron/models"
|
"github.com/ouqiang/gocron/models"
|
||||||
|
"github.com/ouqiang/gocron/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
// web服务器默认端口
|
// web服务器默认端口
|
||||||
|
@ -56,6 +57,13 @@ func initModule() {
|
||||||
if !app.Installed {
|
if !app.Installed {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config, err := setting.Read(app.AppConfig)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal("读取应用配置失败", err)
|
||||||
|
}
|
||||||
|
app.Setting = config
|
||||||
|
|
||||||
models.Db = models.CreateDb()
|
models.Db = models.CreateDb()
|
||||||
|
|
||||||
// 初始化定时任务
|
// 初始化定时任务
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"github.com/ouqiang/gocron/modules/logger"
|
"github.com/ouqiang/gocron/modules/logger"
|
||||||
"github.com/ouqiang/gocron/modules/setting"
|
|
||||||
"github.com/ouqiang/gocron/modules/app"
|
"github.com/ouqiang/gocron/modules/app"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -124,23 +123,15 @@ func keepDbAlived(engine *xorm.Engine) {
|
||||||
|
|
||||||
// 获取数据库配置
|
// 获取数据库配置
|
||||||
func getDbConfig() map[string]string {
|
func getDbConfig() map[string]string {
|
||||||
config, err := setting.Read(app.AppConfig)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal("获取应用配置失败", err)
|
|
||||||
}
|
|
||||||
section := config.Section("db")
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal("获取DB配置失败", err)
|
|
||||||
}
|
|
||||||
var db map[string]string = make(map[string]string)
|
var db map[string]string = make(map[string]string)
|
||||||
db["user"] = section.Key("user").String()
|
db["user"] = app.Setting.Key("db.user").String()
|
||||||
db["password"] = section.Key("password").String()
|
db["password"] = app.Setting.Key("db.password").String()
|
||||||
db["host"] = section.Key("host").String()
|
db["host"] = app.Setting.Key("db.host").String()
|
||||||
db["port"] = section.Key("port").String()
|
db["port"] = app.Setting.Key("db.port").String()
|
||||||
db["database"] = section.Key("database").String()
|
db["database"] = app.Setting.Key("db.database").String()
|
||||||
db["charset"] = section.Key("charset").String()
|
db["charset"] = app.Setting.Key("db.charset").String()
|
||||||
db["prefix"] = section.Key("prefix").String()
|
db["prefix"] = app.Setting.Key("db.prefix").String()
|
||||||
db["engine"] = section.Key("engine").String()
|
db["engine"] = app.Setting.Key("db.engine").String()
|
||||||
|
|
||||||
return db
|
return db
|
||||||
}
|
}
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/ouqiang/gocron/modules/logger"
|
"github.com/ouqiang/gocron/modules/logger"
|
||||||
"runtime"
|
"runtime"
|
||||||
"github.com/ouqiang/gocron/modules/utils"
|
"github.com/ouqiang/gocron/modules/utils"
|
||||||
|
"gopkg.in/ini.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -15,6 +16,7 @@ var (
|
||||||
DataDir string // 存放session等
|
DataDir string // 存放session等
|
||||||
AppConfig string // 应用配置文件
|
AppConfig string // 应用配置文件
|
||||||
Installed bool // 应用是否安装过
|
Installed bool // 应用是否安装过
|
||||||
|
Setting *ini.Section // 应用配置
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitEnv() {
|
func InitEnv() {
|
||||||
|
@ -47,7 +49,7 @@ func IsInstalled() bool {
|
||||||
func CreateInstallLock() error {
|
func CreateInstallLock() error {
|
||||||
_, err := os.Create(ConfDir + "/install.lock")
|
_, err := os.Create(ConfDir + "/install.lock")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("创建安装锁文件失败")
|
logger.Error("创建安装锁文件conf/install.lock失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -62,7 +62,6 @@ func request(req *http.Request, timeout int) ResponseWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setRequestHeader(req *http.Request) {
|
func setRequestHeader(req *http.Request) {
|
||||||
req.Header.Set("Connection", "keep-alive")
|
|
||||||
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8,en;q=0.6")
|
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8,en;q=0.6")
|
||||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 golang/gocron")
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 golang/gocron")
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,39 +5,41 @@ import (
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 读取配置
|
const DefaultSection = "default"
|
||||||
func Read(filename string) (config *ini.File, err error) {
|
|
||||||
config, err = ini.Load(filename)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
// 读取配置
|
||||||
|
func Read(filename string) (*ini.Section,error) {
|
||||||
|
config, err := ini.Load(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
section := config.Section(DefaultSection)
|
||||||
|
|
||||||
|
return section, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 写入配置
|
// 写入配置
|
||||||
func Write(config map[string]map[string]string, filename string) error {
|
func Write(config map[string]string, filename string) error {
|
||||||
if len(config) == 0 {
|
if len(config) == 0 {
|
||||||
return errors.New("参数不能为空")
|
return errors.New("参数不能为空")
|
||||||
}
|
}
|
||||||
|
|
||||||
file := ini.Empty()
|
file := ini.Empty()
|
||||||
for sectionName, items := range config {
|
|
||||||
if sectionName == "" {
|
section, err := file.NewSection(DefaultSection)
|
||||||
return errors.New("节名称不能为空")
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for key, value := range config {
|
||||||
|
if key == "" {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
section, err := file.NewSection(sectionName)
|
_, err = section.NewKey(key, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for key, value := range items {
|
|
||||||
_, err = section.NewKey(key, value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
err := file.SaveTo(filename)
|
err = file.SaveTo(filename)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ func Exec(sshConfig SSHConfig, cmd string) (output string, err error) {
|
||||||
// 后台运行
|
// 后台运行
|
||||||
if sshConfig.ExecTimeout < 0 {
|
if sshConfig.ExecTimeout < 0 {
|
||||||
go session.CombinedOutput(cmd)
|
go session.CombinedOutput(cmd)
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
// 不限制超时
|
// 不限制超时
|
||||||
|
|
|
@ -91,8 +91,9 @@ func ReplaceStrings(s string, old []string, replace []string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func InStringSlice(slice []string, element string) bool {
|
func InStringSlice(slice []string, element string) bool {
|
||||||
|
element = strings.TrimSpace(element)
|
||||||
for _, v := range slice {
|
for _, v := range slice {
|
||||||
if v == element {
|
if strings.TrimSpace(v) == element{
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,6 @@ import (
|
||||||
"github.com/ouqiang/gocron/modules/utils"
|
"github.com/ouqiang/gocron/modules/utils"
|
||||||
"gopkg.in/macaron.v1"
|
"gopkg.in/macaron.v1"
|
||||||
"strconv"
|
"strconv"
|
||||||
"github.com/ouqiang/gocron/modules/logger"
|
|
||||||
"github.com/go-macaron/binding"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/ouqiang/gocron/service"
|
"github.com/ouqiang/gocron/service"
|
||||||
)
|
)
|
||||||
|
@ -29,10 +27,6 @@ type InstallForm struct {
|
||||||
AdminEmail string `binding:"Required;Email;MaxSize(50)"`
|
AdminEmail string `binding:"Required;Email;MaxSize(50)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func(f InstallForm) Error(ctx *macaron.Context, errs binding.Errors) {
|
|
||||||
logger.Error(errs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Create(ctx *macaron.Context) {
|
func Create(ctx *macaron.Context) {
|
||||||
if app.Installed {
|
if app.Installed {
|
||||||
ctx.Redirect("/")
|
ctx.Redirect("/")
|
||||||
|
@ -61,6 +55,12 @@ func Store(ctx *macaron.Context, form InstallForm) string {
|
||||||
return json.CommonFailure("数据库配置写入文件失败", err)
|
return json.CommonFailure("数据库配置写入文件失败", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appConfig, err := setting.Read(app.AppConfig)
|
||||||
|
if err != nil {
|
||||||
|
return json.CommonFailure("读取应用配置失败", err)
|
||||||
|
}
|
||||||
|
app.Setting = appConfig
|
||||||
|
|
||||||
models.Db = models.CreateDb()
|
models.Db = models.CreateDb()
|
||||||
// 创建数据库表
|
// 创建数据库表
|
||||||
migration := new(models.Migration)
|
migration := new(models.Migration)
|
||||||
|
@ -89,19 +89,18 @@ func Store(ctx *macaron.Context, form InstallForm) string {
|
||||||
return json.Success("安装成功", nil)
|
return json.Success("安装成功", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数据库配置写入文件
|
// 配置写入文件
|
||||||
func writeConfig(form InstallForm) error {
|
func writeConfig(form InstallForm) error {
|
||||||
dbConfig := map[string]map[string]string{
|
dbConfig := map[string]string{
|
||||||
"db": map[string]string{
|
"db.engine": form.DbType,
|
||||||
"engine": form.DbType,
|
"db.host": form.DbHost,
|
||||||
"host": form.DbHost,
|
"db.port": strconv.Itoa(form.DbPort),
|
||||||
"port": strconv.Itoa(form.DbPort),
|
"db.user": form.DbUsername,
|
||||||
"user": form.DbUsername,
|
"db.password": form.DbPassword,
|
||||||
"password": form.DbPassword,
|
"db.database": form.DbName,
|
||||||
"database": form.DbName,
|
"db.prefix": form.DbTablePrefix,
|
||||||
"prefix": form.DbTablePrefix,
|
"db.charset": "utf8",
|
||||||
"charset": "utf8",
|
"allow_ips" : "",
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return setting.Write(dbConfig, app.AppConfig)
|
return setting.Write(dbConfig, app.AppConfig)
|
||||||
|
|
|
@ -142,6 +142,7 @@ func RegisterMiddleware(m *macaron.Macaron) {
|
||||||
m.Use(csrf.Csrfer())
|
m.Use(csrf.Csrfer())
|
||||||
m.Use(toolbox.Toolboxer(m))
|
m.Use(toolbox.Toolboxer(m))
|
||||||
checkAppInstall(m)
|
checkAppInstall(m)
|
||||||
|
ipAuth(m)
|
||||||
userAuth(m)
|
userAuth(m)
|
||||||
setShareData(m)
|
setShareData(m)
|
||||||
}
|
}
|
||||||
|
@ -159,6 +160,20 @@ func checkAppInstall(m *macaron.Macaron) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IP验证, 通过反向代理访问gocron,需设置Header X-Real-IP才能获取到客户端真实IP
|
||||||
|
func ipAuth(m *macaron.Macaron) {
|
||||||
|
m.Use(func(ctx *macaron.Context) {
|
||||||
|
allowIpsStr := app.Setting.Key("allow_ips").String()
|
||||||
|
if allowIpsStr == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
clientIp := ctx.RemoteAddr()
|
||||||
|
if !utils.InStringSlice(allowIps, clientIp) {
|
||||||
|
ctx.Status(403)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 用户认证
|
// 用户认证
|
||||||
func userAuth(m *macaron.Macaron) {
|
func userAuth(m *macaron.Macaron) {
|
||||||
m.Use(func(ctx *macaron.Context, sess session.Store) {
|
m.Use(func(ctx *macaron.Context, sess session.Store) {
|
||||||
|
@ -167,7 +182,7 @@ func userAuth(m *macaron.Macaron) {
|
||||||
}
|
}
|
||||||
uri := ctx.Req.URL.Path
|
uri := ctx.Req.URL.Path
|
||||||
found := false
|
found := false
|
||||||
excludePaths := []string{"/install", "/user/login", "/"}
|
excludePaths := []string{"/install", "/user/login", "/api"}
|
||||||
for _, path := range excludePaths {
|
for _, path := range excludePaths {
|
||||||
if strings.HasPrefix(uri, path) {
|
if strings.HasPrefix(uri, path) {
|
||||||
found = true
|
found = true
|
||||||
|
@ -199,14 +214,6 @@ func setShareData(m *macaron.Macaron) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 管理员认证
|
|
||||||
func adminAuth(ctx *macaron.Context, sess session.Store) {
|
|
||||||
if !user.IsAdmin(sess) {
|
|
||||||
ctx.Data["Title"] = "无权限访问此页面"
|
|
||||||
ctx.HTML(403, "error/no_permission")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isAjaxRequest(ctx *macaron.Context) bool {
|
func isAjaxRequest(ctx *macaron.Context) bool {
|
||||||
req := ctx.Req.Header.Get("X-Requested-With")
|
req := ctx.Req.Header.Get("X-Requested-With")
|
||||||
if req == "XMLHttpRequest" {
|
if req == "XMLHttpRequest" {
|
||||||
|
|
|
@ -57,7 +57,7 @@ func (task *Task) Initialize() {
|
||||||
taskModel := new(models.Task)
|
taskModel := new(models.Task)
|
||||||
taskList, err := taskModel.ActiveList()
|
taskList, err := taskModel.ActiveList()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("获取任务列表错误-", err.Error())
|
logger.Error("定时任务初始化#获取任务列表错误-", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(taskList) == 0 {
|
if len(taskList) == 0 {
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
{{{ template "common/header" . }}}
|
|
||||||
<script>
|
|
||||||
swal({
|
|
||||||
title: "403 - FORBIDDEN",
|
|
||||||
text: "您无权限访问此页面",
|
|
||||||
type: "warning"
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
location.href = "/"
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{{{ template "common/footer" . }}}
|
|
|
@ -66,13 +66,13 @@
|
||||||
<textarea rows="5" name="command">{{{.Task.Command}}}</textarea>
|
<textarea rows="5" name="command">{{{.Task.Command}}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="three fields">
|
<div class="six fields">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>任务超时时间(秒)</label>
|
<label>任务超时时间(秒)</label>
|
||||||
<input type="text" name="timeout" value="{{{.Task.Timeout}}}">
|
<input type="text" name="timeout" value="{{{.Task.Timeout}}}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="two fields">
|
<div class="six fields">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>任务失败重试次数</label>
|
<label>任务失败重试次数</label>
|
||||||
<input type="text" name="retry_times" value="{{{.Task.RetryTimes}}}">
|
<input type="text" name="retry_times" value="{{{.Task.RetryTimes}}}">
|
||||||
|
@ -143,7 +143,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a class="ui blue button" href="/manage/mail/edit">邮箱配置</a><br><br>
|
<a class="ui blue button" href="/manage/mail/edit" target="_blank">邮箱配置</a><br><br>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a class="ui blue button" href="/manage/slack/edit">Slack配置</a>
|
<a class="ui blue button" href="/manage/slack/edit" target="_blank">Slack配置</a>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue