github.com/cs3org/reva/v2@v2.27.7/internal/http/services/owncloud/ocs/ocs.go (about)

     1  // Copyright 2018-2021 CERN
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  package ocs
    20  
    21  import (
    22  	"net/http"
    23  
    24  	"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/config"
    25  	"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/sharees"
    26  	"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares"
    27  	"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/cloud/capabilities"
    28  	"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/cloud/user"
    29  	"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/cloud/users"
    30  	configHandler "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/config"
    31  	"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/response"
    32  	"github.com/cs3org/reva/v2/pkg/appctx"
    33  	"github.com/cs3org/reva/v2/pkg/rhttp/global"
    34  	"github.com/go-chi/chi/v5"
    35  	"github.com/jellydator/ttlcache/v2"
    36  	"github.com/mitchellh/mapstructure"
    37  	"github.com/rs/zerolog"
    38  )
    39  
    40  func init() {
    41  	global.Register("ocs", New)
    42  }
    43  
    44  type svc struct {
    45  	c                  *config.Config
    46  	router             *chi.Mux
    47  	warmupCacheTracker *ttlcache.Cache
    48  }
    49  
    50  // New initializes the service
    51  func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error) {
    52  	conf := &config.Config{}
    53  	if err := mapstructure.Decode(m, conf); err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	conf.Init()
    58  
    59  	r := chi.NewRouter()
    60  	s := &svc{
    61  		c:      conf,
    62  		router: r,
    63  	}
    64  
    65  	if err := s.routerInit(log); err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	if conf.CacheWarmupDriver == "first-request" && conf.StatCacheConfig.Store != "noop" {
    70  		s.warmupCacheTracker = ttlcache.NewCache()
    71  		_ = s.warmupCacheTracker.SetTTL(conf.StatCacheConfig.TTL)
    72  	}
    73  
    74  	return s, nil
    75  }
    76  
    77  func (s *svc) Prefix() string {
    78  	return s.c.Prefix
    79  }
    80  
    81  func (s *svc) Close() error {
    82  	return nil
    83  }
    84  
    85  func (s *svc) Unprotected() []string {
    86  	return []string{
    87  		"/v1.php/config",
    88  		"/v2.php/config",
    89  		"/v1.php/apps/files_sharing/api/v1/tokeninfo/unprotected",
    90  		"/v2.php/apps/files_sharing/api/v1/tokeninfo/unprotected",
    91  		"/v1.php/cloud/capabilities",
    92  		"/v2.php/cloud/capabilities",
    93  	}
    94  }
    95  
    96  func (s *svc) routerInit(log *zerolog.Logger) error {
    97  	capabilitiesHandler := new(capabilities.Handler)
    98  	userHandler := new(user.Handler)
    99  	usersHandler := new(users.Handler)
   100  	configHandler := new(configHandler.Handler)
   101  	sharesHandler := new(shares.Handler)
   102  	shareesHandler := new(sharees.Handler)
   103  	capabilitiesHandler.Init(s.c)
   104  	usersHandler.Init(s.c)
   105  	configHandler.Init(s.c)
   106  	err := sharesHandler.Init(s.c)
   107  	if err != nil {
   108  		log.Fatal().Msg(err.Error())
   109  	}
   110  	shareesHandler.Init(s.c)
   111  
   112  	s.router.Route("/v{version:(1|2)}.php", func(r chi.Router) {
   113  		r.Use(response.VersionCtx)
   114  		r.Route("/apps/files_sharing/api/v1", func(r chi.Router) {
   115  			r.Route("/shares", func(r chi.Router) {
   116  				r.Get("/", sharesHandler.ListShares)
   117  				r.Options("/", func(w http.ResponseWriter, r *http.Request) {
   118  					w.WriteHeader(http.StatusOK)
   119  				})
   120  				r.Post("/", sharesHandler.CreateShare)
   121  				r.Route("/pending/{shareid}", func(r chi.Router) {
   122  					r.Post("/", sharesHandler.AcceptReceivedShare)
   123  					r.Delete("/", sharesHandler.RejectReceivedShare)
   124  					r.Put("/", sharesHandler.UpdateReceivedShare)
   125  				})
   126  				r.Route("/remote_shares", func(r chi.Router) {
   127  					r.Get("/", sharesHandler.ListFederatedShares)
   128  					r.Get("/{shareid}", sharesHandler.GetFederatedShare)
   129  				})
   130  				r.Get("/{shareid}", sharesHandler.GetShare)
   131  				r.Put("/{shareid}", sharesHandler.UpdateShare)
   132  				r.Delete("/{shareid}", sharesHandler.RemoveShare)
   133  			})
   134  			r.Get("/sharees", shareesHandler.FindSharees)
   135  			r.Route("/tokeninfo", func(r chi.Router) {
   136  				r.Get("/protected/{tkn}", shareesHandler.TokenInfo(true))
   137  				r.Get("/unprotected/{tkn}", shareesHandler.TokenInfo(false))
   138  			})
   139  		})
   140  
   141  		// placeholder for notifications
   142  		r.Get("/apps/notifications/api/v1/notifications", func(w http.ResponseWriter, r *http.Request) {
   143  			w.WriteHeader(http.StatusOK)
   144  		})
   145  
   146  		r.Get("/config", configHandler.GetConfig)
   147  
   148  		r.Route("/cloud", func(r chi.Router) {
   149  			r.Get("/capabilities", capabilitiesHandler.GetCapabilities)
   150  			r.Get("/user", userHandler.GetSelf)
   151  			r.Route("/users", func(r chi.Router) {
   152  				r.Get("/{userid}", usersHandler.GetUsers)
   153  				r.Get("/{userid}/groups", usersHandler.GetGroups)
   154  			})
   155  		})
   156  	})
   157  
   158  	_ = chi.Walk(s.router, func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
   159  		log.Debug().Str("service", "ocs").Str("method", method).Str("route", route).Int("middlewares", len(middlewares)).Msg("serving endpoint")
   160  		return nil
   161  	})
   162  
   163  	return nil
   164  }
   165  
   166  func (s *svc) Handler() http.Handler {
   167  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   168  		log := appctx.GetLogger(r.Context())
   169  		log.Debug().Str("path", r.URL.Path).Msg("ocs routing")
   170  
   171  		// Warmup the share cache for the user
   172  		go s.cacheWarmup(w, r)
   173  
   174  		// unset raw path, otherwise chi uses it to route and then fails to match percent encoded path segments
   175  		r.URL.RawPath = ""
   176  		s.router.ServeHTTP(w, r)
   177  	})
   178  }