initial commit

This commit is contained in:
Alireza Ahmadi
2024-02-13 01:17:03 +01:00
commit f40b27fd8b
136 changed files with 16023 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
package service
import (
"encoding/json"
"s-ui/database"
"s-ui/database/model"
"s-ui/logger"
"strings"
"time"
"gorm.io/gorm"
)
type ClientService struct {
}
func (s *ClientService) GetAll() (string, error) {
db := database.GetDB()
clients := []model.Client{}
err := db.Model(model.Client{}).Scan(&clients).Error
if err != nil {
return "", err
}
data, err := json.Marshal(clients)
if err != nil {
return "", err
}
return string(data), nil
}
func (s *ClientService) Save(tx *gorm.DB, changes []model.Changes) error {
var err error
for _, change := range changes {
client := model.Client{}
err = json.Unmarshal(change.Obj, &client)
if err != nil {
return err
}
switch change.Action {
case "new":
err = tx.Create(&client).Error
case "del":
err = tx.Where("id = ?", change.Index).Delete(model.Client{}).Error
default:
err = tx.Save(client).Error
}
if err != nil {
return err
}
}
return err
}
func (s *ClientService) DepleteClients() ([]string, []string, error) {
var err error
var clients []model.Client
var changes []model.Changes
now := time.Now().Unix()
db := database.GetDB()
err = db.Model(model.Client{}).Where("enable = true AND ((volume >0 AND up+down > volume) OR (expiry > 0 AND expiry < ?))", now).Scan(&clients).Error
if err != nil {
return nil, nil, err
}
var users, inbounds []string
for _, client := range clients {
logger.Debug("Client ", client.Name, " is going to be disabled")
users = append(users, client.Name)
userInbounds := strings.Split(client.Inbounds, ",")
inbounds = append(inbounds, userInbounds...)
changes = append(changes, model.Changes{
DateTime: time.Now().Unix(),
Actor: "DepleteJob",
Key: "clients",
Action: "disable",
Obj: json.RawMessage(client.Name),
})
}
// Save changes
if len(changes) > 0 {
err = db.Model(model.Client{}).Where("enable = true AND ((volume >0 AND up+down > volume) OR (expiry > 0 AND expiry < ?))", now).Update("enable", false).Error
if err != nil {
return nil, nil, err
}
err = db.Model(model.Changes{}).Create(&changes).Error
if err != nil {
return nil, nil, err
}
}
return users, inbounds, nil
}
+322
View File
@@ -0,0 +1,322 @@
package service
import (
"encoding/json"
"os"
"s-ui/config"
"s-ui/database"
"s-ui/database/model"
"s-ui/singbox"
"time"
)
var ApiAddr string
type ConfigService struct {
ClientService
singbox.Controller
SettingService
}
type SingBoxConfig struct {
Log json.RawMessage `json:"log"`
Dns json.RawMessage `json:"dns"`
Ntp json.RawMessage `json:"ntp"`
Inbounds []json.RawMessage `json:"inbounds"`
Outbounds []json.RawMessage `json:"outbounds"`
Route json.RawMessage `json:"route"`
Experimental json.RawMessage `json:"experimental"`
}
func NewConfigService() *ConfigService {
return &ConfigService{}
}
func (s *ConfigService) InitConfig() error {
configPath := config.GetBinFolderPath()
data, err := os.ReadFile(configPath + "/config.json")
if err != nil {
if os.IsNotExist(err) {
defaultConfig := []byte(config.GetDefaultConfig())
err = os.MkdirAll(configPath, 01764)
if err != nil {
return err
}
err = os.WriteFile(configPath+"/config.json", defaultConfig, 0764)
if err != nil {
return err
}
data = defaultConfig
} else {
return err
}
}
return s.RefreshApiAddr(&data)
}
func (s *ConfigService) GetConfig() (*[]byte, error) {
configPath := config.GetBinFolderPath()
data, err := os.ReadFile(configPath + "/config.json")
if err != nil {
return nil, err
}
return &data, nil
}
func (s *ConfigService) SaveChanges(changes map[string]string, loginUser string) error {
var err error
var clientChanges, settingChanges, configChanges []model.Changes
if _, ok := changes["clients"]; ok {
err = json.Unmarshal([]byte(changes["clients"]), &clientChanges)
if err != nil {
return err
}
}
if _, ok := changes["settings"]; ok {
err = json.Unmarshal([]byte(changes["settings"]), &settingChanges)
if err != nil {
return err
}
}
if _, ok := changes["config"]; ok {
err = json.Unmarshal([]byte(changes["config"]), &configChanges)
if err != nil {
return err
}
}
db := database.GetDB()
tx := db.Begin()
defer func() {
if err == nil {
tx.Commit()
} else {
tx.Rollback()
}
}()
if len(clientChanges) > 0 {
err = s.ClientService.Save(tx, clientChanges)
if err != nil {
return err
}
}
if len(settingChanges) > 0 {
err = s.SettingService.Save(tx, settingChanges)
if err != nil {
return err
}
}
if len(configChanges) > 0 {
singboxConfig, err := s.GetConfig()
if err != nil {
return err
}
newConfig := SingBoxConfig{}
err = json.Unmarshal(*singboxConfig, &newConfig)
if err != nil {
return err
}
for _, change := range configChanges {
rawObject := change.Obj
switch change.Key {
case "all":
err = json.Unmarshal(rawObject, &newConfig)
if err != nil {
return err
}
case "log":
newConfig.Log = rawObject
case "dns":
newConfig.Dns = rawObject
case "ntp":
newConfig.Ntp = rawObject
case "route":
newConfig.Route = rawObject
case "experimental":
newConfig.Experimental = rawObject
case "inbounds":
if change.Action == "edit" {
newConfig.Inbounds[change.Index] = rawObject
} else if change.Action == "del" {
newConfig.Inbounds = append(newConfig.Inbounds[:change.Index], newConfig.Inbounds[change.Index+1:]...)
} else {
newConfig.Inbounds = append(newConfig.Inbounds, rawObject)
}
case "outbounds":
if change.Action == "edit" {
newConfig.Outbounds[change.Index] = rawObject
} else {
newConfig.Outbounds = append(newConfig.Outbounds, rawObject)
}
}
}
// Save to config.json
data, err := json.MarshalIndent(newConfig, "", " ")
if err != nil {
return err
}
err = s.Save(&data)
if err != nil {
return err
}
}
// Log changes
dt := time.Now().Unix()
allChanges := append(append(clientChanges, settingChanges...), configChanges...)
for index := range allChanges {
allChanges[index].DateTime = dt
allChanges[index].Actor = loginUser
}
err = tx.Model(model.Changes{}).Create(&allChanges).Error
if err != nil {
return err
}
return nil
}
func (s *ConfigService) CheckChnages(lu string) (bool, error) {
if lu == "" {
return true, nil
}
db := database.GetDB()
var count int64
err := db.Model(model.Changes{}).Where("date_time > " + lu).Count(&count).Error
return count > 0, err
}
func (s *ConfigService) Save(data *[]byte) error {
configPath := config.GetBinFolderPath()
_, err := os.Stat(configPath + "/config.json")
if os.IsNotExist(err) {
err = os.MkdirAll(configPath, 01764)
if err != nil {
return err
}
} else if err != nil {
return err
}
err = os.WriteFile(configPath+"/config.json", *data, 0764)
if err != nil {
return err
}
s.RefreshApiAddr(data)
s.Controller.Restart()
return nil
}
func (s *ConfigService) RefreshApiAddr(data *[]byte) error {
Env_API := config.GetEnvApi()
if len(Env_API) > 0 {
ApiAddr = Env_API
} else {
var err error
if data == nil {
data, err = s.GetConfig()
if err != nil {
return err
}
}
singboxConfig := SingBoxConfig{}
err = json.Unmarshal(*data, &singboxConfig)
if err != nil {
return err
}
var experimental struct {
V2rayApi struct {
Listen string `json:"listen"`
Stats interface{} `jaon:"stats"`
} `json:"v2ray_api"`
}
err = json.Unmarshal(singboxConfig.Experimental, &experimental)
if err != nil {
return err
}
ApiAddr = experimental.V2rayApi.Listen
}
return nil
}
func (s *ConfigService) DepleteClients() error {
users, inbounds, err := s.ClientService.DepleteClients()
if err != nil || len(users) == 0 || len(inbounds) == 0 {
return err
}
singboxConfig, err := s.GetConfig()
if err != nil {
return err
}
newConfig := SingBoxConfig{}
err = json.Unmarshal(*singboxConfig, &newConfig)
if err != nil {
return err
}
for inbound_index, inbound := range newConfig.Inbounds {
var inboundJson map[string]interface{}
json.Unmarshal(inbound, &inboundJson)
if s.contains(inbounds, inboundJson["tag"].(string)) {
inbound_users, ok := inboundJson["users"].([]interface{})
if ok {
var updatedUsers []interface{}
for _, user := range inbound_users {
userMap, ok := user.(map[string]interface{})
if ok {
name, exists := userMap["name"].(string)
if exists && s.contains(users, name) {
// Skip the user exists
continue
}
username, exists := userMap["username"].(string)
if exists && s.contains(users, username) {
// Skip the username exists
continue
}
}
updatedUsers = append(updatedUsers, user)
}
// Exception for Naive and ShadowTLSv3
if len(updatedUsers) == 0 {
if inboundJson["type"].(string) == "naive" ||
(inboundJson["type"].(string) == "shadowtls" &&
inboundJson["version"].(float64) == 3) {
updatedUsers = append(updatedUsers, make(map[string]interface{}))
}
}
inboundJson["users"] = updatedUsers
}
}
modifiedInbound, err := json.MarshalIndent(inboundJson, "", " ")
if err != nil {
return err
}
newConfig.Inbounds[inbound_index] = modifiedInbound
}
modifiedConfig, err := json.MarshalIndent(newConfig, "", " ")
if err != nil {
return err
}
err = s.Save(&modifiedConfig)
if err != nil {
return err
}
return nil
}
func (s *ConfigService) contains(slice []string, item string) bool {
for _, str := range slice {
if str == item {
return true
}
}
return false
}
+26
View File
@@ -0,0 +1,26 @@
package service
import (
"os"
"s-ui/logger"
"syscall"
"time"
)
type PanelService struct {
}
func (s *PanelService) RestartPanel(delay time.Duration) error {
p, err := os.FindProcess(syscall.Getpid())
if err != nil {
return err
}
go func() {
time.Sleep(delay)
err := p.Signal(syscall.SIGHUP)
if err != nil {
logger.Error("send signal SIGHUP failed:", err)
}
}()
return nil
}
+137
View File
@@ -0,0 +1,137 @@
package service
import (
"os"
"runtime"
"s-ui/config"
"s-ui/logger"
"strings"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/host"
"github.com/shirou/gopsutil/v3/mem"
"github.com/shirou/gopsutil/v3/net"
)
type ServerService struct {
SingBoxService
}
func (s *ServerService) GetStatus(request string) *map[string]interface{} {
status := make(map[string]interface{}, 0)
requests := strings.Split(request, ",")
for _, req := range requests {
switch req {
case "cpu":
status["cpu"] = s.GetCpuPercent()
case "mem":
status["mem"] = s.GetMemInfo()
case "net":
status["net"] = s.GetNetInfo()
case "sys":
status["uptime"] = s.GetUptime()
status["sys"] = s.GetSystemInfo()
case "sbd":
status["sbd"] = s.GetSingboxInfo()
}
}
return &status
}
func (s *ServerService) GetCpuPercent() float64 {
percents, err := cpu.Percent(0, false)
if err != nil {
logger.Warning("get cpu percent failed:", err)
return 0
} else {
return percents[0]
}
}
func (s *ServerService) GetUptime() uint64 {
upTime, err := host.Uptime()
if err != nil {
logger.Warning("get uptime failed:", err)
return 0
} else {
return upTime
}
}
func (s *ServerService) GetMemInfo() map[string]interface{} {
info := make(map[string]interface{}, 0)
memInfo, err := mem.VirtualMemory()
if err != nil {
logger.Warning("get virtual memory failed:", err)
} else {
info["current"] = memInfo.Used
info["total"] = memInfo.Total
}
return info
}
func (s *ServerService) GetNetInfo() map[string]interface{} {
info := make(map[string]interface{}, 0)
ioStats, err := net.IOCounters(false)
if err != nil {
logger.Warning("get io counters failed:", err)
} else if len(ioStats) > 0 {
ioStat := ioStats[0]
info["sent"] = ioStat.BytesSent
info["recv"] = ioStat.BytesRecv
info["psent"] = ioStat.PacketsSent
info["precv"] = ioStat.PacketsRecv
} else {
logger.Warning("can not find io counters")
}
return info
}
func (s *ServerService) GetSingboxInfo() map[string]interface{} {
info := make(map[string]interface{}, 0)
if s.SingBoxService.IsRunning() {
info["running"] = true
sysStats, _ := s.SingBoxService.GetSysStats()
info["stats"] = sysStats
} else {
info["running"] = false
}
return info
}
func (s *ServerService) GetSystemInfo() map[string]interface{} {
info := make(map[string]interface{}, 0)
var rtm runtime.MemStats
runtime.ReadMemStats(&rtm)
info["appMem"] = rtm.Sys
info["appThreads"] = uint32(runtime.NumGoroutine())
cpuInfo, err := cpu.Info()
if err == nil {
info["cpuType"] = cpuInfo[0].ModelName
}
info["cpuCount"] = runtime.NumCPU()
info["hostName"], _ = os.Hostname()
info["appVersion"] = config.GetVersion()
ipv4 := make([]string, 0)
ipv6 := make([]string, 0)
// get ip address
netInterfaces, _ := net.Interfaces()
for i := 0; i < len(netInterfaces); i++ {
if len(netInterfaces[i].Flags) > 2 && netInterfaces[i].Flags[0] == "up" && netInterfaces[i].Flags[1] != "loopback" {
addrs := netInterfaces[i].Addrs
for _, address := range addrs {
if strings.Contains(address.Addr, ".") {
ipv4 = append(ipv4, address.Addr)
} else if address.Addr[0:6] != "fe80::" {
ipv6 = append(ipv6, address.Addr)
}
}
}
}
info["ipv4"] = ipv4
info["ipv6"] = ipv6
return info
}
+292
View File
@@ -0,0 +1,292 @@
package service
import (
"encoding/json"
"os"
"s-ui/database"
"s-ui/database/model"
"s-ui/logger"
"s-ui/util/common"
"strconv"
"strings"
"time"
"gorm.io/gorm"
)
var defaultValueMap = map[string]string{
"webListen": "",
"webDomain": "",
"webPort": "2095",
"webSecret": common.Random(32),
"webCertFile": "",
"webKeyFile": "",
"sessionMaxAge": "0",
"timeLocation": "Asia/Tehran",
"subListen": "",
"subPort": "2096",
"subPath": "/sub/",
"subDomain": "",
"subCertFile": "",
"subKeyFile": "",
"subUpdates": "12",
"subEncode": "true",
"subShowInfo": "false",
"subURI": "",
}
type SettingService struct {
}
func (s *SettingService) GetAllSetting() (*map[string]string, error) {
db := database.GetDB()
settings := make([]*model.Setting, 0)
err := db.Model(model.Setting{}).Find(&settings).Error
if err != nil {
return nil, err
}
allSetting := map[string]string{}
for _, setting := range settings {
allSetting[setting.Key] = setting.Value
}
for key, defaultValue := range defaultValueMap {
if _, exists := allSetting[key]; !exists {
err = s.saveSetting(key, defaultValue)
if err != nil {
return nil, err
}
allSetting[key] = defaultValue
}
}
// Due to security principles
delete(allSetting, "webSecret")
return &allSetting, nil
}
func (s *SettingService) getSetting(key string) (*model.Setting, error) {
db := database.GetDB()
setting := &model.Setting{}
err := db.Model(model.Setting{}).Where("key = ?", key).First(setting).Error
if err != nil {
return nil, err
}
return setting, nil
}
func (s *SettingService) getString(key string) (string, error) {
setting, err := s.getSetting(key)
if database.IsNotFound(err) {
value, ok := defaultValueMap[key]
if !ok {
return "", common.NewErrorf("key <%v> not in defaultValueMap", key)
}
return value, nil
} else if err != nil {
return "", err
}
return setting.Value, nil
}
func (s *SettingService) saveSetting(key string, value string) error {
setting, err := s.getSetting(key)
db := database.GetDB()
if database.IsNotFound(err) {
return db.Create(&model.Setting{
Key: key,
Value: value,
}).Error
} else if err != nil {
return err
}
setting.Key = key
setting.Value = value
return db.Save(setting).Error
}
func (s *SettingService) setString(key string, value string) error {
return s.saveSetting(key, value)
}
func (s *SettingService) getBool(key string) (bool, error) {
str, err := s.getString(key)
if err != nil {
return false, err
}
return strconv.ParseBool(str)
}
func (s *SettingService) setBool(key string, value bool) error {
return s.setString(key, strconv.FormatBool(value))
}
func (s *SettingService) getInt(key string) (int, error) {
str, err := s.getString(key)
if err != nil {
return 0, err
}
return strconv.Atoi(str)
}
func (s *SettingService) setInt(key string, value int) error {
return s.setString(key, strconv.Itoa(value))
}
func (s *SettingService) GetListen() (string, error) {
return s.getString("webListen")
}
func (s *SettingService) GetWebDomain() (string, error) {
return s.getString("webDomain")
}
func (s *SettingService) GetPort() (int, error) {
return s.getInt("webPort")
}
func (s *SettingService) SetPort(port int) error {
return s.setInt("webPort", port)
}
func (s *SettingService) GetCertFile() (string, error) {
return s.getString("webCertFile")
}
func (s *SettingService) GetKeyFile() (string, error) {
return s.getString("webKeyFile")
}
func (s *SettingService) GetSecret() ([]byte, error) {
secret, err := s.getString("webSecret")
if secret == defaultValueMap["webSecret"] {
err := s.saveSetting("webSecret", secret)
if err != nil {
logger.Warning("save webSecret failed:", err)
}
}
return []byte(secret), err
}
func (s *SettingService) GetSessionMaxAge() (int, error) {
return s.getInt("sessionMaxAge")
}
func (s *SettingService) GetTimeLocation() (*time.Location, error) {
l, err := s.getString("timeLocation")
if err != nil {
return nil, err
}
location, err := time.LoadLocation(l)
if err != nil {
defaultLocation := defaultValueMap["timeLocation"]
logger.Errorf("location <%v> not exist, using default location: %v", l, defaultLocation)
return time.LoadLocation(defaultLocation)
}
return location, nil
}
func (s *SettingService) GetSubListen() (string, error) {
return s.getString("subListen")
}
func (s *SettingService) GetSubPort() (int, error) {
return s.getInt("subPort")
}
func (s *SettingService) GetSubPath() (string, error) {
subPath, err := s.getString("subPath")
if err != nil {
return "", err
}
if !strings.HasPrefix(subPath, "/") {
subPath = "/" + subPath
}
if !strings.HasSuffix(subPath, "/") {
subPath += "/"
}
return subPath, nil
}
func (s *SettingService) GetSubDomain() (string, error) {
return s.getString("subDomain")
}
func (s *SettingService) GetSubCertFile() (string, error) {
return s.getString("subCertFile")
}
func (s *SettingService) GetSubKeyFile() (string, error) {
return s.getString("subKeyFile")
}
func (s *SettingService) GetSubUpdates() (int, error) {
return s.getInt("subUpdates")
}
func (s *SettingService) GetSubEncode() (bool, error) {
return s.getBool("subEncode")
}
func (s *SettingService) GetSubShowInfo() (bool, error) {
return s.getBool("subShowInfo")
}
func (s *SettingService) GetSubURI() (string, error) {
return s.getString("subURI")
}
func (s *SettingService) GetFinalSubURI(host string) (string, error) {
allSetting, err := s.GetAllSetting()
if err != nil {
return "", err
}
SubURI := (*allSetting)["subURI"]
if SubURI != "" {
return SubURI, nil
}
protocol := "http"
if (*allSetting)["subKeyFile"] != "" && (*allSetting)["subCertFile"] != "" {
protocol = "https"
}
if (*allSetting)["subDomain"] != "" {
host = (*allSetting)["subDomain"]
}
port := ":" + (*allSetting)["subPort"]
if (port == "80" && protocol == "http") || (port == "443" && protocol == "https") {
port = ""
}
return protocol + "://" + host + port + (*allSetting)["subPath"], nil
}
func (s *SettingService) Save(tx *gorm.DB, changes []model.Changes) error {
var err error
for _, change := range changes {
key := change.Key
var obj string
json.Unmarshal(change.Obj, &obj)
// Secure file existance check
if key == "webCertFile" ||
key == "webKeyFile" ||
key == "subCertFile" ||
key == "subKeyFile" {
err = s.fileExists(obj)
if err != nil {
return common.NewError(" -> ", obj, " is not exists")
}
}
err = tx.Model(model.Setting{}).Where("key = ?", key).Update("value", obj).Error
if err != nil {
return err
}
}
return err
}
func (s *SettingService) fileExists(path string) error {
_, err := os.Stat(path)
return err
}
+42
View File
@@ -0,0 +1,42 @@
package service
import (
"s-ui/singbox"
)
type SingBoxService struct {
singbox.V2rayAPI
singbox.Controller
StatsService
}
func (s *SingBoxService) GetStats() error {
s.V2rayAPI.Init(ApiAddr)
defer s.V2rayAPI.Close()
stats, err := s.V2rayAPI.GetStats(true)
if err != nil {
return err
}
err = s.StatsService.SaveStats(stats)
if err != nil {
return err
}
return nil
}
func (s *SingBoxService) GetSysStats() (*map[string]interface{}, error) {
s.V2rayAPI.Init(ApiAddr)
defer s.V2rayAPI.Close()
resp, err := s.V2rayAPI.GetSysStats()
if err != nil {
return nil, err
}
result := make(map[string]interface{})
result["NumGoroutine"] = resp.NumGoroutine
result["Alloc"] = resp.Alloc
result["Uptime"] = resp.Uptime
return &result, nil
}
+100
View File
@@ -0,0 +1,100 @@
package service
import (
"encoding/json"
"s-ui/database"
"s-ui/database/model"
"time"
"gorm.io/gorm"
)
type onlines struct {
Inbound []string `json:"inbound,omitempty"`
User []string `json:"user,omitempty"`
Outbound []string `json:"outbound,omitempty"`
}
var onlineResources = &onlines{}
type StatsService struct {
}
func (s *StatsService) SaveStats(stats []*model.Stats) error {
var err error
// Reset onlines
onlineResources.Inbound = nil
onlineResources.Outbound = nil
onlineResources.User = nil
if len(stats) == 0 {
return nil
}
db := database.GetDB()
tx := db.Begin()
defer func() {
if err == nil {
tx.Commit()
} else {
tx.Rollback()
}
}()
for _, stat := range stats {
if stat.Resource == "user" {
if stat.Direction {
err = tx.Model(model.Client{}).Where("name = ?", stat.Tag).
UpdateColumn("up", gorm.Expr("up + ?", stat.Traffic)).Error
} else {
err = tx.Model(model.Client{}).Where("name = ?", stat.Tag).
UpdateColumn("down", gorm.Expr("down + ?", stat.Traffic)).Error
}
if err != nil {
return err
}
}
if stat.Direction {
switch stat.Resource {
case "inbound":
onlineResources.Inbound = append(onlineResources.Inbound, stat.Tag)
case "outbound":
onlineResources.Outbound = append(onlineResources.Outbound, stat.Tag)
case "user":
onlineResources.User = append(onlineResources.User, stat.Tag)
}
}
}
err = tx.Create(&stats).Error
return err
}
func (s *StatsService) GetStats(resorce string, tag string, limit int) ([]model.Stats, error) {
var err error
var result []model.Stats
currentTime := time.Now().Unix()
timeDiff := currentTime - (int64(limit) * 3600)
db := database.GetDB()
err = db.Model(model.Stats{}).Where("resource = ? AND tag = ? AND date_time > ?", resorce, tag, timeDiff).Scan(&result).Error
if err != nil {
return nil, err
}
return result, nil
}
func (s *StatsService) GetOnlines() (string, error) {
onlines, err := json.Marshal(onlineResources)
if err != nil {
return "", err
}
return string(onlines), nil
}
func (s *StatsService) DelOldStats(days int) error {
oldTime := time.Now().AddDate(0, 0, -(days)).Unix()
db := database.GetDB()
return db.Where("date_time < ?", oldTime).Delete(model.Stats{}).Error
}
+47
View File
@@ -0,0 +1,47 @@
package service
import (
"s-ui/database"
"s-ui/database/model"
"s-ui/logger"
"s-ui/util/common"
"time"
"gorm.io/gorm"
)
type UserService struct {
}
func (s *UserService) Login(username string, password string, remoteIP string) (string, error) {
user := s.CheckUser(username, password, remoteIP)
if user == nil {
return "", common.NewError("wrong user or password! IP: ", remoteIP)
}
return user.Username, nil
}
func (s *UserService) CheckUser(username string, password string, remoteIP string) *model.User {
db := database.GetDB()
user := &model.User{}
err := db.Model(model.User{}).
Where("username = ? and password = ?", username, password).
First(user).
Error
if err == gorm.ErrRecordNotFound {
return nil
} else if err != nil {
logger.Warning("check user err:", err, " IP: ", remoteIP)
return nil
}
lastLoginTxt := time.Now().Format("2006-01-02 15:04:05") + "-" + remoteIP
err = db.Model(model.User{}).
Where("username = ?", username).
Update("last_logins", &lastLoginTxt).Error
if err != nil {
logger.Warning("unable to log login data", err)
}
return user
}