mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-06 12:19:37 -06:00
@@ -5,3 +5,4 @@ bumps reva version
|
||||
https://github.com/owncloud/ocis/pull/7138
|
||||
https://github.com/owncloud/ocis/pull/6427
|
||||
https://github.com/owncloud/ocis/pull/7178
|
||||
https://github.com/owncloud/ocis/pull/7217
|
||||
|
||||
2
go.mod
2
go.mod
@@ -13,7 +13,7 @@ require (
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/coreos/go-oidc/v3 v3.6.0
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20230516150832-730ac860c71d
|
||||
github.com/cs3org/reva/v2 v2.16.1-0.20230904124812-2ebd3e92cdb9
|
||||
github.com/cs3org/reva/v2 v2.16.1-0.20230906142214-864d9012e37f
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
||||
github.com/egirna/icap-client v0.1.1
|
||||
|
||||
4
go.sum
4
go.sum
@@ -1013,8 +1013,8 @@ github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo
|
||||
github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4=
|
||||
github.com/crewjam/saml v0.4.13 h1:TYHggH/hwP7eArqiXSJUvtOPNzQDyQ7vwmwEqlFWhMc=
|
||||
github.com/crewjam/saml v0.4.13/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA=
|
||||
github.com/cs3org/reva/v2 v2.16.1-0.20230904124812-2ebd3e92cdb9 h1:YWkkoagYryRH56z5pw04Py0Ebg7spCZaWpsxjwGiNgU=
|
||||
github.com/cs3org/reva/v2 v2.16.1-0.20230904124812-2ebd3e92cdb9/go.mod h1:RvhuweTFqzezjUFU0SIdTXakrEx9vJlMvQ7znPXSP1g=
|
||||
github.com/cs3org/reva/v2 v2.16.1-0.20230906142214-864d9012e37f h1:0mbvh+AvpYOp29R5LFgeqddyI0uKZnO/E3MyPEIaYdg=
|
||||
github.com/cs3org/reva/v2 v2.16.1-0.20230906142214-864d9012e37f/go.mod h1:RvhuweTFqzezjUFU0SIdTXakrEx9vJlMvQ7znPXSP1g=
|
||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
|
||||
@@ -50,13 +50,14 @@ type CapabilitiesData struct {
|
||||
|
||||
// Capabilities groups several capability aspects
|
||||
type Capabilities struct {
|
||||
Core *CapabilitiesCore `json:"core" xml:"core"`
|
||||
Checksums *CapabilitiesChecksums `json:"checksums" xml:"checksums"`
|
||||
Files *CapabilitiesFiles `json:"files" xml:"files" mapstructure:"files"`
|
||||
Dav *CapabilitiesDav `json:"dav" xml:"dav"`
|
||||
FilesSharing *CapabilitiesFilesSharing `json:"files_sharing" xml:"files_sharing" mapstructure:"files_sharing"`
|
||||
Spaces *Spaces `json:"spaces,omitempty" xml:"spaces,omitempty" mapstructure:"spaces"`
|
||||
Graph *CapabilitiesGraph `json:"graph,omitempty" xml:"graph,omitempty" mapstructure:"graph"`
|
||||
Core *CapabilitiesCore `json:"core" xml:"core"`
|
||||
Checksums *CapabilitiesChecksums `json:"checksums" xml:"checksums"`
|
||||
Files *CapabilitiesFiles `json:"files" xml:"files" mapstructure:"files"`
|
||||
Dav *CapabilitiesDav `json:"dav" xml:"dav"`
|
||||
FilesSharing *CapabilitiesFilesSharing `json:"files_sharing" xml:"files_sharing" mapstructure:"files_sharing"`
|
||||
Spaces *Spaces `json:"spaces,omitempty" xml:"spaces,omitempty" mapstructure:"spaces"`
|
||||
Graph *CapabilitiesGraph `json:"graph,omitempty" xml:"graph,omitempty" mapstructure:"graph"`
|
||||
PasswordPolicies *CapabilitiesPasswordPolicies `json:"password_policies,omitempty" xml:"password_policies,omitempty" mapstructure:"password_policies"`
|
||||
|
||||
Notifications *CapabilitiesNotifications `json:"notifications,omitempty" xml:"notifications,omitempty"`
|
||||
}
|
||||
@@ -85,6 +86,17 @@ type CapabilitiesGraph struct {
|
||||
Users CapabilitiesGraphUsers `json:"users" xml:"users" mapstructure:"users"`
|
||||
}
|
||||
|
||||
// CapabilitiesPasswordPolicies hold the password policies capabilities
|
||||
type CapabilitiesPasswordPolicies struct {
|
||||
MinCharacters int `json:"min_characters" xml:"min_characters" mapstructure:"min_characters"`
|
||||
MaxCharacters int `json:"max_characters" xml:"max_characters" mapstructure:"max_characters"`
|
||||
MinLowerCaseCharacters int `json:"min_lower_case_characters" xml:"min_lower_case_characters" mapstructure:"min_lower_case_characters"`
|
||||
MinUpperCaseCharacters int `json:"min_upper_case_characters" xml:"min_upper_case_characters" mapstructure:"min_upper_case_characters"`
|
||||
MinDigits int `json:"min_digits" xml:"min_digits" mapstructure:"min_digits"`
|
||||
MinSpecialCharacters int `json:"min_special_characters" xml:"min_special_characters" mapstructure:"min_special_characters"`
|
||||
SpecialCharacters string `json:"special_characters" xml:"special_characters" mapstructure:"special_characters"`
|
||||
}
|
||||
|
||||
// CapabilitiesGraphUsers holds the graph user capabilities
|
||||
type CapabilitiesGraphUsers struct {
|
||||
ReadOnlyAttributes []string `json:"read_only_attributes" xml:"read_only_attributes" mapstructure:"read_only_attributes"`
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
permissionsv1beta1 "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
@@ -142,7 +141,7 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request,
|
||||
}
|
||||
}
|
||||
|
||||
password := strings.TrimSpace(r.FormValue("password"))
|
||||
password := r.FormValue("password")
|
||||
if h.enforcePassword(permKey) && len(password) == 0 {
|
||||
return nil, &ocsError{
|
||||
Code: response.MetaBadRequest.StatusCode,
|
||||
@@ -150,6 +149,15 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request,
|
||||
Error: errors.New("missing required password"),
|
||||
}
|
||||
}
|
||||
if len(password) > 0 {
|
||||
if err := h.passwordValidator.Validate(password); err != nil {
|
||||
return nil, &ocsError{
|
||||
Code: response.MetaBadRequest.StatusCode,
|
||||
Message: "password validation failed",
|
||||
Error: fmt.Errorf("password validation failed: %w", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if statInfo != nil && statInfo.Type == provider.ResourceType_RESOURCE_TYPE_FILE {
|
||||
// Single file shares should never have delete or create permissions
|
||||
@@ -460,7 +468,7 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar
|
||||
newPassword, ok := r.Form["password"]
|
||||
// enforcePassword
|
||||
if h.enforcePassword(permKey) {
|
||||
if (!ok && !share.PasswordProtected) || (ok && len(strings.TrimSpace(newPassword[0])) == 0) {
|
||||
if !ok && !share.PasswordProtected || ok && len(newPassword[0]) == 0 {
|
||||
response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "missing required password", err)
|
||||
return
|
||||
}
|
||||
@@ -468,6 +476,13 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar
|
||||
|
||||
// update or clear password
|
||||
if ok {
|
||||
// skip validation if the clear password scenario
|
||||
if len(newPassword[0]) > 0 {
|
||||
if err := h.passwordValidator.Validate(newPassword[0]); err != nil {
|
||||
response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, fmt.Errorf("missing required password %w", err).Error(), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
updatesFound = true
|
||||
logger.Info().Str("shares", "update").Msg("password updated")
|
||||
updates = append(updates, &link.UpdatePublicShareRequest_Update{
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"mime"
|
||||
"net/http"
|
||||
"path"
|
||||
@@ -39,6 +40,7 @@ import (
|
||||
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/password"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/rs/zerolog"
|
||||
"google.golang.org/grpc/metadata"
|
||||
@@ -87,6 +89,7 @@ type Handler struct {
|
||||
deniable bool
|
||||
resharing bool
|
||||
publicPasswordEnforced passwordEnforced
|
||||
passwordValidator password.Validator
|
||||
|
||||
getClient GatewayClientGetter
|
||||
}
|
||||
@@ -122,7 +125,8 @@ func getCacheWarmupManager(c *config.Config) (sharecache.Warmup, error) {
|
||||
type GatewayClientGetter func() (gateway.GatewayAPIClient, error)
|
||||
|
||||
// Init initializes this and any contained handlers
|
||||
func (h *Handler) Init(c *config.Config) {
|
||||
func (h *Handler) Init(c *config.Config) error {
|
||||
var err error
|
||||
h.gatewayAddr = c.GatewaySvc
|
||||
h.machineAuthAPIKey = c.MachineAuthAPIKey
|
||||
h.storageRegistryAddr = c.StorageregistrySvc
|
||||
@@ -138,20 +142,29 @@ func (h *Handler) Init(c *config.Config) {
|
||||
h.deniable = c.EnableDenials
|
||||
h.resharing = resharing(c)
|
||||
h.publicPasswordEnforced = publicPwdEnforced(c)
|
||||
h.passwordValidator, err = passwordPolicies(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.statCache = cache.GetStatCache(c.StatCacheStore, c.StatCacheNodes, c.StatCacheDatabase, "stat", time.Duration(c.StatCacheTTL)*time.Second, c.StatCacheSize)
|
||||
if c.CacheWarmupDriver != "" {
|
||||
cwm, err := getCacheWarmupManager(c)
|
||||
if err == nil {
|
||||
go h.startCacheWarmup(cwm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go h.startCacheWarmup(cwm)
|
||||
}
|
||||
h.getClient = h.getPoolClient
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitWithGetter initializes the handler and adds the clientGetter
|
||||
func (h *Handler) InitWithGetter(c *config.Config, clientGetter GatewayClientGetter) {
|
||||
h.Init(c)
|
||||
err := h.Init(c)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
h.getClient = clientGetter
|
||||
}
|
||||
|
||||
@@ -1581,6 +1594,30 @@ func publicPwdEnforced(c *config.Config) passwordEnforced {
|
||||
return enf
|
||||
}
|
||||
|
||||
func passwordPolicies(c *config.Config) (password.Validator, error) {
|
||||
var pv password.Validator
|
||||
var err error
|
||||
if c.Capabilities.Capabilities == nil || c.Capabilities.Capabilities.PasswordPolicies == nil {
|
||||
pv, err = password.NewPasswordPolicies(0, 0, 0, 0, 0, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't init the Password Policies %w", err)
|
||||
}
|
||||
return pv, nil
|
||||
}
|
||||
pv, err = password.NewPasswordPolicies(
|
||||
c.Capabilities.Capabilities.PasswordPolicies.MinCharacters,
|
||||
c.Capabilities.Capabilities.PasswordPolicies.MinLowerCaseCharacters,
|
||||
c.Capabilities.Capabilities.PasswordPolicies.MinUpperCaseCharacters,
|
||||
c.Capabilities.Capabilities.PasswordPolicies.MinDigits,
|
||||
c.Capabilities.Capabilities.PasswordPolicies.MinSpecialCharacters,
|
||||
c.Capabilities.Capabilities.PasswordPolicies.SpecialCharacters,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't init the Password Policies %w", err)
|
||||
}
|
||||
return pv, nil
|
||||
}
|
||||
|
||||
// sufficientPermissions returns true if the `existing` permissions contain the `requested` permissions
|
||||
func sufficientPermissions(existing, requested *provider.ResourcePermissions, islink bool) bool {
|
||||
ep := conversions.RoleFromResourcePermissions(existing, islink).OCSPermissions()
|
||||
|
||||
5
vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/ocs.go
generated
vendored
5
vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/ocs.go
generated
vendored
@@ -104,7 +104,10 @@ func (s *svc) routerInit(log *zerolog.Logger) error {
|
||||
capabilitiesHandler.Init(s.c)
|
||||
usersHandler.Init(s.c)
|
||||
configHandler.Init(s.c)
|
||||
sharesHandler.Init(s.c)
|
||||
err := sharesHandler.Init(s.c)
|
||||
if err != nil {
|
||||
log.Fatal().Msg(err.Error())
|
||||
}
|
||||
shareesHandler.Init(s.c)
|
||||
|
||||
s.router.Route("/v{version:(1|2)}.php", func(r chi.Router) {
|
||||
|
||||
157
vendor/github.com/cs3org/reva/v2/pkg/password/password_policies.go
generated
vendored
Normal file
157
vendor/github.com/cs3org/reva/v2/pkg/password/password_policies.go
generated
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
package password
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Validator describes the interface providing a password Validate method
|
||||
type Validator interface {
|
||||
Validate(str string) error
|
||||
}
|
||||
|
||||
// Policies represents a password validation rules
|
||||
type Policies struct {
|
||||
minCharacters int
|
||||
minLowerCaseCharacters int
|
||||
minUpperCaseCharacters int
|
||||
minDigits int
|
||||
minSpecialCharacters int
|
||||
specialCharacters string
|
||||
digitsRegexp *regexp.Regexp
|
||||
specialCharactersRegexp *regexp.Regexp
|
||||
}
|
||||
|
||||
// NewPasswordPolicies returns a new NewPasswordPolicies instance
|
||||
func NewPasswordPolicies(minCharacters, minLowerCaseCharacters, minUpperCaseCharacters, minDigits, minSpecialCharacters int,
|
||||
specialCharacters string) (Validator, error) {
|
||||
p := &Policies{
|
||||
minCharacters: minCharacters,
|
||||
minLowerCaseCharacters: minLowerCaseCharacters,
|
||||
minUpperCaseCharacters: minUpperCaseCharacters,
|
||||
minDigits: minDigits,
|
||||
minSpecialCharacters: minSpecialCharacters,
|
||||
specialCharacters: specialCharacters,
|
||||
}
|
||||
|
||||
p.digitsRegexp = regexp.MustCompile("[0-9]")
|
||||
if len(specialCharacters) > 0 {
|
||||
var err error
|
||||
p.specialCharactersRegexp, err = regexp.Compile(specialCharactersExp(specialCharacters))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Validate implements a password validation regarding the policy
|
||||
func (s Policies) Validate(str string) error {
|
||||
var allErr error
|
||||
if !utf8.ValidString(str) {
|
||||
return fmt.Errorf("the password contains invalid characters")
|
||||
}
|
||||
err := s.validateCharacters(str)
|
||||
if err != nil {
|
||||
allErr = errors.Join(allErr, err)
|
||||
}
|
||||
err = s.validateLowerCase(str)
|
||||
if err != nil {
|
||||
allErr = errors.Join(allErr, err)
|
||||
}
|
||||
err = s.validateUpperCase(str)
|
||||
if err != nil {
|
||||
allErr = errors.Join(allErr, err)
|
||||
}
|
||||
err = s.validateDigits(str)
|
||||
if err != nil {
|
||||
allErr = errors.Join(allErr, err)
|
||||
}
|
||||
err = s.validateSpecialCharacters(str)
|
||||
if err != nil {
|
||||
allErr = errors.Join(allErr, err)
|
||||
}
|
||||
if allErr != nil {
|
||||
return allErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Policies) validateCharacters(str string) error {
|
||||
if s.count(str) < s.minCharacters {
|
||||
return fmt.Errorf("at least %d characters are required", s.minCharacters)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Policies) validateLowerCase(str string) error {
|
||||
if s.countLowerCaseCharacters(str) < s.minLowerCaseCharacters {
|
||||
return fmt.Errorf("at least %d lowercase letters are required", s.minLowerCaseCharacters)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Policies) validateUpperCase(str string) error {
|
||||
if s.countUpperCaseCharacters(str) < s.minUpperCaseCharacters {
|
||||
return fmt.Errorf("at least %d uppercase letters are required", s.minUpperCaseCharacters)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Policies) validateDigits(str string) error {
|
||||
if s.countDigits(str) < s.minDigits {
|
||||
return fmt.Errorf("at least %d numbers are required", s.minDigits)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Policies) validateSpecialCharacters(str string) error {
|
||||
if s.countSpecialCharacters(str) < s.minSpecialCharacters {
|
||||
return fmt.Errorf("at least %d special characters are required. %s", s.minSpecialCharacters, s.specialCharacters)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Policies) count(str string) int {
|
||||
return utf8.RuneCount([]byte(str))
|
||||
}
|
||||
|
||||
func (s Policies) countLowerCaseCharacters(str string) int {
|
||||
var count int
|
||||
for _, c := range str {
|
||||
if strings.ToLower(string(c)) == string(c) && strings.ToUpper(string(c)) != string(c) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func (s Policies) countUpperCaseCharacters(str string) int {
|
||||
var count int
|
||||
for _, c := range str {
|
||||
if strings.ToUpper(string(c)) == string(c) && strings.ToLower(string(c)) != string(c) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func (s Policies) countDigits(str string) int {
|
||||
return len(s.digitsRegexp.FindAllStringIndex(str, -1))
|
||||
}
|
||||
|
||||
func (s Policies) countSpecialCharacters(str string) int {
|
||||
if s.specialCharactersRegexp == nil {
|
||||
return 0
|
||||
}
|
||||
res := s.specialCharactersRegexp.FindAllStringIndex(str, -1)
|
||||
return len(res)
|
||||
}
|
||||
|
||||
func specialCharactersExp(str string) string {
|
||||
// escape the '-' character because it is a not meta-characters but, they are special inside of []
|
||||
return "[" + strings.ReplaceAll(regexp.QuoteMeta(str), "-", `\-`) + "]"
|
||||
}
|
||||
196
vendor/github.com/cs3org/reva/v2/pkg/utils/grpc.go
generated
vendored
196
vendor/github.com/cs3org/reva/v2/pkg/utils/grpc.go
generated
vendored
@@ -2,27 +2,30 @@ package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
group "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
|
||||
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
revactx "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
// GetUser gets the specified user
|
||||
func GetUser(userID *user.UserId, gwc gateway.GatewayAPIClient) (*user.User, error) {
|
||||
getUserResponse, err := gwc.GetUser(context.Background(), &user.GetUserRequest{UserId: userID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if getUserResponse.Status.Code != rpc.Code_CODE_OK {
|
||||
return nil, fmt.Errorf("error getting user: %s", getUserResponse.Status.Message)
|
||||
}
|
||||
// SpaceRole defines the user role on space
|
||||
type SpaceRole func(*storageprovider.ResourcePermissions) bool
|
||||
|
||||
return getUserResponse.GetUser(), nil
|
||||
}
|
||||
// Possible roles in spaces
|
||||
var (
|
||||
AllRole SpaceRole = func(perms *storageprovider.ResourcePermissions) bool { return true }
|
||||
ViewerRole SpaceRole = func(perms *storageprovider.ResourcePermissions) bool { return perms.Stat }
|
||||
EditorRole SpaceRole = func(perms *storageprovider.ResourcePermissions) bool { return perms.InitiateFileUpload }
|
||||
ManagerRole SpaceRole = func(perms *storageprovider.ResourcePermissions) bool { return perms.DenyGrant }
|
||||
)
|
||||
|
||||
// GetServiceUserContext returns an authenticated context of the given service user
|
||||
func GetServiceUserContext(serviceUserID string, gwc gateway.GatewayAPIClient, serviceUserSecret string) (context.Context, error) {
|
||||
@@ -41,3 +44,174 @@ func GetServiceUserContext(serviceUserID string, gwc gateway.GatewayAPIClient, s
|
||||
|
||||
return metadata.AppendToOutgoingContext(ctx, revactx.TokenHeader, authRes.Token), nil
|
||||
}
|
||||
|
||||
// GetUser gets the specified user
|
||||
func GetUser(userID *user.UserId, gwc gateway.GatewayAPIClient) (*user.User, error) {
|
||||
getUserResponse, err := gwc.GetUser(context.Background(), &user.GetUserRequest{UserId: userID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if getUserResponse.Status.Code != rpc.Code_CODE_OK {
|
||||
return nil, fmt.Errorf("error getting user: %s", getUserResponse.Status.Message)
|
||||
}
|
||||
|
||||
return getUserResponse.GetUser(), nil
|
||||
}
|
||||
|
||||
// GetSpace returns the given space
|
||||
func GetSpace(ctx context.Context, spaceID string, gwc gateway.GatewayAPIClient) (*storageprovider.StorageSpace, error) {
|
||||
res, err := gwc.ListStorageSpaces(ctx, listStorageSpaceRequest(spaceID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if res.GetStatus().GetCode() != rpc.Code_CODE_OK {
|
||||
return nil, fmt.Errorf("error while getting space: (%v) %s", res.GetStatus().GetCode(), res.GetStatus().GetMessage())
|
||||
}
|
||||
|
||||
if len(res.StorageSpaces) == 0 {
|
||||
return nil, fmt.Errorf("error getting storage space %s: no space returned", spaceID)
|
||||
}
|
||||
|
||||
return res.StorageSpaces[0], nil
|
||||
}
|
||||
|
||||
// GetGroupMembers returns all members of the given group
|
||||
func GetGroupMembers(ctx context.Context, groupID string, gwc gateway.GatewayAPIClient) ([]string, error) {
|
||||
r, err := gwc.GetGroup(ctx, &group.GetGroupRequest{GroupId: &group.GroupId{OpaqueId: groupID}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r.GetStatus().GetCode() != rpc.Code_CODE_OK {
|
||||
return nil, fmt.Errorf("unexpected status code from gateway client: %d", r.GetStatus().GetCode())
|
||||
}
|
||||
|
||||
users := make([]string, 0, len(r.GetGroup().GetMembers()))
|
||||
for _, u := range r.GetGroup().GetMembers() {
|
||||
users = append(users, u.GetOpaqueId())
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
// ResolveID returns either the given userID or all members of the given groupID (if userID is nil)
|
||||
func ResolveID(ctx context.Context, userid *user.UserId, groupid *group.GroupId, gwc gateway.GatewayAPIClient) ([]string, error) {
|
||||
if userid != nil {
|
||||
return []string{userid.GetOpaqueId()}, nil
|
||||
}
|
||||
|
||||
if ctx == nil {
|
||||
return nil, errors.New("need ctx to resolve group id")
|
||||
}
|
||||
|
||||
return GetGroupMembers(ctx, groupid.GetOpaqueId(), gwc)
|
||||
}
|
||||
|
||||
// GetSpaceMembers returns all members of the given space that have at least the given role. `nil` role will be interpreted as all
|
||||
func GetSpaceMembers(ctx context.Context, spaceID string, gwc gateway.GatewayAPIClient, role SpaceRole) ([]string, error) {
|
||||
if ctx == nil {
|
||||
return nil, errors.New("need authenticated context to find space members")
|
||||
}
|
||||
|
||||
space, err := GetSpace(ctx, spaceID, gwc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var users []string
|
||||
switch space.SpaceType {
|
||||
case "personal":
|
||||
users = append(users, space.GetOwner().GetId().GetOpaqueId())
|
||||
case "project":
|
||||
if users, err = gatherProjectSpaceMembers(ctx, space, gwc, role); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
// TODO: shares? other space types?
|
||||
return nil, fmt.Errorf("unsupported space type: %s", space.SpaceType)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
// GetResourceByID is a convenience method to get a resource by its resourceID
|
||||
func GetResourceByID(ctx context.Context, resourceid *storageprovider.ResourceId, gwc gateway.GatewayAPIClient) (*storageprovider.ResourceInfo, error) {
|
||||
return GetResource(ctx, &storageprovider.Reference{ResourceId: resourceid}, gwc)
|
||||
}
|
||||
|
||||
// GetResource returns a resource by reference
|
||||
func GetResource(ctx context.Context, ref *storageprovider.Reference, gwc gateway.GatewayAPIClient) (*storageprovider.ResourceInfo, error) {
|
||||
res, err := gwc.Stat(ctx, &storageprovider.StatRequest{Ref: ref})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if res.GetStatus().GetCode() != rpc.Code_CODE_OK {
|
||||
return nil, fmt.Errorf("unexpected status code while getting space: %v", res.GetStatus().GetCode())
|
||||
}
|
||||
|
||||
return res.GetInfo(), nil
|
||||
}
|
||||
|
||||
func gatherProjectSpaceMembers(ctx context.Context, space *storageprovider.StorageSpace, gwc gateway.GatewayAPIClient, role SpaceRole) ([]string, error) {
|
||||
var permissionsMap map[string]*storageprovider.ResourcePermissions
|
||||
if err := ReadJSONFromOpaque(space.GetOpaque(), "grants", &permissionsMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
groupsMap := make(map[string]struct{})
|
||||
if opaqueGroups, ok := space.Opaque.Map["groups"]; ok {
|
||||
_ = json.Unmarshal(opaqueGroups.GetValue(), &groupsMap)
|
||||
}
|
||||
|
||||
if role == nil {
|
||||
role = AllRole
|
||||
}
|
||||
|
||||
// we use a map to avoid duplicates
|
||||
usermap := make(map[string]struct{})
|
||||
for id, perm := range permissionsMap {
|
||||
if !role(perm) {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, isGroup := groupsMap[id]; !isGroup {
|
||||
usermap[id] = struct{}{}
|
||||
continue
|
||||
}
|
||||
|
||||
usrs, err := GetGroupMembers(ctx, id, gwc)
|
||||
if err != nil {
|
||||
// TODO: continue?
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, u := range usrs {
|
||||
usermap[u] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
users := make([]string, 0, len(usermap))
|
||||
for id := range usermap {
|
||||
users = append(users, id)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func listStorageSpaceRequest(spaceID string) *storageprovider.ListStorageSpacesRequest {
|
||||
return &storageprovider.ListStorageSpacesRequest{
|
||||
Opaque: AppendPlainToOpaque(nil, "unrestricted", "true"),
|
||||
Filters: []*storageprovider.ListStorageSpacesRequest_Filter{
|
||||
{
|
||||
Type: storageprovider.ListStorageSpacesRequest_Filter_TYPE_ID,
|
||||
Term: &storageprovider.ListStorageSpacesRequest_Filter_Id{
|
||||
Id: &storageprovider.StorageSpaceId{
|
||||
OpaqueId: spaceID,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@@ -356,7 +356,7 @@ github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1
|
||||
github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1
|
||||
github.com/cs3org/go-cs3apis/cs3/tx/v1beta1
|
||||
github.com/cs3org/go-cs3apis/cs3/types/v1beta1
|
||||
# github.com/cs3org/reva/v2 v2.16.1-0.20230904124812-2ebd3e92cdb9
|
||||
# github.com/cs3org/reva/v2 v2.16.1-0.20230906142214-864d9012e37f
|
||||
## explicit; go 1.20
|
||||
github.com/cs3org/reva/v2/cmd/revad/internal/grace
|
||||
github.com/cs3org/reva/v2/cmd/revad/runtime
|
||||
@@ -554,6 +554,7 @@ github.com/cs3org/reva/v2/pkg/ocm/share/manager/loader
|
||||
github.com/cs3org/reva/v2/pkg/ocm/share/manager/nextcloud
|
||||
github.com/cs3org/reva/v2/pkg/ocm/share/manager/registry
|
||||
github.com/cs3org/reva/v2/pkg/ocm/share/sender
|
||||
github.com/cs3org/reva/v2/pkg/password
|
||||
github.com/cs3org/reva/v2/pkg/permission
|
||||
github.com/cs3org/reva/v2/pkg/permission/manager/demo
|
||||
github.com/cs3org/reva/v2/pkg/permission/manager/loader
|
||||
|
||||
Reference in New Issue
Block a user