Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #238 from aenario/permissions-persistence
Permissions persistence
- Loading branch information
Showing
16 changed files
with
285 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,93 @@ | ||
package permissions | ||
|
||
// Validable is an interface for a object than can be validated by a Set | ||
type Validable interface { | ||
ID() string | ||
DocType() string | ||
Valid(field, expected string) bool | ||
import ( | ||
"fmt" | ||
|
||
"github.com/cozy/cozy-stack/pkg/consts" | ||
"github.com/cozy/cozy-stack/pkg/couchdb" | ||
"github.com/cozy/cozy-stack/pkg/couchdb/mango" | ||
"github.com/cozy/cozy-stack/web/jsonapi" | ||
) | ||
|
||
// Permission is a storable object containing a set of rules and | ||
// several codes | ||
type Permission struct { | ||
PID string `json:"_id,omitempty"` | ||
PRev string `json:"_rev,omitempty"` | ||
ApplicationID string `json:"application_id"` | ||
Permissions Set `json:"permissions,omitempty"` | ||
ExpiresAt int `json:"expires_at,omitempty"` | ||
Codes map[string]string `json:"codes,omitempty"` | ||
} | ||
|
||
func validValues(r Rule, o Validable) bool { | ||
// empty r.Values = any value | ||
if len(r.Values) == 0 { | ||
return true | ||
} | ||
// Index is the necessary index for this package | ||
// used in instance creation | ||
var Index = mango.IndexOnFields("application_id") | ||
|
||
if r.Selector == "" { | ||
return r.ValuesContain(o.ID()) | ||
} | ||
// ID implements jsonapi.Doc | ||
func (p *Permission) ID() string { return p.PID } | ||
|
||
return r.SomeValue(func(value string) bool { | ||
return o.Valid(r.Selector, value) | ||
}) | ||
} | ||
// Rev implements jsonapi.Doc | ||
func (p *Permission) Rev() string { return p.PRev } | ||
|
||
func validVerbAndType(r Rule, v Verb, doctype string) bool { | ||
return r.Verbs.Contains(v) && r.Type == doctype | ||
} | ||
// DocType implements jsonapi.Doc | ||
func (p *Permission) DocType() string { return consts.Permissions } | ||
|
||
func validWholeType(r Rule) bool { | ||
return len(r.Values) == 0 | ||
} | ||
// SetID implements jsonapi.Doc | ||
func (p *Permission) SetID(id string) { p.PID = id } | ||
|
||
func validID(r Rule, id string) bool { | ||
return r.Selector == "" && r.ValuesContain(id) | ||
} | ||
// SetRev implements jsonapi.Doc | ||
func (p *Permission) SetRev(rev string) { p.PRev = rev } | ||
|
||
// Relationships implements jsonapi.Doc | ||
func (p *Permission) Relationships() jsonapi.RelationshipMap { return nil } | ||
|
||
// Included implements jsonapi.Doc | ||
func (p *Permission) Included() []jsonapi.Object { return nil } | ||
|
||
// AllowWholeType returns true if the set allows to apply verb to every | ||
// document from the given doctypes (ie. r.values == 0) | ||
func (s Set) AllowWholeType(v Verb, doctype string) bool { | ||
return s.Some(func(r Rule) bool { | ||
return validVerbAndType(r, v, doctype) && validWholeType(r) | ||
}) | ||
// SelfLink implements jsonapi.Doc | ||
func (p *Permission) SelfLink() string { return "/permissions/" + p.PID } | ||
|
||
// GetForApp retrieves the Permission doc for a given app | ||
func GetForApp(db couchdb.Database, slug string) (*Permission, error) { | ||
var res []Permission | ||
err := couchdb.FindDocs(db, consts.Permissions, &couchdb.FindRequest{ | ||
Selector: mango.Equal("application_id", consts.Manifests+"/"+slug), | ||
}, &res) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if len(res) == 0 { | ||
return nil, fmt.Errorf("no permission doc for %v", slug) | ||
} | ||
return &res[0], nil | ||
} | ||
|
||
// AllowID returns true if the set allows to apply verb to given type & id | ||
func (s Set) AllowID(v Verb, doctype, id string) bool { | ||
return s.Some(func(r Rule) bool { | ||
return validVerbAndType(r, v, doctype) && (validWholeType(r) || validID(r, id)) | ||
}) | ||
// Create creates a Permission doc for a given app | ||
func Create(db couchdb.Database, slug string, set Set) (*Permission, error) { | ||
existing, _ := GetForApp(db, slug) | ||
if existing != nil { | ||
return nil, fmt.Errorf("There is already a permission doc for %v", slug) | ||
} | ||
|
||
doc := &Permission{ | ||
ApplicationID: consts.Manifests + "/" + slug, | ||
Permissions: set, // @TODO some validation? | ||
} | ||
|
||
err := couchdb.CreateDoc(db, doc) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return doc, nil | ||
} | ||
|
||
// Allow returns true if the set allows to apply verb to given doc | ||
func (s Set) Allow(v Verb, o Validable) bool { | ||
return s.Some(func(r Rule) bool { | ||
return validVerbAndType(r, v, o.DocType()) && validValues(r, o) | ||
}) | ||
// Destroy removes Permission doc for a given app | ||
func Destroy(db couchdb.Database, slug string) error { | ||
existing, err := GetForApp(db, slug) | ||
if err != nil { | ||
return err | ||
} | ||
return couchdb.DeleteDoc(db, existing) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package permissions | ||
|
||
// Validable is an interface for a object than can be validated by a Set | ||
type Validable interface { | ||
ID() string | ||
DocType() string | ||
Valid(field, expected string) bool | ||
} | ||
|
||
func validValues(r Rule, o Validable) bool { | ||
// empty r.Values = any value | ||
if len(r.Values) == 0 { | ||
return true | ||
} | ||
|
||
if r.Selector == "" { | ||
return r.ValuesContain(o.ID()) | ||
} | ||
|
||
return r.SomeValue(func(value string) bool { | ||
return o.Valid(r.Selector, value) | ||
}) | ||
} | ||
|
||
func validVerbAndType(r Rule, v Verb, doctype string) bool { | ||
return r.Verbs.Contains(v) && r.Type == doctype | ||
} | ||
|
||
func validWholeType(r Rule) bool { | ||
return len(r.Values) == 0 | ||
} | ||
|
||
func validID(r Rule, id string) bool { | ||
return r.Selector == "" && r.ValuesContain(id) | ||
} | ||
|
||
// AllowWholeType returns true if the set allows to apply verb to every | ||
// document from the given doctypes (ie. r.values == 0) | ||
func (s Set) AllowWholeType(v Verb, doctype string) bool { | ||
return s.Some(func(r Rule) bool { | ||
return validVerbAndType(r, v, doctype) && validWholeType(r) | ||
}) | ||
} | ||
|
||
// AllowID returns true if the set allows to apply verb to given type & id | ||
func (s Set) AllowID(v Verb, doctype, id string) bool { | ||
return s.Some(func(r Rule) bool { | ||
return validVerbAndType(r, v, doctype) && (validWholeType(r) || validID(r, id)) | ||
}) | ||
} | ||
|
||
// Allow returns true if the set allows to apply verb to given doc | ||
func (s Set) Allow(v Verb, o Validable) bool { | ||
return s.Some(func(r Rule) bool { | ||
return validVerbAndType(r, v, o.DocType()) && validValues(r, o) | ||
}) | ||
} |
Oops, something went wrong.