更改目录结构

This commit is contained in:
bjdgyc
2021-03-01 15:46:08 +08:00
parent 3464d1d10e
commit 0f91c779e3
105 changed files with 29099 additions and 96 deletions

89
server/dbdata/db.go Normal file
View File

@@ -0,0 +1,89 @@
package dbdata
import (
"time"
"github.com/asdine/storm/v3"
"github.com/asdine/storm/v3/codec/json"
"github.com/bjdgyc/anylink/base"
bolt "go.etcd.io/bbolt"
)
var (
sdb *storm.DB
)
func initDb() {
var err error
sdb, err = storm.Open(base.Cfg.DbFile, storm.Codec(json.Codec),
storm.BoltOptions(0600, &bolt.Options{Timeout: 10 * time.Second}))
if err != nil {
base.Fatal(err)
}
// 初始化数据库
err = sdb.Init(&User{})
if err != nil {
base.Fatal(err)
}
// fmt.Println("s1")
}
func initData() {
var (
err error
install bool
)
// 判断是否初次使用
err = Get(SettingBucket, Installed, &install)
if err == nil && install {
// 已经安装过
return
}
defer func() {
_ = Set(SettingBucket, Installed, true)
}()
smtp := &SettingSmtp{
Host: "127.0.0.1",
Port: 25,
From: "vpn@xx.com",
}
_ = SettingSet(smtp)
other := &SettingOther{
Banner: "您已接入公司网络,请按照公司规定使用。\n请勿进行非工作下载及视频行为",
AccountMail: accountMail,
}
_ = SettingSet(other)
}
func CheckErrNotFound(err error) bool {
return err == storm.ErrNotFound
}
const accountMail = `<p>您好:</p>
<p>&nbsp;&nbsp;您的{{.Issuer}}账号已经审核开通。</p>
<p>
登陆地址: <b>{{.LinkAddr}}</b> <br/>
用户组: <b>{{.Group}}</b> <br/>
用户名: <b>{{.Username}}</b> <br/>
用户PIN码: <b>{{.PinCode}}</b> <br/>
用户动态码(3天后失效):<br/>
<img src="{{.OtpImg}}"/>
</p>
<div>
使用说明:
<ul>
<li>请使用OTP软件扫描动态码二维码</li>
<li>然后使用anyconnect客户端进行登陆</li>
<li>登陆密码为 【PIN码+动态码】</li>
</ul>
</div>
<p>
软件下载地址: https://gitee.com/bjdgyc/anylink-soft/blob/master/README.md
</p>`

66
server/dbdata/db_orm.go Normal file
View File

@@ -0,0 +1,66 @@
package dbdata
import "github.com/asdine/storm/v3/index"
const PageSize = 10
func Save(data interface{}) error {
return sdb.Save(data)
}
func Update(data interface{}) error {
return sdb.Update(data)
}
func UpdateField(data interface{}, fieldName string, value interface{}) error {
return sdb.UpdateField(data, fieldName, value)
}
func Del(data interface{}) error {
return sdb.DeleteStruct(data)
}
func Set(bucket, key string, data interface{}) error {
return sdb.Set(bucket, key, data)
}
func Get(bucket, key string, data interface{}) error {
return sdb.Get(bucket, key, data)
}
func CountAll(data interface{}) int {
n, _ := sdb.Count(data)
return n
}
func One(fieldName string, value interface{}, to interface{}) error {
return sdb.One(fieldName, value, to)
}
func Find(fieldName string, value interface{}, to interface{}, options ...func(q *index.Options)) error {
return sdb.Find(fieldName, value, to, options...)
}
func All(to interface{}, limit, page int) error {
opt := getOpt(limit, page)
return sdb.All(to, opt)
}
func Prefix(fieldName string, prefix string, to interface{}, limit, page int) error {
opt := getOpt(limit, page)
return sdb.Prefix(fieldName, prefix, to, opt)
}
func getOpt(limit, page int) func(*index.Options) {
skip := (page - 1) * limit
opt := func(opt *index.Options) {
opt.Reverse = true
if limit > 0 {
opt.Limit = limit
}
if skip > 0 {
opt.Skip = skip
}
}
return opt
}

33
server/dbdata/db_test.go Normal file
View File

