mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-05-05 02:20:28 -05:00
c9df9f5f31
drives.go implemented a local user/group cache (ttl based) to speed up repeated user and group lookups. This commit moves the implementation to the 'identity' module to make it usable outside of drives.go.
151 lines
5.8 KiB
Go
151 lines
5.8 KiB
Go
package svc
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"net/url"
|
|
"path"
|
|
"strings"
|
|
|
|
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
|
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
|
"github.com/cs3org/reva/v2/pkg/events"
|
|
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
|
"github.com/cs3org/reva/v2/pkg/storagespace"
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/jellydator/ttlcache/v3"
|
|
"github.com/owncloud/ocis/v2/ocis-pkg/keycloak"
|
|
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
|
ehsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/eventhistory/v0"
|
|
searchsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/search/v0"
|
|
settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
|
|
"github.com/owncloud/ocis/v2/services/graph/pkg/config"
|
|
"github.com/owncloud/ocis/v2/services/graph/pkg/identity"
|
|
"github.com/owncloud/ocis/v2/services/graph/pkg/service/v0/errorcode"
|
|
"go-micro.dev/v4/client"
|
|
mevents "go-micro.dev/v4/events"
|
|
"go.opentelemetry.io/otel/trace"
|
|
"google.golang.org/protobuf/types/known/emptypb"
|
|
)
|
|
|
|
//go:generate make -C ../../.. generate
|
|
|
|
// Publisher is the interface for events publisher
|
|
type Publisher interface {
|
|
Publish(string, interface{}, ...mevents.PublishOption) error
|
|
}
|
|
|
|
// Permissions is the interface used to access the permissions service
|
|
type Permissions interface {
|
|
ListPermissions(ctx context.Context, req *settingssvc.ListPermissionsRequest, opts ...client.CallOption) (*settingssvc.ListPermissionsResponse, error)
|
|
GetPermissionByID(ctx context.Context, request *settingssvc.GetPermissionByIDRequest, opts ...client.CallOption) (*settingssvc.GetPermissionByIDResponse, error)
|
|
ListPermissionsByResource(ctx context.Context, in *settingssvc.ListPermissionsByResourceRequest, opts ...client.CallOption) (*settingssvc.ListPermissionsByResourceResponse, error)
|
|
}
|
|
|
|
// HTTPClient is the subset of the http.Client that is being used to interact with the download gateway
|
|
type HTTPClient interface {
|
|
Do(req *http.Request) (*http.Response, error)
|
|
}
|
|
|
|
// GetGatewayServiceClientFunc is a callback used to pass in a mock during testing
|
|
type GetGatewayServiceClientFunc func() (gateway.GatewayAPIClient, error)
|
|
|
|
// RoleService is the interface used to access the role service
|
|
type RoleService interface {
|
|
ListRoles(ctx context.Context, in *settingssvc.ListBundlesRequest, opts ...client.CallOption) (*settingssvc.ListBundlesResponse, error)
|
|
ListRoleAssignments(ctx context.Context, in *settingssvc.ListRoleAssignmentsRequest, opts ...client.CallOption) (*settingssvc.ListRoleAssignmentsResponse, error)
|
|
AssignRoleToUser(ctx context.Context, in *settingssvc.AssignRoleToUserRequest, opts ...client.CallOption) (*settingssvc.AssignRoleToUserResponse, error)
|
|
RemoveRoleFromUser(ctx context.Context, in *settingssvc.RemoveRoleFromUserRequest, opts ...client.CallOption) (*emptypb.Empty, error)
|
|
}
|
|
|
|
// Graph defines implements the business logic for Service.
|
|
type Graph struct {
|
|
config *config.Config
|
|
mux *chi.Mux
|
|
logger *log.Logger
|
|
identityBackend identity.Backend
|
|
identityEducationBackend identity.EducationBackend
|
|
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
|
roleService RoleService
|
|
permissionsService Permissions
|
|
specialDriveItemsCache *ttlcache.Cache[string, interface{}]
|
|
identityCache identity.IdentityCache
|
|
eventsPublisher events.Publisher
|
|
searchService searchsvc.SearchProviderService
|
|
keycloakClient keycloak.Client
|
|
historyClient ehsvc.EventHistoryService
|
|
traceProvider trace.TracerProvider
|
|
}
|
|
|
|
// ServeHTTP implements the Service interface.
|
|
func (g Graph) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
// There was a number of issues with the chi router and parameters with
|
|
// slashes/percentage/other characters that didn't get properly escaped.
|
|
// This is a workaround to fix this. Also, we're not the only ones who have
|
|
// tried to fix this, as seen in this issue:
|
|
// https://github.com/go-chi/chi/issues/641#issuecomment-883156692
|
|
r.URL.RawPath = r.URL.EscapedPath()
|
|
|
|
g.mux.ServeHTTP(w, r)
|
|
}
|
|
|
|
func (g Graph) publishEvent(ctx context.Context, ev interface{}) {
|
|
if g.eventsPublisher != nil {
|
|
if err := events.Publish(ctx, g.eventsPublisher, ev); err != nil {
|
|
g.logger.Error().
|
|
Err(err).
|
|
Msg("could not publish user created event")
|
|
}
|
|
}
|
|
}
|
|
|
|
func (g Graph) getWebDavBaseURL() (*url.URL, error) {
|
|
webDavBaseURL, err := url.Parse(g.config.Spaces.WebDavBase)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
webDavBaseURL.Path = path.Join(webDavBaseURL.Path, g.config.Spaces.WebDavPath)
|
|
return webDavBaseURL, nil
|
|
}
|
|
|
|
// ListResponse is used for proper marshalling of Graph list responses
|
|
type ListResponse struct {
|
|
Value interface{} `json:"value,omitempty"`
|
|
}
|
|
|
|
const (
|
|
// ReadmeSpecialFolderName for the drive specialFolder property
|
|
ReadmeSpecialFolderName = "readme"
|
|
// SpaceImageSpecialFolderName for the drive specialFolder property
|
|
SpaceImageSpecialFolderName = "image"
|
|
)
|
|
|
|
// TODO might be different for /education/users vs /users
|
|
func (g Graph) parseMemberRef(ref string) (string, string, error) {
|
|
memberURL, err := url.ParseRequestURI(ref)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
segments := strings.Split(memberURL.Path, "/")
|
|
if len(segments) < 2 {
|
|
return "", "", errors.New("invalid member reference")
|
|
}
|
|
id := segments[len(segments)-1]
|
|
memberType := segments[len(segments)-2]
|
|
return memberType, id, nil
|
|
}
|
|
|
|
func parseIDParam(r *http.Request, param string) (storageprovider.ResourceId, error) {
|
|
driveID, err := url.PathUnescape(chi.URLParam(r, param))
|
|
if err != nil {
|
|
return storageprovider.ResourceId{}, errorcode.New(errorcode.InvalidRequest, err.Error())
|
|
}
|
|
|
|
id, err := storagespace.ParseID(driveID)
|
|
if err != nil {
|
|
return storageprovider.ResourceId{}, errorcode.New(errorcode.InvalidRequest, err.Error())
|
|
}
|
|
return id, nil
|
|
}
|