github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/models/user.go (about) 1 package model 2 3 import ( 4 "crypto/md5" 5 "crypto/sha1" 6 "encoding/gob" 7 "encoding/hex" 8 "encoding/json" 9 "strings" 10 11 "github.com/cloudreve/Cloudreve/v3/pkg/util" 12 "github.com/jinzhu/gorm" 13 "github.com/pkg/errors" 14 ) 15 16 const ( 17 // Active 账户正常状态 18 Active = iota 19 // NotActivicated 未激活 20 NotActivicated 21 // Baned 被封禁 22 Baned 23 // OveruseBaned 超额使用被封禁 24 OveruseBaned 25 ) 26 27 // User 用户模型 28 type User struct { 29 // 表字段 30 gorm.Model 31 Email string `gorm:"type:varchar(100);unique_index"` 32 Nick string `gorm:"size:50"` 33 Password string `json:"-"` 34 Status int 35 GroupID uint 36 Storage uint64 37 TwoFactor string 38 Avatar string 39 Options string `json:"-" gorm:"size:4294967295"` 40 Authn string `gorm:"size:4294967295"` 41 42 // 关联模型 43 Group Group `gorm:"save_associations:false:false"` 44 Policy Policy `gorm:"PRELOAD:false,association_autoupdate:false"` 45 46 // 数据库忽略字段 47 OptionsSerialized UserOption `gorm:"-"` 48 } 49 50 func init() { 51 gob.Register(User{}) 52 } 53 54 // UserOption 用户个性化配置字段 55 type UserOption struct { 56 ProfileOff bool `json:"profile_off,omitempty"` 57 PreferredTheme string `json:"preferred_theme,omitempty"` 58 } 59 60 // Root 获取用户的根目录 61 func (user *User) Root() (*Folder, error) { 62 var folder Folder 63 err := DB.Where("parent_id is NULL AND owner_id = ?", user.ID).First(&folder).Error 64 return &folder, err 65 } 66 67 // DeductionStorage 减少用户已用容量 68 func (user *User) DeductionStorage(size uint64) bool { 69 if size == 0 { 70 return true 71 } 72 if size <= user.Storage { 73 user.Storage -= size 74 DB.Model(user).Update("storage", gorm.Expr("storage - ?", size)) 75 return true 76 } 77 // 如果要减少的容量超出已用容量,则设为零 78 user.Storage = 0 79 DB.Model(user).Update("storage", 0) 80 81 return false 82 } 83 84 // IncreaseStorage 检查并增加用户已用容量 85 func (user *User) IncreaseStorage(size uint64) bool { 86 if size == 0 { 87 return true 88 } 89 if size <= user.GetRemainingCapacity() { 90 user.Storage += size 91 DB.Model(user).Update("storage", gorm.Expr("storage + ?", size)) 92 return true 93 } 94 return false 95 } 96 97 // ChangeStorage 更新用户容量 98 func (user *User) ChangeStorage(tx *gorm.DB, operator string, size uint64) error { 99 return tx.Model(user).Update("storage", gorm.Expr("storage "+operator+" ?", size)).Error 100 } 101 102 // IncreaseStorageWithoutCheck 忽略可用容量,增加用户已用容量 103 func (user *User) IncreaseStorageWithoutCheck(size uint64) { 104 if size == 0 { 105 return 106 } 107 user.Storage += size 108 DB.Model(user).Update("storage", gorm.Expr("storage + ?", size)) 109 110 } 111 112 // GetRemainingCapacity 获取剩余配额 113 func (user *User) GetRemainingCapacity() uint64 { 114 total := user.Group.MaxStorage 115 if total <= user.Storage { 116 return 0 117 } 118 return total - user.Storage 119 } 120 121 // GetPolicyID 获取用户当前的存储策略ID 122 func (user *User) GetPolicyID(prefer uint) uint { 123 if len(user.Group.PolicyList) > 0 { 124 return user.Group.PolicyList[0] 125 } 126 return 0 127 } 128 129 // GetUserByID 用ID获取用户 130 func GetUserByID(ID interface{}) (User, error) { 131 var user User 132 result := DB.Set("gorm:auto_preload", true).First(&user, ID) 133 return user, result.Error 134 } 135 136 // GetActiveUserByID 用ID获取可登录用户 137 func GetActiveUserByID(ID interface{}) (User, error) { 138 var user User 139 result := DB.Set("gorm:auto_preload", true).Where("status = ?", Active).First(&user, ID) 140 return user, result.Error 141 } 142 143 // GetActiveUserByOpenID 用OpenID获取可登录用户 144 func GetActiveUserByOpenID(openid string) (User, error) { 145 var user User 146 result := DB.Set("gorm:auto_preload", true).Where("status = ? and open_id = ?", Active, openid).Find(&user) 147 return user, result.Error 148 } 149 150 // GetUserByEmail 用Email获取用户 151 func GetUserByEmail(email string) (User, error) { 152 var user User 153 result := DB.Set("gorm:auto_preload", true).Where("email = ?", email).First(&user) 154 return user, result.Error 155 } 156 157 // GetActiveUserByEmail 用Email获取可登录用户 158 func GetActiveUserByEmail(email string) (User, error) { 159 var user User 160 result := DB.Set("gorm:auto_preload", true).Where("status = ? and email = ?", Active, email).First(&user) 161 return user, result.Error 162 } 163 164 // NewUser 返回一个新的空 User 165 func NewUser() User { 166 options := UserOption{} 167 return User{ 168 OptionsSerialized: options, 169 } 170 } 171 172 // BeforeSave Save用户前的钩子 173 func (user *User) BeforeSave() (err error) { 174 err = user.SerializeOptions() 175 return err 176 } 177 178 // AfterCreate 创建用户后的钩子 179 func (user *User) AfterCreate(tx *gorm.DB) (err error) { 180 // 创建用户的默认根目录 181 defaultFolder := &Folder{ 182 Name: "/", 183 OwnerID: user.ID, 184 } 185 tx.Create(defaultFolder) 186 return err 187 } 188 189 // AfterFind 找到用户后的钩子 190 func (user *User) AfterFind() (err error) { 191 // 解析用户设置到OptionsSerialized 192 if user.Options != "" { 193 err = json.Unmarshal([]byte(user.Options), &user.OptionsSerialized) 194 } 195 196 // 预加载存储策略 197 user.Policy, _ = GetPolicyByID(user.GetPolicyID(0)) 198 return err 199 } 200 201 //SerializeOptions 将序列后的Option写入到数据库字段 202 func (user *User) SerializeOptions() (err error) { 203 optionsValue, err := json.Marshal(&user.OptionsSerialized) 204 user.Options = string(optionsValue) 205 return err 206 } 207 208 // CheckPassword 根据明文校验密码 209 func (user *User) CheckPassword(password string) (bool, error) { 210 211 // 根据存储密码拆分为 Salt 和 Digest 212 passwordStore := strings.Split(user.Password, ":") 213 if len(passwordStore) != 2 && len(passwordStore) != 3 { 214 return false, errors.New("Unknown password type") 215 } 216 217 // 兼容V2密码,升级后存储格式为: md5:$HASH:$SALT 218 if len(passwordStore) == 3 { 219 if passwordStore[0] != "md5" { 220 return false, errors.New("Unknown password type") 221 } 222 hash := md5.New() 223 _, err := hash.Write([]byte(passwordStore[2] + password)) 224 bs := hex.EncodeToString(hash.Sum(nil)) 225 if err != nil { 226 return false, err 227 } 228 return bs == passwordStore[1], nil 229 } 230 231 //计算 Salt 和密码组合的SHA1摘要 232 hash := sha1.New() 233 _, err := hash.Write([]byte(password + passwordStore[0])) 234 bs := hex.EncodeToString(hash.Sum(nil)) 235 if err != nil { 236 return false, err 237 } 238 239 return bs == passwordStore[1], nil 240 } 241 242 // SetPassword 根据给定明文设定 User 的 Password 字段 243 func (user *User) SetPassword(password string) error { 244 //生成16位 Salt 245 salt := util.RandStringRunes(16) 246 247 //计算 Salt 和密码组合的SHA1摘要 248 hash := sha1.New() 249 _, err := hash.Write([]byte(password + salt)) 250 bs := hex.EncodeToString(hash.Sum(nil)) 251 252 if err != nil { 253 return err 254 } 255 256 //存储 Salt 值和摘要, ":"分割 257 user.Password = salt + ":" + string(bs) 258 return nil 259 } 260 261 // NewAnonymousUser 返回一个匿名用户 262 func NewAnonymousUser() *User { 263 user := User{} 264 user.Policy.Type = "anonymous" 265 user.Group, _ = GetGroupByID(3) 266 return &user 267 } 268 269 // IsAnonymous 返回是否为未登录用户 270 func (user *User) IsAnonymous() bool { 271 return user.ID == 0 272 } 273 274 // SetStatus 设定用户状态 275 func (user *User) SetStatus(status int) { 276 DB.Model(&user).Update("status", status) 277 } 278 279 // Update 更新用户 280 func (user *User) Update(val map[string]interface{}) error { 281 return DB.Model(user).Updates(val).Error 282 } 283 284 // UpdateOptions 更新用户偏好设定 285 func (user *User) UpdateOptions() error { 286 if err := user.SerializeOptions(); err != nil { 287 return err 288 } 289 return user.Update(map[string]interface{}{"options": user.Options}) 290 }