fix: prohibit concurrent read/write

This commit is contained in:
2023-12-26 18:21:27 +01:00
parent 16e5ad4f23
commit 39e3eb3862
+17
View File
@@ -6,6 +6,7 @@ import (
"io" "io"
"net/http" "net/http"
"reflect" "reflect"
"sync"
"github.com/sparetimecoders/goamqp" "github.com/sparetimecoders/goamqp"
) )
@@ -23,6 +24,7 @@ type CompanyPrivileges struct {
// PrivilegeHandler processes PrivilegeAdded-events and fetches the initial set of privileges from an authz-service // PrivilegeHandler processes PrivilegeAdded-events and fetches the initial set of privileges from an authz-service
type PrivilegeHandler struct { type PrivilegeHandler struct {
*sync.RWMutex
client *http.Client client *http.Client
baseURL string baseURL string
privileges map[string]map[string]*CompanyPrivileges privileges map[string]map[string]*CompanyPrivileges
@@ -41,6 +43,7 @@ func WithBaseURL(url string) OptsFunc {
// New creates a new PrivilegeHandler. Pass OptsFuncs to configure. // New creates a new PrivilegeHandler. Pass OptsFuncs to configure.
func New(opts ...OptsFunc) *PrivilegeHandler { func New(opts ...OptsFunc) *PrivilegeHandler {
handler := &PrivilegeHandler{ handler := &PrivilegeHandler{
RWMutex: &sync.RWMutex{},
client: &http.Client{}, client: &http.Client{},
baseURL: "http://authz-service", baseURL: "http://authz-service",
privileges: map[string]map[string]*CompanyPrivileges{}, privileges: map[string]map[string]*CompanyPrivileges{},
@@ -63,6 +66,8 @@ func (h *PrivilegeHandler) Fetch() error {
return err return err
} }
h.RLock()
defer h.RUnlock()
err = json.Unmarshal(buff, &h.privileges) err = json.Unmarshal(buff, &h.privileges)
if err != nil { if err != nil {
return err return err
@@ -77,6 +82,8 @@ func (h *PrivilegeHandler) Process(msg interface{}, _ goamqp.Headers) (interface
if priv, exists := h.privileges[ev.Email]; exists { if priv, exists := h.privileges[ev.Email]; exists {
priv[ev.CompanyID] = &CompanyPrivileges{} priv[ev.CompanyID] = &CompanyPrivileges{}
} else { } else {
h.Lock()
defer h.Unlock()
h.privileges[ev.Email] = map[string]*CompanyPrivileges{ h.privileges[ev.Email] = map[string]*CompanyPrivileges{
ev.CompanyID: {}, ev.CompanyID: {},
} }
@@ -84,13 +91,19 @@ func (h *PrivilegeHandler) Process(msg interface{}, _ goamqp.Headers) (interface
return nil, nil return nil, nil
case *UserRemoved: case *UserRemoved:
if priv, exists := h.privileges[ev.Email]; exists { if priv, exists := h.privileges[ev.Email]; exists {
h.Lock()
defer h.Unlock()
delete(priv, ev.CompanyID) delete(priv, ev.CompanyID)
} }
return nil, nil return nil, nil
case *PrivilegeAdded: case *PrivilegeAdded:
h.Lock()
defer h.Unlock()
h.setPrivileges(ev.Email, ev.CompanyID, ev.Privilege, true) h.setPrivileges(ev.Email, ev.CompanyID, ev.Privilege, true)
return nil, nil return nil, nil
case *PrivilegeRemoved: case *PrivilegeRemoved:
h.Lock()
defer h.Unlock()
h.setPrivileges(ev.Email, ev.CompanyID, ev.Privilege, false) h.setPrivileges(ev.Email, ev.CompanyID, ev.Privilege, false)
return nil, nil return nil, nil
default: default:
@@ -130,6 +143,8 @@ func (h *PrivilegeHandler) setPrivileges(email, companyId string, privilege Priv
// CompaniesByUser return a slice of company ids matching the provided email and predicate func // CompaniesByUser return a slice of company ids matching the provided email and predicate func
func (h *PrivilegeHandler) CompaniesByUser(email string, predicate func(privileges CompanyPrivileges) bool) []string { func (h *PrivilegeHandler) CompaniesByUser(email string, predicate func(privileges CompanyPrivileges) bool) []string {
h.RLock()
defer h.RUnlock()
var result []string var result []string
if p, exists := h.privileges[email]; exists { if p, exists := h.privileges[email]; exists {
for k, v := range p { for k, v := range p {
@@ -143,6 +158,8 @@ func (h *PrivilegeHandler) CompaniesByUser(email string, predicate func(privileg
// IsAllowed return true if the provided predicate return true for the privileges matching the provided email and companyID, return false otherwise // IsAllowed return true if the provided predicate return true for the privileges matching the provided email and companyID, return false otherwise
func (h *PrivilegeHandler) IsAllowed(email, companyID string, predicate func(privileges CompanyPrivileges) bool) bool { func (h *PrivilegeHandler) IsAllowed(email, companyID string, predicate func(privileges CompanyPrivileges) bool) bool {
h.RLock()
defer h.RUnlock()
if p, exists := h.privileges[email]; exists { if p, exists := h.privileges[email]; exists {
if v, exists := p[companyID]; exists { if v, exists := p[companyID]; exists {
return predicate(*v) return predicate(*v)