0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2025-01-13 22:50:38 -05:00

fix: Add mutex for managing file access

Signed-off-by: onidoru <25552941+onidoru@users.noreply.github.com>
This commit is contained in:
onidoru 2024-02-07 17:15:31 +02:00 committed by Nikita K
parent d9e64b9a34
commit bf5bbee9d0

View file

@ -20,7 +20,12 @@ const (
type HtpasswdClient struct { type HtpasswdClient struct {
credMap credMap credMap credMap
filepath string credFile credFile
}
type credFile struct {
path string
rw *sync.RWMutex
} }
type credMap struct { type credMap struct {
@ -30,7 +35,10 @@ type credMap struct {
func NewHtpasswdClient(filepath string) *HtpasswdClient { func NewHtpasswdClient(filepath string) *HtpasswdClient {
return &HtpasswdClient{ return &HtpasswdClient{
filepath: filepath, credFile: credFile{
path: filepath,
rw: &sync.RWMutex{},
},
credMap: credMap{ credMap: credMap{
m: make(map[string]string), m: make(map[string]string),
rw: &sync.RWMutex{}, rw: &sync.RWMutex{},
@ -39,12 +47,12 @@ func NewHtpasswdClient(filepath string) *HtpasswdClient {
} }
// Init initializes the HtpasswdClient. // Init initializes the HtpasswdClient.
// It performs the file read using the filename specified in NewHtpasswdClient // It performs the credFile read using the filename specified in NewHtpasswdClient
// and caches all user passwords. // and caches all user passwords.
func (hc *HtpasswdClient) Init() error { func (hc *HtpasswdClient) Init() error {
credsFile, err := os.Open(hc.filepath) credsFile, err := os.Open(hc.credFile.path)
if err != nil { if err != nil {
return fmt.Errorf("error occurred while opening creds-file: %w", err) return fmt.Errorf("error occurred while opening creds-credFile: %w", err)
} }
defer credsFile.Close() defer credsFile.Close()
@ -63,7 +71,7 @@ func (hc *HtpasswdClient) Init() error {
} }
if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
return fmt.Errorf("error occurred while reading creds-file: %w", err) return fmt.Errorf("error occurred while reading creds-credFile: %w", err)
} }
return nil return nil
@ -121,7 +129,7 @@ func (hc *HtpasswdClient) ChangePassword(login, supposedOldPassword, newPassword
return zerr.ErrOldPasswordIsWrong return zerr.ErrOldPasswordIsWrong
} }
// if passwords match, no need to update file and map, return nil as if operation is successful // if passwords match, no need to update credFile and map, return nil as if operation is successful
if err := bcrypt.CompareHashAndPassword([]byte(oldPassphrase), []byte(newPassword)); err == nil { if err := bcrypt.CompareHashAndPassword([]byte(oldPassphrase), []byte(newPassword)); err == nil {
return nil return nil
} }
@ -132,9 +140,9 @@ func (hc *HtpasswdClient) ChangePassword(login, supposedOldPassword, newPassword
return fmt.Errorf("error occurred while encrypting new password: %w", err) return fmt.Errorf("error occurred while encrypting new password: %w", err)
} }
file, err := os.ReadFile(hc.filepath) file, err := os.ReadFile(hc.credFile.path)
if err != nil { if err != nil {
return fmt.Errorf("error occurred while reading creds-file: %w", err) return fmt.Errorf("error occurred while reading creds-credFile: %w", err)
} }
// read passwords line by line to find the corresponding login // read passwords line by line to find the corresponding login
@ -149,41 +157,39 @@ func (hc *HtpasswdClient) ChangePassword(login, supposedOldPassword, newPassword
} }
} }
// write new content to temporary file // write new content to temporary credFile
// and replace the old file with temporary, so the operation is atomic // and replace the old credFile with temporary, so the operation is atomic
output := []byte(strings.Join(lines, "\n")) output := []byte(strings.Join(lines, "\n"))
tmpfile, err := os.CreateTemp(filepath.Dir(hc.filepath), "htpasswd-*.tmp") tmpfile, err := os.CreateTemp(filepath.Dir(hc.credFile.path), "htpasswd-*.tmp")
if err != nil { if err != nil {
return fmt.Errorf("error occurred when creating temp htpasswd file: %w", err) return fmt.Errorf("error occurred when creating temp htpasswd credFile: %w", err)
} }
if _, err := tmpfile.Write(output); err != nil { if _, err := tmpfile.Write(output); err != nil {
tmpfile.Close() tmpfile.Close()
os.Remove(tmpfile.Name()) os.Remove(tmpfile.Name())
return fmt.Errorf("error occurred when writing to temp htpasswd file: %w", err)
return fmt.Errorf("error occurred when writing to temp htpasswd credFile: %w", err)
} }
if err := tmpfile.Close(); err != nil { if err := tmpfile.Close(); err != nil {
os.Remove(tmpfile.Name()) os.Remove(tmpfile.Name())
return fmt.Errorf("error occurred when closing temp htpasswd file: %w", err)
return fmt.Errorf("error occurred when closing temp htpasswd credFile: %w", err)
} }
if err := os.Rename(tmpfile.Name(), hc.filepath); err != nil { if err := os.Rename(tmpfile.Name(), hc.credFile.path); err != nil {
return fmt.Errorf("error occurred while replacing htpasswd file with new file: %w", err) return fmt.Errorf("error occurred while replacing htpasswd credFile with new credFile: %w", err)
} }
err = os.WriteFile(hc.filepath, output, constants.DefaultDirPerms) err = os.WriteFile(hc.credFile.path, output, constants.DefaultDirPerms)
if err != nil { if err != nil {
return fmt.Errorf("error occurred while writing to creds-file: %w", err) return fmt.Errorf("error occurred while writing to creds-credFile: %w", err)
} }
// set to credMap only if all file operations are successful to prevent collisions // set to credMap only if all credFile operations are successful to prevent collisions
hc.credMap.rw.Lock() return hc.credMap.Set(login, string(newPassphrase))
hc.credMap.m[login] = string(newPassphrase)
hc.credMap.rw.Unlock()
return nil
} }
func (c credMap) Set(login, passphrase string) error { func (c credMap) Set(login, passphrase string) error {