Skip to content

Commit df2d665

Browse files
soneda-yuyaCopilot
andauthored
fix(server): allow to access assets endpoint from custom domain (#1802)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 1966bd8 commit df2d665

File tree

12 files changed

+833
-12
lines changed

12 files changed

+833
-12
lines changed

server/e2e/common.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/gavv/httpexpect/v2"
1717
"github.com/reearth/reearth/server/internal/app"
1818
"github.com/reearth/reearth/server/internal/app/config"
19+
"github.com/reearth/reearth/server/internal/infrastructure/domain"
1920
"github.com/reearth/reearth/server/internal/infrastructure/fs"
2021
"github.com/reearth/reearth/server/internal/infrastructure/memory"
2122
"github.com/reearth/reearth/server/internal/infrastructure/mongo"
@@ -95,11 +96,13 @@ func initGateway() *gateway.Container {
9596
return &gateway.Container{
9697
File: lo.Must(fs.NewFile(afero.NewMemMapFs(), "https://example.com/")),
9798
PolicyChecker: policy.NewPermissiveChecker(),
99+
DomainChecker: domain.NewDefaultChecker(),
98100
}
99101
}
100102
return &gateway.Container{
101103
File: *fr,
102104
PolicyChecker: policy.NewPermissiveChecker(),
105+
DomainChecker: domain.NewDefaultChecker(),
103106
}
104107
}
105108

