Files
HY2XS_flamy/apps/service/peer.go
T

322 lines
8.4 KiB
Go

package service
import (
"errors"
"fmt"
"github.com/gin-gonic/gin"
"hy2xs-admin/dao"
"hy2xs-admin/model/bo"
"hy2xs-admin/model/constant"
"hy2xs-admin/model/dto"
"hy2xs-admin/model/entity"
"hy2xs-admin/model/vo"
"hy2xs-admin/util"
"time"
)
func Login(username string, plainPassword string) (string, bool, error) {
account, err := dao.GetAdminUser("username = ? and status = 1", username)
if err != nil {
return "", false, err
}
verified, legacy := util.VerifyPassword(plainPassword, *account.PasswordHash)
if !verified {
return "", false, errors.New(constant.WrongPassword)
}
if legacy {
hash, hashErr := util.HashPassword(plainPassword)
if hashErr == nil {
_ = dao.UpdateAdminUser([]int64{*account.Id}, map[string]interface{}{"password_hash": hash})
}
}
accountBo := bo.AccountBo{
Id: *account.Id,
Username: *account.Username,
Roles: []string{"admin"},
Deleted: 0,
}
token, tokenErr := GenToken(accountBo)
if tokenErr != nil {
return "", false, tokenErr
}
requirePasswordChange := legacy
if account.ForcePasswordChange != nil {
requirePasswordChange = *account.ForcePasswordChange != 0
}
return token, requirePasswordChange, nil
}
func PagePeer(peerPageDto dto.PeerPageDto) ([]entity.Account, int64, error) {
peers, total, err := dao.PagePeer(peerPageDto)
if err != nil {
return nil, 0, err
}
accounts := make([]entity.Account, 0, len(peers))
for _, p := range peers {
role := "user"
acc := entity.Account{
BaseEntity: p.BaseEntity,
Username: p.Name,
ConPass: p.SecretCiphertext,
Quota: p.QuotaBytes,
Download: p.DownloadBytes,
Upload: p.UploadBytes,
ExpireTime: p.ExpiresAt,
KickUtilTime: p.BannedUntil,
DeviceNo: p.MaxDevices,
Role: &role,
Deleted: p.Disabled,
ConAt: p.LastConnectionAt,
Remark: p.Remark,
}
accounts = append(accounts, acc)
}
return accounts, total, nil
}
func SavePeer(account entity.Account) error {
if account.Username == nil || *account.Username == "" {
return errors.New(constant.InvalidError)
}
secret := ""
if account.ConPass != nil && *account.ConPass != "" {
secret = *account.ConPass
} else {
generated, genErr := util.RandomString(24)
if genErr != nil {
return genErr
}
secret = fmt.Sprintf("%s.%s", *account.Username, generated)
}
authId, authErr := util.RandomString(18)
if authErr != nil {
return authErr
}
secretDigest := util.PeerSecretDigest(secret)
peer := entity.Peer{
Name: account.Username,
Remark: account.Remark,
AuthId: &authId,
SecretDigest: &secretDigest,
SecretCiphertext: &secret,
QuotaBytes: account.Quota,
ExpiresAt: account.ExpireTime,
MaxDevices: account.DeviceNo,
Disabled: account.Deleted,
}
_, err := dao.SavePeer(peer)
return err
}
func DeletePeer(ids []int64) error {
return dao.DeletePeer(ids)
}
func UpdatePeer(account entity.Account) error {
updates := map[string]interface{}{}
if account.Username != nil && *account.Username != "" {
updates["username"] = *account.Username
}
_ = account.Pass
if account.ConPass != nil && *account.ConPass != "" {
updates["secret_ciphertext"] = *account.ConPass
updates["secret_digest"] = util.PeerSecretDigest(*account.ConPass)
}
if account.Quota != nil {
updates["quota_bytes"] = *account.Quota
}
if account.ExpireTime != nil {
updates["expires_at"] = *account.ExpireTime
}
if account.Download != nil {
updates["download_bytes"] = *account.Download
}
if account.Upload != nil {
updates["upload_bytes"] = *account.Upload
}
if account.DeviceNo != nil {
updates["max_devices"] = *account.DeviceNo
}
if account.Deleted != nil {
updates["disabled"] = *account.Deleted
}
if account.LoginAt != nil && *account.LoginAt > 0 {
updates["login_at"] = *account.LoginAt
}
if account.ConAt != nil && *account.ConAt > 0 {
updates["last_connection_at"] = *account.ConAt
}
if account.Remark != nil {
updates["remark"] = *account.Remark
}
return dao.UpdatePeer([]int64{*account.Id}, updates)
}
func ResetTraffic(id int64) error {
return dao.UpdatePeer([]int64{id}, map[string]interface{}{"download_bytes": 0, "upload_bytes": 0})
}
func ExistPeerName(username string, id int64) bool {
var err error
if id != 0 {
_, err = dao.GetPeer("name = ? and id != ?", username, id)
} else {
_, err = dao.GetPeer("name = ?", username)
}
if err != nil {
if err.Error() == constant.WrongPassword {
return false
}
}
return true
}
func GetPeer(id int64) (entity.Account, error) {
peer, err := dao.GetPeer("id = ?", id)
if err != nil {
return entity.Account{}, err
}
role := "user"
return entity.Account{
BaseEntity: peer.BaseEntity,
Username: peer.Name,
ConPass: peer.SecretCiphertext,
Quota: peer.QuotaBytes,
Download: peer.DownloadBytes,
Upload: peer.UploadBytes,
ExpireTime: peer.ExpiresAt,
DeviceNo: peer.MaxDevices,
KickUtilTime: peer.BannedUntil,
ConAt: peer.LastConnectionAt,
Deleted: peer.Disabled,
Remark: peer.Remark,
Role: &role,
}, nil
}
func GetAdminAccount(id int64) (entity.AdminUser, error) {
return dao.GetAdminUser("id = ?", id)
}
func ListExportPeer() ([]bo.AccountExport, error) {
peers, err := dao.ListPeer("1=1")
if err != nil {
return nil, errors.New(constant.SysError)
}
var accountExports []bo.AccountExport
for _, item := range peers {
role := "user"
conPass := ""
if item.SecretCiphertext != nil {
conPass = *item.SecretCiphertext
}
accountExport := bo.AccountExport{
Id: *item.Id,
Username: *item.Name,
Pass: "",
ConPass: conPass,
Quota: *item.QuotaBytes,
Download: *item.DownloadBytes,
Upload: *item.UploadBytes,
ExpireTime: *item.ExpiresAt,
DeviceNo: *item.MaxDevices,
KickUtilTime: *item.BannedUntil,
Role: role,
Deleted: *item.Disabled,
CreateTime: *item.CreateTime,
UpdateTime: *item.UpdateTime,
LoginAt: 0,
ConAt: *item.LastConnectionAt,
Remark: *item.Remark,
}
accountExports = append(accountExports, accountExport)
}
return accountExports, nil
}
func ReleaseKickPeer(id int64) error {
return dao.UpdatePeer([]int64{id}, map[string]interface{}{"banned_until": 0})
}
func UpsertPeer(accounts []entity.Account) error {
for _, account := range accounts {
if account.Id != nil && *account.Id > 0 {
if err := UpdatePeer(account); err != nil {
return err
}
continue
}
if err := SavePeer(account); err != nil {
return err
}
}
return nil
}
func GetAdminInfo(c *gin.Context) (vo.AccountInfoVo, error) {
myClaims, err := ParseToken(GetToken(c))
if err != nil {
return vo.AccountInfoVo{}, err
}
if myClaims.Admin.Deleted != 0 {
return vo.AccountInfoVo{}, errors.New("this account has been disabled")
}
admin, err := dao.GetAdminUser("id = ?", myClaims.Admin.Id)
if err != nil {
return vo.AccountInfoVo{}, err
}
if admin.Status != nil && *admin.Status == 0 {
return vo.AccountInfoVo{}, errors.New("this account has been disabled")
}
return vo.AccountInfoVo{
Id: myClaims.Admin.Id,
Username: myClaims.Admin.Username,
Roles: myClaims.Admin.Roles,
}, nil
}
func UpdatePeerLastConnectionAt(id int64, conAt int64) error {
return dao.UpdatePeer([]int64{id}, map[string]interface{}{"last_connection_at": conAt})
}
func UpdateAdminLastLoginAt(id int64, loginAt int64) error {
return dao.UpdateAdminUser([]int64{id}, map[string]interface{}{"last_login_at": loginAt})
}
func ChangeAdminPassword(c *gin.Context, oldPassword string, newPassword string) error {
info, err := GetAdminInfo(c)
if err != nil {
return err
}
admin, err := dao.GetAdminUser("id = ?", info.Id)
if err != nil {
return err
}
if admin.PasswordHash == nil {
return errors.New(constant.SysError)
}
verified, _ := util.VerifyPassword(oldPassword, *admin.PasswordHash)
if !verified {
return errors.New(constant.WrongPassword)
}
hash, hashErr := util.HashPassword(newPassword)
if hashErr != nil {
return hashErr
}
nowMs := time.Now().UnixMilli()
currentTokenVersion := int64(1)
if admin.TokenVersion != nil && *admin.TokenVersion > 0 {
currentTokenVersion = *admin.TokenVersion
}
return dao.UpdateAdminUser([]int64{info.Id}, map[string]interface{}{
"password_hash": hash,
"force_password_change": 0,
"password_changed_at": nowMs,
"token_version": currentTokenVersion + 1,
})
}