auth
auth/profile.go
The great documentation and exported interface cleanup. Modify all our *Store interfaces to be unexported, as there's no real good reason they need to be exported, especially as they can be implemented without being exported. The interfaces shouldn't matter to 99% of users of the package, so let's not pollute our package API. Further, all methods of the interfaces are now unexported, for pretty much the same reasoning. Add a doc.go file with documentation explaining the choices the package is making and what it provides. Implement documentation on all our exported types and methods and functions, which makes golint happy. The only remaining golint warning is about NewMemstore, which will stay the way it is. The memstore type is useful outside tests for things like standing up a server quickly when we don't care about the storage, and because the type is unexported, we _need_ a New function to create an instance that can be passed to the Context.
1.1 --- a/profile.go Wed Oct 22 00:30:28 2014 -0400 1.2 +++ b/profile.go Sun Oct 26 00:53:36 2014 -0400 1.3 @@ -8,24 +8,46 @@ 1.4 ) 1.5 1.6 const ( 1.7 + // MinPassphraseLength is the minimum length, in bytes, of a passphrase, exclusive. 1.8 MinPassphraseLength = 6 1.9 + // MaxPassphraseLength is the maximum length, in bytes, of a passphrase, exclusive. 1.10 MaxPassphraseLength = 64 1.11 ) 1.12 1.13 var ( 1.14 - ErrNoProfileStore = errors.New("no ProfileStore was specified for the Context") 1.15 - ErrProfileAlreadyExists = errors.New("profile already exists in ProfileStore") 1.16 - ErrProfileNotFound = errors.New("profile not found in ProfileStore") 1.17 - ErrLoginAlreadyExists = errors.New("login already exists in ProfileStore") 1.18 - ErrLoginNotFound = errors.New("login not found in ProfileStore") 1.19 + // ErrNoProfileStore is returned when a Context tries to act on a profileStore without setting one first. 1.20 + ErrNoProfileStore = errors.New("no profileStore was specified for the Context") 1.21 + // ErrProfileAlreadyExists is returned when a Profile is added to a profileStore, but another Profile with 1.22 + // the same ID already exists in the profileStore. 1.23 + ErrProfileAlreadyExists = errors.New("profile already exists in profileStore") 1.24 + // ErrProfileNotFound is returned when a Profile is requested but not found in the profileStore. 1.25 + ErrProfileNotFound = errors.New("profile not found in profileStore") 1.26 + // ErrLoginAlreadyExists is returned when a Login is added to a profileStore, but another Login with the same 1.27 + // Type and Value already exists in the profileStore. 1.28 + ErrLoginAlreadyExists = errors.New("login already exists in profileStore") 1.29 + // ErrLoginNotFound is returned when a Login is requested but not found in the profileStore. 1.30 + ErrLoginNotFound = errors.New("login not found in profileStore") 1.31 1.32 - ErrMissingPassphrase = errors.New("missing passphrase") 1.33 - ErrMissingPassphraseReset = errors.New("missing passphrase reset") 1.34 + // ErrMissingPassphrase is returned when a ProfileChange is validated but does not contain a 1.35 + // Passphrase, and requires one. 1.36 + ErrMissingPassphrase = errors.New("missing passphrase") 1.37 + // ErrMissingPassphraseReset is returned when a ProfileChange is validated but does not contain 1.38 + // a PassphraseReset, and requires one. 1.39 + ErrMissingPassphraseReset = errors.New("missing passphrase reset") 1.40 + // ErrMissingPassphraseResetCreated is returned when a ProfileChange is validated but does not 1.41 + // contain a PassphraseResetCreated, and requires one. 1.42 ErrMissingPassphraseResetCreated = errors.New("missing passphrase reset created timestamp") 1.43 - ErrPassphraseTooShort = errors.New("passphrase too short") 1.44 - ErrPassphraseTooLong = errors.New("passphrase too long") 1.45 + // ErrPassphraseTooShort is returned when a ProfileChange is validated and contains a Passphrase, 1.46 + // but the Passphrase is shorter than MinPassphraseLength. 1.47 + ErrPassphraseTooShort = errors.New("passphrase too short") 1.48 + // ErrPassphraseTooLong is returned when a ProfileChange is validated and contains a Passphrase, 1.49 + // but the Passphrase is longer than MaxPassphraseLength. 1.50 + ErrPassphraseTooLong = errors.New("passphrase too long") 1.51 ) 1.52 1.53 +// Profile represents a single user of the service, 1.54 +// including their authentication information, but not 1.55 +// including their username or email. 1.56 type Profile struct { 1.57 ID uuid.ID 1.58 Name string 1.59 @@ -41,6 +63,8 @@ 1.60 LastSeen time.Time 1.61 } 1.62 1.63 +// ApplyChange applies the properties of the passed ProfileChange 1.64 +// to the Profile it is called on. 1.65 func (p *Profile) ApplyChange(change ProfileChange) { 1.66 if change.Name != nil { 1.67 p.Name = *change.Name 1.68 @@ -74,12 +98,15 @@ 1.69 } 1.70 } 1.71 1.72 +// ApplyBulkChange applies the properties of the passed BulkProfileChange 1.73 +// to the Profile it is called on. 1.74 func (p *Profile) ApplyBulkChange(change BulkProfileChange) { 1.75 if change.Compromised != nil { 1.76 p.Compromised = *change.Compromised 1.77 } 1.78 } 1.79 1.80 +// ProfileChange represents a single atomic change to a Profile's mutable data. 1.81 type ProfileChange struct { 1.82 Name *string 1.83 Passphrase *string 1.84 @@ -93,6 +120,10 @@ 1.85 LastSeen *time.Time 1.86 } 1.87 1.88 +// Validate checks the ProfileChange it is called on 1.89 +// and asserts its internal validity, or lack thereof. 1.90 +// A descriptive error will be returned in the case of 1.91 +// an invalid change. 1.92 func (c ProfileChange) Validate() error { 1.93 if c.Name == nil && c.Passphrase == nil && c.Iterations == nil && c.Salt == nil && c.PassphraseScheme == nil && c.Compromised == nil && c.LockedUntil == nil && c.PassphraseReset == nil && c.PassphraseResetCreated == nil && c.LastSeen == nil { 1.94 return ErrEmptyChange 1.95 @@ -121,10 +152,17 @@ 1.96 return nil 1.97 } 1.98 1.99 +// BulkProfileChange represents a single atomic change to many Profiles' mutable data. 1.100 +// It is a subset of a ProfileChange, as it doesn't make sense to mutate some of the 1.101 +// ProfileChange values across many Profiles all at once. 1.102 type BulkProfileChange struct { 1.103 Compromised *bool 1.104 } 1.105 1.106 +// Validate checks the BulkProfileChange it is called on 1.107 +// and asserts its internal validity, or lack thereof. 1.108 +// A descriptive error will be returned in the case of an 1.109 +// invalid change. 1.110 func (b BulkProfileChange) Validate() error { 1.111 if b.Compromised == nil { 1.112 return ErrEmptyChange 1.113 @@ -132,6 +170,9 @@ 1.114 return nil 1.115 } 1.116 1.117 +// Login represents a single human-friendly identifier for 1.118 +// a given Profile that can be used to log into that Profile. 1.119 +// Each Profile may only have one Login for each Type. 1.120 type Login struct { 1.121 Type string 1.122 Value string 1.123 @@ -140,21 +181,21 @@ 1.124 LastUsed time.Time 1.125 } 1.126 1.127 -type ProfileStore interface { 1.128 - GetProfileByID(id uuid.ID) (Profile, error) 1.129 - GetProfileByLogin(loginType, value string) (Profile, error) 1.130 - SaveProfile(profile Profile) error 1.131 - UpdateProfile(id uuid.ID, change ProfileChange) error 1.132 - UpdateProfiles(ids []uuid.ID, change BulkProfileChange) error 1.133 - DeleteProfile(id uuid.ID) error 1.134 +type profileStore interface { 1.135 + getProfileByID(id uuid.ID) (Profile, error) 1.136 + getProfileByLogin(loginType, value string) (Profile, error) 1.137 + saveProfile(profile Profile) error 1.138 + updateProfile(id uuid.ID, change ProfileChange) error 1.139 + updateProfiles(ids []uuid.ID, change BulkProfileChange) error 1.140 + deleteProfile(id uuid.ID) error 1.141 1.142 - AddLogin(login Login) error 1.143 - RemoveLogin(loginType, value string, profile uuid.ID) error 1.144 - RecordLoginUse(loginType, value string, when time.Time) error 1.145 - ListLogins(profile uuid.ID, num, offset int) ([]Login, error) 1.146 + addLogin(login Login) error 1.147 + removeLogin(loginType, value string, profile uuid.ID) error 1.148 + recordLoginUse(loginType, value string, when time.Time) error 1.149 + listLogins(profile uuid.ID, num, offset int) ([]Login, error) 1.150 } 1.151 1.152 -func (m *Memstore) GetProfileByID(id uuid.ID) (Profile, error) { 1.153 +func (m *memstore) getProfileByID(id uuid.ID) (Profile, error) { 1.154 m.profileLock.RLock() 1.155 defer m.profileLock.RUnlock() 1.156 p, ok := m.profiles[id.String()] 1.157 @@ -164,7 +205,7 @@ 1.158 return p, nil 1.159 } 1.160 1.161 -func (m *Memstore) GetProfileByLogin(loginType, value string) (Profile, error) { 1.162 +func (m *memstore) getProfileByLogin(loginType, value string) (Profile, error) { 1.163 m.loginLock.RLock() 1.164 defer m.loginLock.RUnlock() 1.165 login, ok := m.logins[loginType+":"+value] 1.166 @@ -180,7 +221,7 @@ 1.167 return profile, nil 1.168 } 1.169 1.170 -func (m *Memstore) SaveProfile(profile Profile) error { 1.171 +func (m *memstore) saveProfile(profile Profile) error { 1.172 m.profileLock.Lock() 1.173 defer m.profileLock.Unlock() 1.174 _, ok := m.profiles[profile.ID.String()] 1.175 @@ -191,7 +232,7 @@ 1.176 return nil 1.177 } 1.178 1.179 -func (m *Memstore) UpdateProfile(id uuid.ID, change ProfileChange) error { 1.180 +func (m *memstore) updateProfile(id uuid.ID, change ProfileChange) error { 1.181 m.profileLock.Lock() 1.182 defer m.profileLock.Unlock() 1.183 p, ok := m.profiles[id.String()] 1.184 @@ -203,7 +244,7 @@ 1.185 return nil 1.186 } 1.187 1.188 -func (m *Memstore) UpdateProfiles(ids []uuid.ID, change BulkProfileChange) error { 1.189 +func (m *memstore) updateProfiles(ids []uuid.ID, change BulkProfileChange) error { 1.190 m.profileLock.Lock() 1.191 defer m.profileLock.Unlock() 1.192 for id, profile := range m.profiles { 1.193 @@ -218,7 +259,7 @@ 1.194 return nil 1.195 } 1.196 1.197 -func (m *Memstore) DeleteProfile(id uuid.ID) error { 1.198 +func (m *memstore) deleteProfile(id uuid.ID) error { 1.199 m.profileLock.Lock() 1.200 defer m.profileLock.Unlock() 1.201 _, ok := m.profiles[id.String()] 1.202 @@ -229,7 +270,7 @@ 1.203 return nil 1.204 } 1.205 1.206 -func (m *Memstore) AddLogin(login Login) error { 1.207 +func (m *memstore) addLogin(login Login) error { 1.208 m.loginLock.Lock() 1.209 defer m.loginLock.Unlock() 1.210 _, ok := m.logins[login.Type+":"+login.Value] 1.211 @@ -241,7 +282,7 @@ 1.212 return nil 1.213 } 1.214 1.215 -func (m *Memstore) RemoveLogin(loginType, value string, profile uuid.ID) error { 1.216 +func (m *memstore) removeLogin(loginType, value string, profile uuid.ID) error { 1.217 m.loginLock.Lock() 1.218 defer m.loginLock.Unlock() 1.219 l, ok := m.logins[loginType+":"+value] 1.220 @@ -265,7 +306,7 @@ 1.221 return nil 1.222 } 1.223 1.224 -func (m *Memstore) RecordLoginUse(loginType, value string, when time.Time) error { 1.225 +func (m *memstore) recordLoginUse(loginType, value string, when time.Time) error { 1.226 m.loginLock.Lock() 1.227 defer m.loginLock.Unlock() 1.228 l, ok := m.logins[loginType+":"+value] 1.229 @@ -277,7 +318,7 @@ 1.230 return nil 1.231 } 1.232 1.233 -func (m *Memstore) ListLogins(profile uuid.ID, num, offset int) ([]Login, error) { 1.234 +func (m *memstore) listLogins(profile uuid.ID, num, offset int) ([]Login, error) { 1.235 m.loginLock.RLock() 1.236 defer m.loginLock.RUnlock() 1.237 ids, ok := m.profileLoginLookup[profile.String()]