server/internal/app/app.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ func initEcho(ctx context.Context, cfg *ServerConfig) *echo.Echo {
151151
published.GET("/:name/data.json", PublishedData("", true))
152152
published.GET("/:name/", PublishedIndex("", true))
153153

154-
serveFiles(e, cfg.Gateways.File)
154+
serveFiles(e, allowedOrigins(cfg), cfg.Gateways.DomainChecker, cfg.Gateways.File)
155155

156156
serveUploadFiles(e, cfg.Gateways.File)
157157

server/internal/app/config/config.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ type VisualizerConfig struct {
8888
InternalApi InternalApiConfig `pp:",omitempty"`
8989

9090
// Policy Checker Configuration
91-
Policy Policy `pp:",omitempty"`
91+
Policy Policy `pp:",omitempty"`
92+
DomainChecker DomainCheckerConfig `pp:",omitempty"`
9293
}
9394

9495
type Policy struct {
@@ -102,6 +103,13 @@ type CheckerConfig struct {
102103
Timeout int `default:"30"`
103104
}
104105

106+
type DomainCheckerConfig struct {
107+
Type string `default:"default"`
108+
Endpoint string
109+
Token string
110+
Timeout int `default:"30"`
111+
}
112+
105113
type InternalApiConfig struct {
106114
Active bool `default:"false" pp:",omitempty"`
107115
Port string `default:"50051" pp:",omitempty"`

server/internal/app/file.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,19 @@ import (
99
"time"
1010

1111
"github.com/labstack/echo/v4"
12+
"github.com/reearth/reearth/server/internal/app/internal/middleware"
1213
"github.com/reearth/reearth/server/internal/usecase/gateway"
1314
"github.com/reearth/reearth/server/pkg/id"
1415
"github.com/reearth/reearthx/rerror"
1516
)
1617

1718
func serveFiles(
1819
ec *echo.Echo,
19-
repo gateway.File,
20+
allowedOrigins []string,
21+
domainChecker gateway.DomainChecker,
22+
fileGateway gateway.File,
2023
) {
21-
if repo == nil {
24+
if fileGateway == nil {
2225
return
2326
}
2427

@@ -44,17 +47,26 @@ func serveFiles(
4447
"/assets/:filename",
4548
fileHandler(func(ctx echo.Context) (io.Reader, string, error) {
4649
filename := ctx.Param("filename")
47-
r, err := repo.ReadAsset(ctx.Request().Context(), filename)
50+
r, err := fileGateway.ReadAsset(ctx.Request().Context(), filename)
4851
return r, filename, err
4952
}),
53+
middleware.AssetsCORSMiddleware(domainChecker, allowedOrigins),
54+
)
55+
56+
// Handle OPTIONS for assets endpoint
57+
ec.OPTIONS("/assets/:filename",
58+
func(c echo.Context) error {
59+
return c.NoContent(http.StatusNoContent)
60+
},
61+
middleware.AssetsCORSMiddleware(domainChecker, allowedOrigins),
5062
)
5163

5264
ec.GET(
5365
"/export/:filename",
5466
fileHandler(func(ctx echo.Context) (io.Reader, string, error) {
5567
filename := ctx.Param("filename")
5668

57-
r, err := repo.ReadExportProjectZip(ctx.Request().Context(), filename)
69+
r, err := fileGateway.ReadExportProjectZip(ctx.Request().Context(), filename)
5870
if err != nil {
5971
fmt.Printf("[export] !!!! download error: %s \n", filename)
6072
return nil, filename, err
@@ -66,7 +78,7 @@ func serveFiles(
6678
go func() {
6779
// download and then delete
6880
time.Sleep(3 * time.Second)
69-
err := repo.RemoveExportProjectZip(rctx, filename)
81+
err := fileGateway.RemoveExportProjectZip(rctx, filename)
7082
if err != nil {
7183
fmt.Printf("[export] !!!! delete err: %s \n", err.Error())
7284
} else {
@@ -85,7 +97,7 @@ func serveFiles(
8597
return nil, "", rerror.ErrNotFound
8698
}
8799
filename := ctx.Param("filename")
88-
r, err := repo.ReadPluginFile(ctx.Request().Context(), pid, filename)
100+
r, err := fileGateway.ReadPluginFile(ctx.Request().Context(), pid, filename)
89101
return r, filename, err
90102
}),
91103
)
@@ -94,7 +106,7 @@ func serveFiles(
94106
"/published/:name",
95107
fileHandler(func(ctx echo.Context) (io.Reader, string, error) {
96108
name := ctx.Param("name")
97-
r, err := repo.ReadBuiltSceneFile(ctx.Request().Context(), name)
109+
r, err := fileGateway.ReadBuiltSceneFile(ctx.Request().Context(), name)
98110
return r, name + ".json", err
99111
}),
100112
)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package middleware
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/labstack/echo/v4"
7+
"github.com/reearth/reearth/server/internal/usecase/gateway"
8+
"github.com/reearth/reearthx/log"
9+
)
10+
11+
func AssetsCORSMiddleware(domainChecker gateway.DomainChecker, allowedOrigins []string) func(echo.HandlerFunc) echo.HandlerFunc {
12+
return func(next echo.HandlerFunc) echo.HandlerFunc {
13+
return func(c echo.Context) error {
14+
origin := c.Request().Header.Get("Origin")
15+
if origin == "" {
16+
return c.NoContent(http.StatusBadRequest)
17+
}
18+
allowedOrigin := ""
19+
for _, allowed := range allowedOrigins {
20+
if allowed == origin {
21+
allowedOrigin = allowed
22+
break
23+
}
24+
}
25+
if allowedOrigin == "" {
26+
domainResp, err := domainChecker.CheckDomain(c.Request().Context(), gateway.DomainCheckRequest{
27+
Domain: origin,
28+
})
29+
if err != nil {
30+
log.Errorfc(c.Request().Context(), "[AssetsCORSMiddleware] domain checker check domain err: %v", err)
31+
return next(c)
32+
}
33+
if domainResp.Allowed {
34+
allowedOrigin = origin
35+
}
36+
}
37+
38+
if allowedOrigin != "" {
39+
c.Response().Header().Set("Access-Control-Allow-Origin", allowedOrigin)
40+
c.Response().Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
41+
c.Response().Header().Set("Access-Control-Allow-Headers", "*")
42+
c.Response().Header().Set("Access-Control-Max-Age", "86400")
43+
}
44+
45+
return next(c)
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)