Skip to content
This repository has been archived by the owner on Jan 27, 2021. It is now read-only.

Commit

Permalink
Merge pull request #36 from owncloud/feature/accounts-uuid-middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
refs authored May 22, 2020
2 parents f2d1c0a + 85c4232 commit d7eab50
Show file tree
Hide file tree
Showing 18 changed files with 756 additions and 271 deletions.
4 changes: 2 additions & 2 deletions .drone.star
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ def testing(ctx):
},
{
'name': 'staticcheck',
'image': 'webhippie/golang:1.13',
'image': 'golangci/golangci-lint:latest',
'pull': 'always',
'commands': [
'make staticcheck',
'golangci-lint run',
],
'volumes': [
{
Expand Down
33 changes: 33 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
issues:
exclude-rules:
- path: pkg/middleware/account_uuid.go
text: "SA4006:"
linters:
- staticcheck
- path: pkg/proxy/proxy_integration_test.go
linters:
- bodyclose
linters:
enable:
- bodyclose
- deadcode
- gosimple
- govet
- staticcheck
- structcheck
- typecheck
- unused
- varcheck
- depguard
- golint
- unconvert
# - scopelint
- maligned
- misspell
- prealloc
#- gosec

disable:
- errcheck
- ineffassign
- scopelint
4 changes: 0 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,6 @@ fmt:
vet:
go vet $(PACKAGES)

.PHONY: staticcheck
staticcheck:
go run honnef.co/go/tools/cmd/staticcheck -tags '$(TAGS)' $(PACKAGES)

.PHONY: lint
lint:
for PKG in $(PACKAGES); do go run golang.org/x/lint/golint -set_exit_status $$PKG || exit 1; done;
Expand Down
6 changes: 6 additions & 0 deletions config/proxy-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
"HTTP": {
"Namespace": "com.owncloud"
},
"oidc": {
"endpoint": "https://localhost:9200",
"realm": "",
"signing_algs": ["RS256", "PS256"],
"insecure": true
},
"policy_selector": {
"static": {"policy" : "reva"}
},
Expand Down
25 changes: 13 additions & 12 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,24 @@ require (
contrib.go.opencensus.io/exporter/jaeger v0.2.0
contrib.go.opencensus.io/exporter/ocagent v0.6.0
contrib.go.opencensus.io/exporter/zipkin v0.1.1
github.com/coreos/go-oidc v2.1.0+incompatible
github.com/golang/protobuf v1.3.2
github.com/micro/cli/v2 v2.1.2-0.20200203150404-894195727d9c
github.com/micro/go-micro/v2 v2.0.1-0.20200212105717-d76baf59de2e
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/cs3org/go-cs3apis v0.0.0-20200306065539-29abc33f5be0
github.com/cs3org/reva v0.1.0
github.com/justinas/alice v1.2.0
github.com/micro/cli/v2 v2.1.2
github.com/micro/go-micro/v2 v2.6.0
github.com/oklog/run v1.1.0
github.com/openzipkin/zipkin-go v0.2.2
github.com/owncloud/flaex v0.2.0 // indirect
github.com/owncloud/ocis-accounts v0.1.0
github.com/owncloud/ocis-pkg/v2 v2.2.0
github.com/owncloud/flaex v0.2.0
github.com/owncloud/ocis-accounts v0.1.2-0.20200522102615-8c7da929195a
github.com/owncloud/ocis-pkg/v2 v2.2.1
github.com/prometheus/client_golang v1.2.1
github.com/prometheus/procfs v0.0.8 // indirect
github.com/restic/calens v0.2.0
github.com/spf13/viper v1.6.2
go.opencensus.io v0.22.2
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
github.com/spf13/viper v1.6.3
go.opencensus.io v0.22.3
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
gopkg.in/square/go-jose.v2 v2.4.0 // indirect
)

replace google.golang.org/grpc => google.golang.org/grpc v1.26.0
260 changes: 170 additions & 90 deletions go.sum

Large diffs are not rendered by default.

101 changes: 101 additions & 0 deletions pkg/cache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package cache

import (
"fmt"
"sync"
)

// Entry represents an entry on the cache. You can type assert on V.
type Entry struct {
V interface{}
Valid bool
}

// Cache is a barebones cache implementation.
type Cache struct {
entries map[string]map[string]Entry
size int
m sync.Mutex
}

// NewCache returns a new instance of Cache.
func NewCache(o ...Option) Cache {
opts := newOptions(o...)

return Cache{
size: opts.size,
entries: map[string]map[string]Entry{},
}
}

// Get gets an entry on a service `svcKey` by a give `key`.
func (c *Cache) Get(svcKey, key string) (*Entry, error) {
var value Entry
ok := true

c.m.Lock()
defer c.m.Unlock()

if value, ok = c.entries[svcKey][key]; !ok {
return nil, fmt.Errorf("invalid service key: `%v`", key)
}

return &value, nil
}

// Set sets a key / value. It lets a service add entries on a request basis.
func (c *Cache) Set(svcKey, key string, val interface{}) error {
c.m.Lock()
defer c.m.Unlock()

if !c.fits() {
return fmt.Errorf("cache is full")
}

if _, ok := c.entries[svcKey]; !ok {
c.entries[svcKey] = map[string]Entry{}
}

if _, ok := c.entries[svcKey][key]; ok {
return fmt.Errorf("key `%v` already exists", key)
}

c.entries[svcKey][key] = Entry{
V: val,
Valid: true,
}

return nil
}

// Invalidate invalidates a cache Entry by key.
func (c *Cache) Invalidate(svcKey, key string) error {
r, err := c.Get(svcKey, key)
if err != nil {
return err
}

r.Valid = false
c.entries[svcKey][key] = *r
return nil
}

// Evict frees memory from the cache by removing invalid keys. It is a noop.
func (c *Cache) Evict() {
for _, v := range c.entries {
for k, svcEntry := range v {
if !svcEntry.Valid {
delete(v, k)
}
}
}
}

// Length returns the amount of entries per service key.
func (c *Cache) Length(k string) int {
return len(c.entries[k])
}

func (c *Cache) fits() bool {
return c.size >= len(c.entries)
}
99 changes: 99 additions & 0 deletions pkg/cache/cache_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package cache

import (
"testing"
)

// Prevents from invalid import cycle.
type AccountsCacheEntry struct {
Email string
UUID string
}

func TestSet(t *testing.T) {
c := NewCache(
Size(256),
)

err := c.Set("accounts", "hello@foo.bar", AccountsCacheEntry{
Email: "hello@foo.bar",
UUID: "9c31b040-59e2-4a2b-926b-334d9e3fbd05",
})
if err != nil {
t.Error(err)
}

if c.Length("accounts") != 1 {
t.Errorf("expected length 1 got `%v`", len(c.entries))
}

item, err := c.Get("accounts", "hello@foo.bar")
if err != nil {
t.Error(err)
}

if cachedEntry, ok := item.V.(AccountsCacheEntry); !ok {
t.Errorf("invalid cached value type")
} else {
if cachedEntry.Email != "hello@foo.bar" {
t.Errorf("invalid value. Expected `hello@foo.bar` got: `%v`", cachedEntry.Email)
}
}
}

func TestEvict(t *testing.T) {
c := NewCache(
Size(256),
)

if err := c.Set("accounts", "hello@foo.bar", AccountsCacheEntry{
Email: "hello@foo.bar",
UUID: "9c31b040-59e2-4a2b-926b-334d9e3fbd05",
}); err != nil {
t.Error(err)
}

if err := c.Invalidate("accounts", "hello@foo.bar"); err != nil {
t.Error(err)
}

v, err := c.Get("accounts", "hello@foo.bar")
if err != nil {
t.Error(err)
}

if v.Valid {
t.Errorf("cache key unexpected valid state")
}

c.Evict()

if c.Length("accounts") != 0 {
t.Errorf("expected length 0 got `%v`", len(c.entries))
}
}

func TestGet(t *testing.T) {
svcCache := NewCache(
Size(256),
)

err := svcCache.Set("accounts", "node", "0.0.0.0:1234")
if err != nil {
t.Error(err)
}

raw, err := svcCache.Get("accounts", "node")
if err != nil {
t.Error(err)
}

v, ok := raw.V.(string)
if !ok {
t.Errorf("invalid type on service node key")
}

if v != "0.0.0.0:1234" {
t.Errorf("expected `0.0.0.0:1234` got `%v`", v)
}
}
36 changes: 36 additions & 0 deletions pkg/cache/option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cache

import "time"

// Options are all the possible options.
type Options struct {
size int
ttl time.Duration
}

// Option mutates option
type Option func(*Options)

// Size configures the size of the cache in items.
func Size(s int) Option {
return func(o *Options) {
o.size = s
}
}

// TTL rebuilds the cache after the configured duration.
func TTL(ttl time.Duration) Option {
return func(o *Options) {
o.ttl = ttl
}
}

func newOptions(opts ...Option) Options {
o := Options{}

for _, v := range opts {
v(&o)
}

return o
}
Loading

0 comments on commit d7eab50

Please sign in to comment.