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