(account Account, plaintextPassword []byte)
| 163 | } |
| 164 | |
| 165 | func (hba HTTPBasicAuth) correctPassword(account Account, plaintextPassword []byte) (bool, error) { |
| 166 | compare := func() (bool, error) { |
| 167 | return hba.Hash.Compare(account.password, plaintextPassword) |
| 168 | } |
| 169 | |
| 170 | // if no caching is enabled, simply return the result of hashing + comparing |
| 171 | if hba.HashCache == nil { |
| 172 | return compare() |
| 173 | } |
| 174 | |
| 175 | // compute a cache key that is unique for these input parameters |
| 176 | cacheKey := hex.EncodeToString(append(account.password, plaintextPassword...)) |
| 177 | |
| 178 | // fast track: if the result of the input is already cached, use it |
| 179 | hba.HashCache.mu.RLock() |
| 180 | same, ok := hba.HashCache.cache[cacheKey] |
| 181 | hba.HashCache.mu.RUnlock() |
| 182 | if ok { |
| 183 | return same, nil |
| 184 | } |
| 185 | // slow track: do the expensive op, then add it to the cache |
| 186 | // but perform it in a singleflight group so that multiple |
| 187 | // parallel requests using the same password don't cause a |
| 188 | // thundering herd problem by all performing the same hashing |
| 189 | // operation before the first one finishes and caches it. |
| 190 | v, err, _ := hba.HashCache.g.Do(cacheKey, func() (any, error) { |
| 191 | return compare() |
| 192 | }) |
| 193 | if err != nil { |
| 194 | return false, err |
| 195 | } |
| 196 | same = v.(bool) |
| 197 | hba.HashCache.mu.Lock() |
| 198 | if len(hba.HashCache.cache) >= 1000 { |
| 199 | hba.HashCache.makeRoom() // keep cache size under control |
| 200 | } |
| 201 | hba.HashCache.cache[cacheKey] = same |
| 202 | hba.HashCache.mu.Unlock() |
| 203 | |
| 204 | return same, nil |
| 205 | } |
| 206 | |
| 207 | func (hba HTTPBasicAuth) promptForCredentials(w http.ResponseWriter, err error) (User, bool, error) { |
| 208 | // browsers show a message that says something like: |
no test coverage detected