github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/web/remote/remote.go (about) 1 // Package remote is the used for the /remote routes. They are intended for 2 // requesting data that is not in the Cozy itself, but in a remote place. 3 package remote 4 5 import ( 6 "net/http" 7 "strings" 8 9 "github.com/cozy/cozy-stack/model/permission" 10 "github.com/cozy/cozy-stack/model/remote" 11 "github.com/cozy/cozy-stack/pkg/consts" 12 "github.com/cozy/cozy-stack/pkg/jsonapi" 13 "github.com/cozy/cozy-stack/web/middlewares" 14 "github.com/labstack/echo/v4" 15 ) 16 17 func allDoctypes(c echo.Context) error { 18 if err := middlewares.AllowWholeType(c, permission.GET, consts.Doctypes); err != nil { 19 return wrapRemoteErr(err) 20 } 21 22 inst := middlewares.GetInstance(c) 23 doctypes, err := remote.ListDoctypes(inst) 24 if err != nil { 25 return wrapRemoteErr(err) 26 } 27 return c.JSON(http.StatusOK, doctypes) 28 } 29 30 func remoteGet(c echo.Context) error { 31 doctype := c.Param("doctype") 32 slug, err := allowWholeType(c, permission.GET, doctype) 33 if err != nil { 34 return wrapRemoteErr(err) 35 } 36 instance := middlewares.GetInstance(c) 37 remote, err := remote.Find(instance, doctype) 38 if err != nil { 39 return wrapRemoteErr(err) 40 } 41 if remote.Verb != "GET" { 42 return jsonapi.MethodNotAllowed("GET") 43 } 44 err = remote.ProxyTo(instance, c.Response(), c.Request(), slug) 45 if err != nil { 46 return wrapRemoteErr(err) 47 } 48 return nil 49 } 50 51 func remotePost(c echo.Context) error { 52 doctype := c.Param("doctype") 53 slug, err := allowWholeType(c, permission.POST, doctype) 54 if err != nil { 55 return wrapRemoteErr(err) 56 } 57 instance := middlewares.GetInstance(c) 58 remote, err := remote.Find(instance, doctype) 59 if err != nil { 60 return wrapRemoteErr(err) 61 } 62 if remote.Verb != "POST" { 63 return jsonapi.MethodNotAllowed("POST") 64 } 65 err = remote.ProxyTo(instance, c.Response(), c.Request(), slug) 66 if err != nil { 67 return wrapRemoteErr(err) 68 } 69 return nil 70 } 71 72 func remoteAsset(c echo.Context) error { 73 _, err := middlewares.GetPermission(c) 74 if err != nil { 75 return err 76 } 77 return wrapRemoteErr(remote. 78 ProxyRemoteAsset(c.Param("asset-name"), c.Response())) 79 } 80 81 // Routes set the routing for the remote service 82 func Routes(router *echo.Group) { 83 router.GET("/_all_doctypes", allDoctypes) 84 router.GET("/:doctype", remoteGet) 85 router.POST("/:doctype", remotePost) 86 router.GET("/assets/:asset-name", remoteAsset) 87 88 nextcloudRoutes(router) 89 } 90 91 func wrapRemoteErr(err error) error { 92 switch err { 93 case remote.ErrNotFoundRemote: 94 return jsonapi.NotFound(err) 95 case remote.ErrInvalidRequest: 96 return jsonapi.BadRequest(err) 97 case remote.ErrRequestFailed: 98 return jsonapi.BadGateway(err) 99 case remote.ErrInvalidVariables: 100 return jsonapi.BadRequest(err) 101 case remote.ErrMissingVar: 102 return jsonapi.BadRequest(err) 103 case remote.ErrInvalidContentType: 104 return jsonapi.BadGateway(err) 105 case remote.ErrRemoteAssetNotFound: 106 return jsonapi.NotFound(err) 107 } 108 return err 109 } 110 111 func allowWholeType(c echo.Context, v permission.Verb, doctype string) (string, error) { 112 pdoc, err := middlewares.GetPermission(c) 113 if err != nil { 114 return "", err 115 } 116 if !pdoc.Permissions.AllowWholeType(v, doctype) { 117 return "", middlewares.ErrForbidden 118 } 119 slug := "" 120 if parts := strings.SplitN(pdoc.SourceID, "/", 2); len(parts) > 1 { 121 slug = parts[1] 122 } 123 return slug, nil 124 }