1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
12 "git.curoverse.com/arvados.git/sdk/go/arvados"
16 maxPermCacheAge = time.Hour
17 minPermCacheAge = 5 * time.Minute
20 type permChecker interface {
21 SetToken(token string)
22 Check(uuid string) (bool, error)
25 func newPermChecker(ac arvados.Client) permChecker {
27 return &cachingPermChecker{
29 cache: make(map[string]cacheEnt),
34 type cacheEnt struct {
39 type cachingPermChecker struct {
41 cache map[string]cacheEnt
49 func (pc *cachingPermChecker) SetToken(token string) {
50 if pc.Client.AuthToken == token {
53 pc.Client.AuthToken = token
54 pc.cache = make(map[string]cacheEnt)
57 func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
59 logger := logger(nil).
60 WithField("token", pc.Client.AuthToken).
61 WithField("uuid", uuid)
64 if perm, ok := pc.cache[uuid]; ok && now.Sub(perm.Time) < maxPermCacheAge {
65 logger.WithField("allowed", perm.allowed).Debug("cache hit")
66 return perm.allowed, nil
68 var buf map[string]interface{}
69 path, err := pc.PathForUUID("get", uuid)
76 err = pc.RequestAndDecode(&buf, "GET", path, nil, url.Values{
77 "include_trash": {"true"},
78 "select": {`["uuid"]`},
84 } else if txErr, ok := err.(*arvados.TransactionError); ok && pc.isNotAllowed(txErr.StatusCode) {
87 logger.WithError(err).Error("lookup error")
90 logger.WithField("allowed", allowed).Debug("cache miss")
91 pc.cache[uuid] = cacheEnt{Time: now, allowed: allowed}
95 func (pc *cachingPermChecker) isNotAllowed(status int) bool {
97 case http.StatusForbidden, http.StatusUnauthorized, http.StatusNotFound:
104 func (pc *cachingPermChecker) tidy() {
105 if len(pc.cache) <= pc.maxCurrent*2 {
108 tooOld := time.Now().Add(-minPermCacheAge)
109 for uuid, t := range pc.cache {
110 if t.Before(tooOld) {
111 delete(pc.cache, uuid)
114 pc.maxCurrent = len(pc.cache)