github.com/cs3org/reva/v2@v2.27.7/pkg/siteacc/data/account.go (about) 1 // Copyright 2018-2020 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this filePath except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package data 20 21 import ( 22 "strings" 23 "time" 24 25 "github.com/cs3org/reva/v2/pkg/siteacc/credentials" 26 "github.com/pkg/errors" 27 28 "github.com/cs3org/reva/v2/pkg/utils" 29 ) 30 31 // Account represents a single site account. 32 type Account struct { 33 Email string `json:"email"` 34 Title string `json:"title"` 35 FirstName string `json:"firstName"` 36 LastName string `json:"lastName"` 37 Site string `json:"site"` 38 Role string `json:"role"` 39 PhoneNumber string `json:"phoneNumber"` 40 41 Password credentials.Password `json:"password"` 42 43 DateCreated time.Time `json:"dateCreated"` 44 DateModified time.Time `json:"dateModified"` 45 46 Data AccountData `json:"data"` 47 Settings AccountSettings `json:"settings"` 48 } 49 50 // AccountData holds additional data for a site account. 51 type AccountData struct { 52 GOCDBAccess bool `json:"gocdbAccess"` 53 SiteAccess bool `json:"siteAccess"` 54 } 55 56 // AccountSettings holds additional settings for a site account. 57 type AccountSettings struct { 58 ReceiveAlerts bool `json:"receiveAlerts"` 59 } 60 61 // Accounts holds an array of site accounts. 62 type Accounts = []*Account 63 64 // Update copies the data of the given account to this account. 65 func (acc *Account) Update(other *Account, setPassword bool, copyData bool) error { 66 if err := other.verify(false, false); err != nil { 67 return errors.Wrap(err, "unable to update account data") 68 } 69 70 // Manually update fields 71 acc.Title = other.Title 72 acc.FirstName = other.FirstName 73 acc.LastName = other.LastName 74 acc.Role = other.Role 75 acc.PhoneNumber = other.PhoneNumber 76 77 if setPassword && other.Password.Value != "" { 78 // If a password was provided, use that as the new one 79 if err := acc.UpdatePassword(other.Password.Value); err != nil { 80 return errors.Wrap(err, "unable to update account data") 81 } 82 } 83 84 if copyData { 85 acc.Data = other.Data 86 } 87 88 return nil 89 } 90 91 // Configure copies the settings of the given account to this account. 92 func (acc *Account) Configure(other *Account) error { 93 // Simply copy the stored settings 94 acc.Settings = other.Settings 95 96 return nil 97 } 98 99 // UpdatePassword assigns a new password to the account, hashing it first. 100 func (acc *Account) UpdatePassword(pwd string) error { 101 if err := acc.Password.Set(pwd); err != nil { 102 return errors.Wrap(err, "unable to update the user password") 103 } 104 return nil 105 } 106 107 // Clone creates a copy of the account; if erasePassword is set to true, the password will be cleared in the cloned object. 108 func (acc *Account) Clone(erasePassword bool) *Account { 109 clone := *acc 110 111 if erasePassword { 112 clone.Password.Clear() 113 } 114 115 return &clone 116 } 117 118 // CheckScopeAccess checks whether the user can access the specified scope. 119 func (acc *Account) CheckScopeAccess(scope string) bool { 120 hasAccess := false 121 122 switch strings.ToLower(scope) { 123 case ScopeDefault: 124 hasAccess = true 125 126 case ScopeGOCDB: 127 hasAccess = acc.Data.GOCDBAccess 128 129 case ScopeSite: 130 hasAccess = acc.Data.SiteAccess 131 } 132 133 return hasAccess 134 } 135 136 // Cleanup trims all string entries. 137 func (acc *Account) Cleanup() { 138 acc.Email = strings.TrimSpace(acc.Email) 139 acc.Title = strings.TrimSpace(acc.Title) 140 acc.FirstName = strings.TrimSpace(acc.FirstName) 141 acc.LastName = strings.TrimSpace(acc.LastName) 142 acc.Site = strings.TrimSpace(acc.Site) 143 acc.Role = strings.TrimSpace(acc.Role) 144 acc.PhoneNumber = strings.TrimSpace(acc.PhoneNumber) 145 } 146 147 func (acc *Account) verify(isNewAccount, verifyPassword bool) error { 148 if acc.Email == "" { 149 return errors.Errorf("no email address provided") 150 } else if !utils.IsEmailValid(acc.Email) { 151 return errors.Errorf("invalid email address: %v", acc.Email) 152 } 153 154 if acc.FirstName == "" { 155 return errors.Errorf("no first name provided") 156 } else if !utils.IsValidName(acc.FirstName) { 157 return errors.Errorf("first name contains invalid characters: %v", acc.FirstName) 158 } 159 160 if acc.LastName == "" { 161 return errors.Errorf("no last name provided") 162 } else if !utils.IsValidName(acc.LastName) { 163 return errors.Errorf("last name contains invalid characters: %v", acc.LastName) 164 } 165 166 if isNewAccount && acc.Site == "" { 167 return errors.Errorf("no site provided") 168 } 169 170 if acc.Role == "" { 171 return errors.Errorf("no role provided") 172 } else if !utils.IsValidName(acc.Role) { 173 return errors.Errorf("role contains invalid characters: %v", acc.Role) 174 } 175 176 if acc.PhoneNumber != "" && !utils.IsValidPhoneNumber(acc.PhoneNumber) { 177 return errors.Errorf("invalid phone number provided") 178 } 179 180 if verifyPassword { 181 if !acc.Password.IsValid() { 182 return errors.Errorf("no valid password set") 183 } 184 } 185 186 return nil 187 } 188 189 // NewAccount creates a new site account. 190 func NewAccount(email string, title, firstName, lastName string, site, role string, phoneNumber string, password string) (*Account, error) { 191 t := time.Now() 192 193 acc := &Account{ 194 Email: email, 195 Title: title, 196 FirstName: firstName, 197 LastName: lastName, 198 Site: site, 199 Role: role, 200 PhoneNumber: phoneNumber, 201 DateCreated: t, 202 DateModified: t, 203 Data: AccountData{ 204 GOCDBAccess: false, 205 SiteAccess: false, 206 }, 207 Settings: AccountSettings{ 208 ReceiveAlerts: true, 209 }, 210 } 211 212 // Set the user password, which also makes sure that the given password is strong enough 213 if err := acc.UpdatePassword(password); err != nil { 214 return nil, err 215 } 216 217 if err := acc.verify(true, true); err != nil { 218 return nil, err 219 } 220 221 return acc, nil 222 }