service/permissions/registry.go (171 lines of code) (raw):

package permissions import ( "ddm-admin-console/router" "ddm-admin-console/service/codebase" "ddm-admin-console/service/k8s" "errors" "fmt" "sync" "time" "github.com/gin-gonic/gin" ) type RegistryPermission struct { CanGet bool CanUpdate bool CanDelete bool Expiry time.Time } type Registry struct { //token - []permission perms map[string]map[string]RegistryPermission permsLock sync.RWMutex codebaseService codebase.ServiceInterface k8sService k8s.ServiceInterface } func Make(cbService codebase.ServiceInterface, k8sService k8s.ServiceInterface) *Registry { r := Registry{ perms: make(map[string]map[string]RegistryPermission), k8sService: k8sService, codebaseService: cbService, } //go r.expiryTicker() return &r } func (r *Registry) expiryTicker() { tk := time.NewTicker(time.Second) for range tk.C { r.CheckExpiry() } } func (r *Registry) CheckExpiry() { r.permsLock.RLock() var tokensToRemove []string for tok, regPerms := range r.perms { for _, perms := range regPerms { if time.Now().Unix() > perms.Expiry.Unix() { tokensToRemove = append(tokensToRemove, tok) } break } } r.permsLock.RUnlock() r.permsLock.Lock() for _, t := range tokensToRemove { delete(r.perms, t) } r.permsLock.Unlock() } func (r *Registry) SetPermission(token string, registryName string, permission RegistryPermission) { if time.Now().Unix() > permission.Expiry.Unix() { return } r.permsLock.Lock() tokenPerms, ok := r.perms[token] if !ok { tokenPerms = make(map[string]RegistryPermission) } tokenPerms[registryName] = permission r.perms[token] = tokenPerms r.permsLock.Unlock() } func (r *Registry) GetPermission(token, registryName string) (*RegistryPermission, error) { r.permsLock.RLock() regs, ok := r.perms[token] if !ok { r.permsLock.RUnlock() return nil, errors.New("no permission") } perm, ok := regs[registryName] if !ok { r.permsLock.RUnlock() return nil, errors.New("no permission") } if time.Now().Unix() > perm.Expiry.Unix() { r.permsLock.RUnlock() r.DeleteToken(token) return nil, errors.New("no permission") } r.permsLock.RUnlock() return &perm, nil } func (r *Registry) DeleteTokenContext(ctx *gin.Context) error { tok, err := router.ExtractToken(ctx) if err != nil { return fmt.Errorf("no token: %w", err) } r.DeleteToken(tok.AccessToken) return nil } func (r *Registry) DeleteToken(tok string) { r.permsLock.Lock() defer r.permsLock.Unlock() delete(r.perms, tok) } func (r *Registry) DeleteRegistry(name string) { r.permsLock.Lock() defer r.permsLock.Unlock() for token, regPerms := range r.perms { _, ok := regPerms[name] if ok { delete(r.perms[token], name) return } } } func (r *Registry) FilterCodebases(ginContext *gin.Context, cbs []codebase.Codebase, k8sService k8s.ServiceInterface) ([]codebase.WithPermissions, error) { tok, err := router.ExtractToken(ginContext) if err != nil { return nil, fmt.Errorf("no token: %w", err) } withPerms := make([]codebase.WithPermissions, 0, len(cbs)) for i, cb := range cbs { perm, err := r.GetPermission(tok.AccessToken, cb.Name) if err == nil { if !perm.CanGet { continue } } else { canGet, canUpdate, canDelete, err := codebase.CheckCodebasePermission(cb.Name, k8sService) if err != nil { return nil, fmt.Errorf("unable to check perms: %w", err) } perm = &RegistryPermission{CanUpdate: canUpdate, CanDelete: canDelete, CanGet: canGet, Expiry: tok.Expiry} r.SetPermission(tok.AccessToken, cb.Name, *perm) if !canGet { continue } } withPerms = append(withPerms, codebase.WithPermissions{ Codebase: &cbs[i], CanUpdate: perm.CanUpdate, CanDelete: perm.CanDelete, }) } return withPerms, nil } func (r *Registry) LoadUserRegistries(ctx *gin.Context) error { cbs, err := r.codebaseService.GetAllByType(codebase.RegistryCodebaseType) if err != nil { return fmt.Errorf("unable to load codebases: %w", err) } userCtx := router.ContextWithUserAccessToken(ctx) k8sService, err := r.k8sService.ServiceForContext(userCtx) if err != nil { return fmt.Errorf("unable to get k8s service for context: %w", err) } tokenData, err := router.ExtractToken(ctx) if err != nil { return fmt.Errorf("unable to extract token from context, err: %w", err) } for _, cb := range cbs { canGet, canUpdate, canDelete, err := codebase.CheckCodebasePermission(cb.Name, k8sService) if err != nil { return fmt.Errorf("unable to check codebase permissions: %w", err) } r.SetPermission(tokenData.AccessToken, cb.Name, RegistryPermission{ CanUpdate: canUpdate, CanGet: canGet, CanDelete: canDelete, Expiry: tokenData.Expiry, }) } return nil }