mirror of
https://github.com/bjdgyc/anylink.git
synced 2025-08-07 21:54:17 +08:00
更改目录结构
This commit is contained in:
79
server/admin/api_base.go
Normal file
79
server/admin/api_base.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/bjdgyc/anylink/pkg/utils"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// Login 登陆接口
|
||||
func Login(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO 调试信息输出
|
||||
// hd, _ := httputil.DumpRequest(r, true)
|
||||
// fmt.Println("DumpRequest: ", string(hd))
|
||||
|
||||
_ = r.ParseForm()
|
||||
adminUser := r.PostFormValue("admin_user")
|
||||
adminPass := r.PostFormValue("admin_pass")
|
||||
|
||||
// 认证错误
|
||||
if !(adminUser == base.Cfg.AdminUser &&
|
||||
utils.PasswordVerify(adminPass, base.Cfg.AdminPass)) {
|
||||
RespError(w, RespUserOrPassErr)
|
||||
return
|
||||
}
|
||||
|
||||
// token有效期
|
||||
expiresAt := time.Now().Unix() + 3600*3
|
||||
jwtData := map[string]interface{}{"admin_user": adminUser}
|
||||
tokenString, err := SetJwtData(jwtData, expiresAt)
|
||||
if err != nil {
|
||||
RespError(w, 1, err)
|
||||
return
|
||||
}
|
||||
|
||||
data := make(map[string]interface{})
|
||||
data["token"] = tokenString
|
||||
data["admin_user"] = adminUser
|
||||
data["expires_at"] = expiresAt
|
||||
|
||||
RespSucess(w, data)
|
||||
}
|
||||
|
||||
func authMiddleware(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET,POST,OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "*")
|
||||
if r.Method == http.MethodOptions {
|
||||
return
|
||||
}
|
||||
|
||||
route := mux.CurrentRoute(r)
|
||||
name := route.GetName()
|
||||
// fmt.Println("bb", r.URL.Path, name)
|
||||
if utils.InArrStr([]string{"login", "index", "static"}, name) {
|
||||
// 不进行鉴权
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// 进行登陆鉴权
|
||||
jwtToken := r.Header.Get("Jwt")
|
||||
if jwtToken == "" {
|
||||
jwtToken = r.FormValue("jwt")
|
||||
}
|
||||
data, err := GetJwtData(jwtToken)
|
||||
if err != nil || base.Cfg.AdminUser != fmt.Sprint(data["admin_user"]) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
108
server/admin/api_group.go
Normal file
108
server/admin/api_group.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/bjdgyc/anylink/dbdata"
|
||||
)
|
||||
|
||||
func GroupList(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
pageS := r.FormValue("page")
|
||||
page, _ := strconv.Atoi(pageS)
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
var pageSize = dbdata.PageSize
|
||||
|
||||
count := dbdata.CountAll(&dbdata.Group{})
|
||||
|
||||
var datas []dbdata.Group
|
||||
err := dbdata.All(&datas, pageSize, page)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
data := map[string]interface{}{
|
||||
"count": count,
|
||||
"page_size": pageSize,
|
||||
"datas": datas,
|
||||
}
|
||||
|
||||
RespSucess(w, data)
|
||||
}
|
||||
|
||||
func GroupNames(w http.ResponseWriter, r *http.Request) {
|
||||
var names = dbdata.GetGroupNames()
|
||||
data := map[string]interface{}{
|
||||
"count": len(names),
|
||||
"page_size": 0,
|
||||
"datas": names,
|
||||
}
|
||||
RespSucess(w, data)
|
||||
}
|
||||
|
||||
func GroupDetail(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
idS := r.FormValue("id")
|
||||
id, _ := strconv.Atoi(idS)
|
||||
if id < 1 {
|
||||
RespError(w, RespParamErr, "Id错误")
|
||||
return
|
||||
}
|
||||
|
||||
var data dbdata.Group
|
||||
err := dbdata.One("Id", id, &data)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
RespSucess(w, data)
|
||||
}
|
||||
|
||||
func GroupSet(w http.ResponseWriter, r *http.Request) {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
v := &dbdata.Group{}
|
||||
err = json.Unmarshal(body, v)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = dbdata.SetGroup(v)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
RespSucess(w, nil)
|
||||
}
|
||||
|
||||
func GroupDel(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
idS := r.FormValue("id")
|
||||
id, _ := strconv.Atoi(idS)
|
||||
if id < 1 {
|
||||
RespError(w, RespParamErr, "Id错误")
|
||||
return
|
||||
}
|
||||
|
||||
data := dbdata.Group{Id: id}
|
||||
err := dbdata.Del(&data)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
RespSucess(w, nil)
|
||||
}
|
111
server/admin/api_ip_map.go
Normal file
111
server/admin/api_ip_map.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/bjdgyc/anylink/dbdata"
|
||||
)
|
||||
|
||||
func UserIpMapList(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
pageS := r.FormValue("page")
|
||||
page, _ := strconv.Atoi(pageS)
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
var pageSize = dbdata.PageSize
|
||||
|
||||
count := dbdata.CountAll(&dbdata.IpMap{})
|
||||
|
||||
var datas []dbdata.IpMap
|
||||
err := dbdata.All(&datas, pageSize, page)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
data := map[string]interface{}{
|
||||
"count": count,
|
||||
"page_size": pageSize,
|
||||
"datas": datas,
|
||||
}
|
||||
|
||||
RespSucess(w, data)
|
||||
}
|
||||
|
||||
func UserIpMapDetail(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
idS := r.FormValue("id")
|
||||
id, _ := strconv.Atoi(idS)
|
||||
if id < 1 {
|
||||
RespError(w, RespParamErr, "用户名错误")
|
||||
return
|
||||
}
|
||||
|
||||
var data dbdata.IpMap
|
||||
err := dbdata.One("Id", id, &data)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
RespSucess(w, data)
|
||||
}
|
||||
|
||||
func UserIpMapSet(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
v := &dbdata.IpMap{}
|
||||
err = json.Unmarshal(body, v)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
// fmt.Println(v, len(v.Ip), len(v.MacAddr))
|
||||
|
||||
if len(v.IpAddr) < 4 || len(v.MacAddr) < 6 {
|
||||
RespError(w, RespParamErr, "IP或MAC错误")
|
||||
return
|
||||
}
|
||||
|
||||
v.UpdatedAt = time.Now()
|
||||
err = dbdata.Save(v)
|
||||
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
RespSucess(w, nil)
|
||||
}
|
||||
|
||||
func UserIpMapDel(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
idS := r.FormValue("id")
|
||||
id, _ := strconv.Atoi(idS)
|
||||
|
||||
if id < 1 {
|
||||
RespError(w, RespParamErr, "IP映射id错误")
|
||||
return
|
||||
}
|
||||
|
||||
data := dbdata.IpMap{Id: id}
|
||||
err := dbdata.Del(&data)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
RespSucess(w, nil)
|
||||
}
|
62
server/admin/api_other.go
Normal file
62
server/admin/api_other.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/bjdgyc/anylink/dbdata"
|
||||
)
|
||||
|
||||
func setOtherGet(data interface{}, w http.ResponseWriter) {
|
||||
err := dbdata.SettingGet(data)
|
||||
if err != nil && !dbdata.CheckErrNotFound(err) {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
RespSucess(w, data)
|
||||
}
|
||||
|
||||
func setOtherEdit(data interface{}, w http.ResponseWriter, r *http.Request) {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
err = json.Unmarshal(body, data)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
// fmt.Println(data)
|
||||
|
||||
err = dbdata.SettingSet(data)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
RespSucess(w, data)
|
||||
}
|
||||
|
||||
func SetOtherSmtp(w http.ResponseWriter, r *http.Request) {
|
||||
data := &dbdata.SettingSmtp{}
|
||||
setOtherGet(data, w)
|
||||
}
|
||||
|
||||
func SetOtherSmtpEdit(w http.ResponseWriter, r *http.Request) {
|
||||
data := &dbdata.SettingSmtp{}
|
||||
setOtherEdit(data, w, r)
|
||||
}
|
||||
|
||||
func SetOther(w http.ResponseWriter, r *http.Request) {
|
||||
data := &dbdata.SettingOther{}
|
||||
setOtherGet(data, w)
|
||||
}
|
||||
|
||||
func SetOtherEdit(w http.ResponseWriter, r *http.Request) {
|
||||
data := &dbdata.SettingOther{}
|
||||
setOtherEdit(data, w, r)
|
||||
}
|
93
server/admin/api_set.go
Normal file
93
server/admin/api_set.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
|
||||
"github.com/bjdgyc/anylink/dbdata"
|
||||
"github.com/bjdgyc/anylink/sessdata"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/bjdgyc/anylink/pkg/utils"
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
"github.com/shirou/gopsutil/disk"
|
||||
"github.com/shirou/gopsutil/host"
|
||||
"github.com/shirou/gopsutil/load"
|
||||
"github.com/shirou/gopsutil/mem"
|
||||
)
|
||||
|
||||
func SetHome(w http.ResponseWriter, r *http.Request) {
|
||||
data := make(map[string]interface{})
|
||||
|
||||
sess := sessdata.OnlineSess()
|
||||
|
||||
data["counts"] = map[string]int{
|
||||
"online": len(sess),
|
||||
"user": dbdata.CountAll(&dbdata.User{}),
|
||||
"group": dbdata.CountAll(&dbdata.Group{}),
|
||||
"ip_map": dbdata.CountAll(&dbdata.IpMap{}),
|
||||
}
|
||||
|
||||
RespSucess(w, data)
|
||||
}
|
||||
|
||||
func SetSystem(w http.ResponseWriter, r *http.Request) {
|
||||
data := make(map[string]interface{})
|
||||
|
||||
m, _ := mem.VirtualMemory()
|
||||
data["mem"] = map[string]interface{}{
|
||||
"total": utils.HumanByte(m.Total),
|
||||
"free": utils.HumanByte(m.Free),
|
||||
"percent": decimal(m.UsedPercent),
|
||||
}
|
||||
|
||||
d, _ := disk.Usage("/")
|
||||
data["disk"] = map[string]interface{}{
|
||||
"total": utils.HumanByte(d.Total),
|
||||
"free": utils.HumanByte(d.Free),
|
||||
"percent": decimal(d.UsedPercent),
|
||||
}
|
||||
|
||||
cc, _ := cpu.Counts(true)
|
||||
c, _ := cpu.Info()
|
||||
ci := c[0]
|
||||
cpuUsedPercent, _ := cpu.Percent(0, false)
|
||||
cup := cpuUsedPercent[0]
|
||||
if cup == 0 {
|
||||
cup = 1
|
||||
}
|
||||
data["cpu"] = map[string]interface{}{
|
||||
"core": cc,
|
||||
"modelName": ci.ModelName,
|
||||
"ghz": fmt.Sprintf("%.2f GHz", ci.Mhz/1000),
|
||||
"percent": decimal(cup),
|
||||
}
|
||||
|
||||
hi, _ := host.Info()
|
||||
l, _ := load.Avg()
|
||||
data["sys"] = map[string]interface{}{
|
||||
"goOs": runtime.GOOS,
|
||||
"goArch": runtime.GOARCH,
|
||||
"goVersion": runtime.Version(),
|
||||
"goroutine": runtime.NumGoroutine(),
|
||||
|
||||
"hostname": hi.Hostname,
|
||||
"platform": fmt.Sprintf("%v %v %v", hi.Platform, hi.PlatformFamily, hi.PlatformVersion),
|
||||
"kernel": hi.KernelVersion,
|
||||
|
||||
"load": fmt.Sprint(l.Load1, l.Load5, l.Load15),
|
||||
}
|
||||
|
||||
RespSucess(w, data)
|
||||
}
|
||||
|
||||
func SetSoft(w http.ResponseWriter, r *http.Request) {
|
||||
data := base.ServerCfg2Slice()
|
||||
RespSucess(w, data)
|
||||
}
|
||||
|
||||
func decimal(f float64) float64 {
|
||||
i := int(f * 100)
|
||||
return float64(i) / 100
|
||||
}
|
245
server/admin/api_user.go
Normal file
245
server/admin/api_user.go
Normal file
@@ -0,0 +1,245 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/bjdgyc/anylink/dbdata"
|
||||
"github.com/bjdgyc/anylink/sessdata"
|
||||
"github.com/skip2/go-qrcode"
|
||||
)
|
||||
|
||||
func UserList(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
prefix := r.FormValue("prefix")
|
||||
pageS := r.FormValue("page")
|
||||
page, _ := strconv.Atoi(pageS)
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
var (
|
||||
pageSize = dbdata.PageSize
|
||||
count int
|
||||
datas []dbdata.User
|
||||
err error
|
||||
)
|
||||
|
||||
// 查询前缀匹配
|
||||
if len(prefix) > 0 {
|
||||
count = pageSize
|
||||
err = dbdata.Prefix("Username", prefix, &datas, pageSize, 1)
|
||||
} else {
|
||||
count = dbdata.CountAll(&dbdata.User{})
|
||||
err = dbdata.All(&datas, pageSize, page)
|
||||
}
|
||||
|
||||
if err != nil && !dbdata.CheckErrNotFound(err) {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
data := map[string]interface{}{
|
||||
"count": count,
|
||||
"page_size": pageSize,
|
||||
"datas": datas,
|
||||
}
|
||||
|
||||
RespSucess(w, data)
|
||||
}
|
||||
|
||||
func UserDetail(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
idS := r.FormValue("id")
|
||||
id, _ := strconv.Atoi(idS)
|
||||
if id < 1 {
|
||||
RespError(w, RespParamErr, "用户名错误")
|
||||
return
|
||||
}
|
||||
|
||||
var user dbdata.User
|
||||
err := dbdata.One("Id", id, &user)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
RespSucess(w, user)
|
||||
}
|
||||
|
||||
func UserSet(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
data := &dbdata.User{}
|
||||
err = json.Unmarshal(body, data)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = dbdata.SetUser(data)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 发送邮件
|
||||
if data.SendEmail {
|
||||
err = userAccountMail(data)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
RespSucess(w, nil)
|
||||
}
|
||||
|
||||
func UserDel(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
idS := r.FormValue("id")
|
||||
id, _ := strconv.Atoi(idS)
|
||||
|
||||
if id < 1 {
|
||||
RespError(w, RespParamErr, "用户id错误")
|
||||
return
|
||||
}
|
||||
|
||||
user := dbdata.User{Id: id}
|
||||
err := dbdata.Del(&user)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
RespSucess(w, nil)
|
||||
}
|
||||
|
||||
func UserOtpQr(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
b64 := r.FormValue("b64")
|
||||
idS := r.FormValue("id")
|
||||
id, _ := strconv.Atoi(idS)
|
||||
var user dbdata.User
|
||||
err := dbdata.One("Id", id, &user)
|
||||
if err != nil {
|
||||
RespError(w, RespInternalErr, err)
|
||||
return
|
||||
}
|
||||
|
||||
issuer := base.Cfg.Issuer
|
||||
qrstr := fmt.Sprintf("otpauth://totp/%s:%s?issuer=%s&secret=%s", issuer, user.Email, issuer, user.OtpSecret)
|
||||
qr, _ := qrcode.New(qrstr, qrcode.High)
|
||||
|
||||
if b64 == "1" {
|
||||
data, _ := qr.PNG(300)
|
||||
s := base64.StdEncoding.EncodeToString(data)
|
||||
_, err = fmt.Fprint(w, s)
|
||||
if err != nil {
|
||||
base.Error(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
err = qr.Write(300, w)
|
||||
if err != nil {
|
||||
base.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// 在线用户
|
||||
func UserOnline(w http.ResponseWriter, r *http.Request) {
|
||||
datas := sessdata.OnlineSess()
|
||||
|
||||
data := map[string]interface{}{
|
||||
"count": len(datas),
|
||||
"page_size": dbdata.PageSize,
|
||||
"datas": datas,
|
||||
}
|
||||
|
||||
RespSucess(w, data)
|
||||
}
|
||||
|
||||
func UserOffline(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
token := r.FormValue("token")
|
||||
sessdata.CloseSess(token)
|
||||
RespSucess(w, nil)
|
||||
}
|
||||
|
||||
func UserReline(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
token := r.FormValue("token")
|
||||
sessdata.CloseCSess(token)
|
||||
RespSucess(w, nil)
|
||||
}
|
||||
|
||||
type userAccountMailData struct {
|
||||
Issuer string
|
||||
LinkAddr string
|
||||
Group string
|
||||
Username string
|
||||
PinCode string
|
||||
OtpImg string
|
||||
}
|
||||
|
||||
func userAccountMail(user *dbdata.User) error {
|
||||
// 平台通知
|
||||
htmlBody := `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<title>Hello AnyLink!</title>
|
||||
</head>
|
||||
<body>
|
||||
%s
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
dataOther := &dbdata.SettingOther{}
|
||||
err := dbdata.SettingGet(dataOther)
|
||||
if err != nil {
|
||||
base.Error(err)
|
||||
return err
|
||||
}
|
||||
htmlBody = fmt.Sprintf(htmlBody, dataOther.AccountMail)
|
||||
// fmt.Println(htmlBody)
|
||||
|
||||
// token有效期3天
|
||||
expiresAt := time.Now().Unix() + 3600*24*3
|
||||
jwtData := map[string]interface{}{"id": user.Id}
|
||||
tokenString, err := SetJwtData(jwtData, expiresAt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data := userAccountMailData{
|
||||
LinkAddr: base.Cfg.LinkAddr,
|
||||
Group: strings.Join(user.Groups, ","),
|
||||
Username: user.Username,
|
||||
PinCode: user.PinCode,
|
||||
OtpImg: fmt.Sprintf("https://%s/otp_qr?id=%d&jwt=%s", base.Cfg.LinkAddr, user.Id, tokenString),
|
||||
}
|
||||
w := bytes.NewBufferString("")
|
||||
t, _ := template.New("auth_complete").Parse(htmlBody)
|
||||
err = t.Execute(w, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// fmt.Println(w.String())
|
||||
return SendMail(base.Cfg.Issuer+"平台通知", user.Email, w.String())
|
||||
}
|
108
server/admin/common.go
Normal file
108
server/admin/common.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/bjdgyc/anylink/dbdata"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
mail "github.com/xhit/go-simple-mail/v2"
|
||||
// "github.com/mojocn/base64Captcha"
|
||||
)
|
||||
|
||||
func SetJwtData(data map[string]interface{}, expiresAt int64) (string, error) {
|
||||
jwtData := jwt.MapClaims{"exp": expiresAt}
|
||||
for k, v := range data {
|
||||
jwtData[k] = v
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwtData)
|
||||
|
||||
// Sign and get the complete encoded token as a string using the secret
|
||||
tokenString, err := token.SignedString([]byte(base.Cfg.JwtSecret))
|
||||
return tokenString, err
|
||||
}
|
||||
|
||||
func GetJwtData(jwtToken string) (map[string]interface{}, error) {
|
||||
token, err := jwt.Parse(jwtToken, func(token *jwt.Token) (interface{}, error) {
|
||||
// since we only use the one private key to sign the tokens,
|
||||
// we also only use its public counter part to verify
|
||||
return []byte(base.Cfg.JwtSecret), nil
|
||||
})
|
||||
|
||||
if err != nil || !token.Valid {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
claims, ok := token.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
return nil, errors.New("data is parse err")
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
func SendMail(subject, to, htmlBody string) error {
|
||||
|
||||
dataSmtp := &dbdata.SettingSmtp{}
|
||||
err := dbdata.SettingGet(dataSmtp)
|
||||
if err != nil {
|
||||
base.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
server := mail.NewSMTPClient()
|
||||
|
||||
// SMTP Server
|
||||
server.Host = dataSmtp.Host
|
||||
server.Port = dataSmtp.Port
|
||||
server.Username = dataSmtp.Username
|
||||
server.Password = dataSmtp.Password
|
||||
if dataSmtp.UseSSl {
|
||||
server.Encryption = mail.EncryptionSSL
|
||||
}
|
||||
|
||||
// Since v2.3.0 you can specified authentication type:
|
||||
// - PLAIN (default)
|
||||
// - LOGIN
|
||||
// - CRAM-MD5
|
||||
server.Authentication = mail.AuthPlain
|
||||
|
||||
// Variable to keep alive connection
|
||||
server.KeepAlive = false
|
||||
|
||||
// Timeout for connect to SMTP Server
|
||||
server.ConnectTimeout = 10 * time.Second
|
||||
|
||||
// Timeout for send the data and wait respond
|
||||
server.SendTimeout = 10 * time.Second
|
||||
|
||||
// Set TLSConfig to provide custom TLS configuration. For example,
|
||||
// to skip TLS verification (useful for testing):
|
||||
server.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
|
||||
// SMTP client
|
||||
smtpClient, err := server.Connect()
|
||||
|
||||
if err != nil {
|
||||
base.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// New email simple html with inline and CC
|
||||
email := mail.NewMSG()
|
||||
email.SetFrom(dataSmtp.From).
|
||||
AddTo(to).
|
||||
SetSubject(subject)
|
||||
|
||||
email.SetBody(mail.TextHTML, htmlBody)
|
||||
|
||||
// Call Send and pass the client
|
||||
err = email.Send(smtpClient)
|
||||
if err != nil {
|
||||
base.Error(err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
23
server/admin/common_test.go
Normal file
23
server/admin/common_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestJwtData(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
base.Cfg.JwtSecret = "dsfasfdfsadfasdfasd3sdaf"
|
||||
data := map[string]interface{}{
|
||||
"key": "value",
|
||||
}
|
||||
expiresAt := time.Now().Add(time.Minute).Unix()
|
||||
token, err := SetJwtData(data, expiresAt)
|
||||
assert.Nil(err)
|
||||
dataN, err := GetJwtData(token)
|
||||
assert.Nil(err)
|
||||
assert.Equal(dataN["key"], "value")
|
||||
}
|
15
server/admin/error.go
Normal file
15
server/admin/error.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package admin
|
||||
|
||||
// 返回码
|
||||
const (
|
||||
RespSuccess = 0
|
||||
RespInternalErr = 1
|
||||
RespTokenErr = 2
|
||||
RespUserOrPassErr = 3
|
||||
RespParamErr = 4
|
||||
)
|
||||
|
||||
var RespMap = map[int]string{
|
||||
RespTokenErr: "客户端TOKEN错误",
|
||||
RespUserOrPassErr: "用户名或密码错误",
|
||||
}
|
64
server/admin/resp.go
Normal file
64
server/admin/resp.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
)
|
||||
|
||||
type Resp struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Location string `json:"location"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func respHttp(w http.ResponseWriter, respCode int, data interface{}, errS ...interface{}) {
|
||||
resp := Resp{
|
||||
Code: respCode,
|
||||
Msg: "success",
|
||||
Data: data,
|
||||
}
|
||||
_, file, line, _ := runtime.Caller(2)
|
||||
resp.Location = fmt.Sprintf("%v:%v", file, line)
|
||||
|
||||
if respCode != 0 {
|
||||
resp.Msg = ""
|
||||
if v, ok := RespMap[respCode]; ok {
|
||||
resp.Msg += v
|
||||
}
|
||||
|
||||
if len(errS) > 0 {
|
||||
resp.Msg += fmt.Sprint(errS...)
|
||||
}
|
||||
}
|
||||
|
||||
b, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
base.Error(err, resp)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err = w.Write(b)
|
||||
if err != nil {
|
||||
base.Error(err)
|
||||
}
|
||||
// 记录返回数据
|
||||
// logger.Category("response").Debug(string(b))
|
||||
}
|
||||
|
||||
func RespSucess(w http.ResponseWriter, data interface{}) {
|
||||
respHttp(w, 0, data, "")
|
||||
}
|
||||
|
||||
func RespError(w http.ResponseWriter, respCode int, errS ...interface{}) {
|
||||
respHttp(w, respCode, nil, errS...)
|
||||
}
|
||||
|
||||
func RespData(w http.ResponseWriter, data interface{}, err error) {
|
||||
respHttp(w, http.StatusOK, data, "")
|
||||
}
|
39
server/admin/resp_test.go
Normal file
39
server/admin/resp_test.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRespSucess(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
w := httptest.NewRecorder()
|
||||
RespSucess(w, "data")
|
||||
// fmt.Println(w)
|
||||
assert.Equal(w.Code, 200)
|
||||
body, _ := ioutil.ReadAll(w.Body)
|
||||
res := Resp{}
|
||||
err := json.Unmarshal(body, &res)
|
||||
assert.Nil(err)
|
||||
assert.Equal(res.Code, 0)
|
||||
assert.Equal(res.Data, "data")
|
||||
|
||||
}
|
||||
|
||||
func TestRespError(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
w := httptest.NewRecorder()
|
||||
RespError(w, 10, "err-msg")
|
||||
// fmt.Println(w)
|
||||
assert.Equal(w.Code, 200)
|
||||
body, _ := ioutil.ReadAll(w.Body)
|
||||
res := Resp{}
|
||||
err := json.Unmarshal(body, &res)
|
||||
assert.Nil(err)
|
||||
assert.Equal(res.Code, 10)
|
||||
assert.Equal(res.Msg, "err-msg")
|
||||
}
|
71
server/admin/server.go
Normal file
71
server/admin/server.go
Normal file
@@ -0,0 +1,71 @@
|
||||
// admin:后台管理接口
|
||||
package admin
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// 开启服务
|
||||
func StartAdmin() {
|
||||
|
||||
r := mux.NewRouter()
|
||||
r.Use(authMiddleware)
|
||||
|
||||
r.Handle("/", http.RedirectHandler("/ui/", http.StatusFound)).Name("index")
|
||||
r.PathPrefix("/ui/").Handler(
|
||||
http.StripPrefix("/ui/", http.FileServer(http.Dir(base.Cfg.UiPath))),
|
||||
).Name("static")
|
||||
r.HandleFunc("/base/login", Login).Name("login")
|
||||
|
||||
r.HandleFunc("/set/home", SetHome)
|
||||
r.HandleFunc("/set/system", SetSystem)
|
||||
r.HandleFunc("/set/soft", SetSoft)
|
||||
r.HandleFunc("/set/other", SetOther)
|
||||
r.HandleFunc("/set/other/edit", SetOtherEdit)
|
||||
r.HandleFunc("/set/other/smtp", SetOtherSmtp)
|
||||
r.HandleFunc("/set/other/smtp/edit", SetOtherSmtpEdit)
|
||||
|
||||
r.HandleFunc("/user/list", UserList)
|
||||
r.HandleFunc("/user/detail", UserDetail)
|
||||
r.HandleFunc("/user/set", UserSet)
|
||||
r.HandleFunc("/user/del", UserDel)
|
||||
r.HandleFunc("/user/online", UserOnline)
|
||||
r.HandleFunc("/user/offline", UserOffline)
|
||||
r.HandleFunc("/user/reline", UserReline)
|
||||
r.HandleFunc("/user/otp_qr", UserOtpQr)
|
||||
r.HandleFunc("/user/ip_map/list", UserIpMapList)
|
||||
r.HandleFunc("/user/ip_map/detail", UserIpMapDetail)
|
||||
r.HandleFunc("/user/ip_map/set", UserIpMapSet)
|
||||
r.HandleFunc("/user/ip_map/del", UserIpMapDel)
|
||||
|
||||
r.HandleFunc("/group/list", GroupList)
|
||||
r.HandleFunc("/group/names", GroupNames)
|
||||
r.HandleFunc("/group/detail", GroupDetail)
|
||||
r.HandleFunc("/group/set", GroupSet)
|
||||
r.HandleFunc("/group/del", GroupDel)
|
||||
|
||||
// pprof
|
||||
r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
||||
r.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||
r.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
r.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||
r.HandleFunc("/debug/pprof", location("/debug/pprof/"))
|
||||
r.PathPrefix("/debug/pprof/").HandlerFunc(pprof.Index)
|
||||
|
||||
base.Info("Listen admin", base.Cfg.AdminAddr)
|
||||
err := http.ListenAndServe(base.Cfg.AdminAddr, r)
|
||||
if err != nil {
|
||||
base.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func location(url string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Location", url)
|
||||
w.WriteHeader(http.StatusFound)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user