@@ -0,0 +1,33 @@
package dbdata
import (
"os"
"path"
"testing"
"github.com/bjdgyc/anylink/base"
"github.com/stretchr/testify/assert"
)
func preIpData() {
tmpDb := path.Join(os.TempDir(), "anylink_test.db")
base.Cfg.DbFile = tmpDb
initDb()
}
func closeIpdata() {
sdb.Close()
tmpDb := path.Join(os.TempDir(), "anylink_test.db")
os.Remove(tmpDb)
}
func TestDb(t *testing.T) {
assert := assert.New(t)
preIpData()
defer closeIpdata()
u := User{Username: "a"}
_ = Save(&u)
assert.Equal(u.Id, 1)
}

134
server/dbdata/group.go Normal file
View File

@@ -0,0 +1,134 @@
package dbdata
import (
"errors"
"fmt"
"net"
"time"
"github.com/bjdgyc/anylink/base"
)
const (
Allow = "allow"
Deny = "deny"
)
type GroupLinkAcl struct {
// 自上而下匹配 默认 allow * *
Action string `json:"action"` // allow、deny
Val string `json:"val"`
Port uint16 `json:"port"`
IpNet *net.IPNet `json:"ip_net"`
Note string `json:"note"`
}
type ValData struct {
Val string `json:"val"`
IpMask string `json:"ip_mask"`
Note string `json:"note"`
}
type Group struct {
Id int `json:"id" storm:"id,increment"`
Name string `json:"name" storm:"unique"`
Note string `json:"note"`
AllowLan bool `json:"allow_lan"`
ClientDns []ValData `json:"client_dns"`
RouteInclude []ValData `json:"route_include"`
RouteExclude []ValData `json:"route_exclude"`
LinkAcl []GroupLinkAcl `json:"link_acl"`
Bandwidth int `json:"bandwidth"` // 带宽限制
Status int8 `json:"status"` // 1正常
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func GetGroupNames() []string {
var datas []Group
err := All(&datas, 0, 0)
if err != nil {
base.Error(err)
return nil
}
var names []string
for _, v := range datas {
names = append(names, v.Name)
}
return names
}
func SetGroup(g *Group) error {
var err error
if g.Name == "" {
return errors.New("用户组名错误")
}
// 判断数据
clientDns := []ValData{}
for _, v := range g.ClientDns {
if v.Val != "" {
clientDns = append(clientDns, v)
}
}
if len(clientDns) == 0 {
return errors.New("DNS 错误")
}
g.ClientDns = clientDns
routeInclude := []ValData{}
for _, v := range g.RouteInclude {
if v.Val != "" {
ipMask, _, err := parseIpNet(v.Val)
if err != nil {
return errors.New("RouteInclude 错误" + err.Error())
}
v.IpMask = ipMask
routeInclude = append(routeInclude, v)
}
}
g.RouteInclude = routeInclude
routeExclude := []ValData{}
for _, v := range g.RouteExclude {
if v.Val != "" {
ipMask, _, err := parseIpNet(v.Val)
if err != nil {
return errors.New("RouteExclude 错误" + err.Error())
}
v.IpMask = ipMask
routeExclude = append(routeExclude, v)
}
}
g.RouteExclude = routeExclude
// 转换数据
linkAcl := []GroupLinkAcl{}
for _, v := range g.LinkAcl {
if v.Val != "" {
_, ipNet, err := parseIpNet(v.Val)
if err != nil {
return errors.New("GroupLinkAcl 错误" + err.Error())
}
v.IpNet = ipNet
linkAcl = append(linkAcl, v)
}
}
g.LinkAcl = linkAcl
g.UpdatedAt = time.Now()
err = Save(g)
return err
}
func parseIpNet(s string) (string, *net.IPNet, error) {
ip, ipNet, err := net.ParseCIDR(s)
if err != nil {
return "", nil, err
}
mask := net.IP(ipNet.Mask)
ipMask := fmt.Sprintf("%s/%s", ip, mask)
return ipMask, ipNet, nil
}

18
server/dbdata/ip_map.go Normal file
View File

@@ -0,0 +1,18 @@
package dbdata
import (
"net"
"time"
)
type IpMap struct {
Id int `json:"id" storm:"id,increment"`
IpAddr net.IP `json:"ip_addr" storm:"unique"`
MacAddr string `json:"mac_addr" storm:"unique"`
Username string `json:"username"`
Keep bool `json:"keep"` // 保留 ip-mac 绑定
KeepTime time.Time `json:"keep_time"`
Note string `json:"note"` // 备注
LastLogin time.Time `json:"last_login"`
UpdatedAt time.Time `json:"updated_at"`
}

47
server/dbdata/setting.go Normal file
View File

@@ -0,0 +1,47 @@
package dbdata
import (
"reflect"
)
const (
SettingBucket = "SettingBucket"
Installed = "Installed"
)
func StructName(data interface{}) string {
ref := reflect.ValueOf(data)
s := &ref
if s.Kind() == reflect.Ptr {
e := s.Elem()
s = &e
}
name := s.Type().Name()
return name
}
func SettingSet(data interface{}) error {
key := StructName(data)
err := Set(SettingBucket, key, data)
return err
}
func SettingGet(data interface{}) error {
key := StructName(data)
err := Get(SettingBucket, key, data)
return err
}
type SettingSmtp struct {
Host string `json:"host"`
Port int `json:"port"`
Username string `json:"username"`
Password string `json:"password"`
From string `json:"from"`
UseSSl bool `json:"use_ssl"`
}
type SettingOther struct {
Banner string `json:"banner"`
AccountMail string `json:"account_mail"`
}

10
server/dbdata/start.go Normal file
View File

@@ -0,0 +1,10 @@
package dbdata
func Start() {
initDb()
initData()
}
func Stop() error {
return sdb.Close()
}

146
server/dbdata/user.go Normal file
View File

@@ -0,0 +1,146 @@
package dbdata
import (
"errors"
"fmt"
"sync"
"time"
"github.com/bjdgyc/anylink/pkg/utils"
"github.com/xlzd/gotp"
)
type User struct {
Id int `json:"id" storm:"id,increment"`
Username string `json:"username" storm:"unique"`
Nickname string `json:"nickname"`
Email string `json:"email"`
// Password string `json:"password"`
PinCode string `json:"pin_code"`
OtpSecret string `json:"otp_secret"`
DisableOtp bool `json:"disable_otp"` // 禁用otp
Groups []string `json:"groups"`
Status int8 `json:"status"` // 1正常
SendEmail bool `json:"send_email"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func SetUser(v *User) error {
var err error
if v.Username == "" || len(v.Groups) == 0 {
return errors.New("用户名或组错误")
}
planPass := v.PinCode
// 自动生成密码
if len(planPass) < 6 {
planPass = utils.RandomNum(8)
}
v.PinCode = planPass
if v.OtpSecret == "" {
v.OtpSecret = gotp.RandomSecret(32)
}
// 判断组是否有效
ng := []string{}
groups := GetGroupNames()
for _, g := range v.Groups {
if utils.InArrStr(groups, g) {
ng = append(ng, g)
}
}
if len(ng) == 0 {
return errors.New("用户名或组错误")
}
v.Groups = ng
v.UpdatedAt = time.Now()
err = Save(v)
return err
}
// 验证用户登陆信息
func CheckUser(name, pwd, group string) error {
// return nil
pl := len(pwd)
if name == "" || pl < 6 {
return fmt.Errorf("%s %s", name, "密码错误")
}
v := &User{}
err := One("Username", name, v)
if err != nil || v.Status != 1 {
return fmt.Errorf("%s %s", name, "用户名错误")
}
// 判断用户组信息
if !utils.InArrStr(v.Groups, group) {
return fmt.Errorf("%s %s", name, "用户组错误")
}
groupData := &Group{}
err = One("Name", group, groupData)
if err != nil || groupData.Status != 1 {
return fmt.Errorf("%s %s", name, "用户组错误")
}
// 判断otp信息
if !v.DisableOtp {
pwd = pwd[:pl-6]
otp := pwd[pl-6:]
if !checkOtp(name, otp, v.OtpSecret) {
return fmt.Errorf("%s %s", name, "动态码错误")
}
}
// 判断用户密码
if pwd != v.PinCode {
return fmt.Errorf("%s %s", name, "密码错误")
}
return nil
}
var (
userOtpMux = sync.Mutex{}
userOtp = map[string]time.Time{}
)
func init() {
go func() {
expire := time.Second * 60
for range time.Tick(time.Second * 10) {
tnow := time.Now()
userOtpMux.Lock()
for k, v := range userOtp {
if tnow.After(v.Add(expire)) {
delete(userOtp, k)
}
}
userOtpMux.Unlock()
}
}()
}
// 判断令牌信息
func checkOtp(name, otp, secret string) bool {
key := fmt.Sprintf("%s:%s", name, otp)
userOtpMux.Lock()
defer userOtpMux.Unlock()
// 令牌只能使用一次
if _, ok := userOtp[key]; ok {
// 已经存在
return false
}
userOtp[key] = time.Now()
totp := gotp.NewDefaultTOTP(secret)
unix := time.Now().Unix()
verify := totp.Verify(otp, int(unix))
return verify
}