From 2e4c48eda8a309041e96eaefa8159726f46bd264 Mon Sep 17 00:00:00 2001 From: Bruno Michel Date: Wed, 30 Oct 2024 09:43:58 +0100 Subject: [PATCH 1/2] Add a DataProxy iframe on login page for cleaning --- assets/templates/login.html | 1 + model/instance/instance.go | 8 +++++ pkg/consts/consts.go | 3 ++ web/apps/serve.go | 6 ++++ web/auth/auth.go | 6 ++++ web/statik/statik.go | 66 ++++++++++++++++++------------------- 6 files changed, 57 insertions(+), 33 deletions(-) diff --git a/assets/templates/login.html b/assets/templates/login.html index af79f781a48..a355627b53b 100644 --- a/assets/templates/login.html +++ b/assets/templates/login.html @@ -124,5 +124,6 @@

{{.Title}}

+ diff --git a/model/instance/instance.go b/model/instance/instance.go index 6339f5c24b2..0e7f8405dbc 100644 --- a/model/instance/instance.go +++ b/model/instance/instance.go @@ -546,6 +546,14 @@ func (i *Instance) ChangePasswordURL() string { return u.String() } +// DataProxyCleanURL returns the URL of the DataProxy iframe for cleaning +// PouchDB. +func (i *Instance) DataProxyCleanURL() string { + u := i.SubDomain(consts.DataProxySlug) + u.Path = "/reset" + return u.String() +} + // FromURL normalizes a given url with the scheme and domain of the instance. func (i *Instance) FromURL(u *url.URL) string { u2 := url.URL{ diff --git a/pkg/consts/consts.go b/pkg/consts/consts.go index 22615ffff0d..d8ef4c1a3d4 100644 --- a/pkg/consts/consts.go +++ b/pkg/consts/consts.go @@ -21,6 +21,9 @@ const ( // PassSlug is the slug of cozy-pass webapp, which is used by the stack for // linking the bitwarden OAuth clients. PassSlug = "passwords" + // DataProxySlug is the slug of the dataproxy webapp, which is used for + // embedding a PouchDB in the client (used by the search for example). + DataProxySlug = "dataproxy" ) const ( diff --git a/web/apps/serve.go b/web/apps/serve.go index 3a2e091c882..c17f49ac621 100644 --- a/web/apps/serve.go +++ b/web/apps/serve.go @@ -261,6 +261,12 @@ func ServeAppFile(c echo.Context, i *instance.Instance, fs appfs.FileServer, web handleIntent(c, i, slug, intentID) } + if route.Public && slug == consts.DataProxySlug { + // Allow to dataproxy to be embedded in a iframe from the login page of the + // stack for cleaning. + middlewares.AppendCSPRule(c, "frame-ancestors", i.PageURL("/", nil)) + } + // For index file, we inject the locale, the stack domain, and a token if the // user is connected content, err := fs.Open(slug, version, shasum, filepath) diff --git a/web/auth/auth.go b/web/auth/auth.go index 84f7b9144d5..b05cba926fe 100644 --- a/web/auth/auth.go +++ b/web/auth/auth.go @@ -207,6 +207,11 @@ func renderLoginForm(c echo.Context, i *instance.Instance, code int, credsErrors magicLink = false } + dataProxyCleanURL := i.DataProxyCleanURL() + csp := c.Response().Header().Get(echo.HeaderContentSecurityPolicy) + csp = strings.Replace(csp, "frame-src 'none'", "frame-src "+dataProxyCleanURL+" ", 1) + c.Response().Header().Set(echo.HeaderContentSecurityPolicy, csp) + return c.Render(code, "login.html", echo.Map{ "TemplateTitle": i.TemplateTitle(), "Domain": i.ContextualDomain(), @@ -226,6 +231,7 @@ func renderLoginForm(c echo.Context, i *instance.Instance, code int, credsErrors "MagicLink": magicLink, "OAuth": hasOAuth, "FranceConnect": hasFranceConnect, + "DataProxyCleanURL": dataProxyCleanURL, }) } diff --git a/web/statik/statik.go b/web/statik/statik.go index 91baa98c1bb..9bc354a80c5 100644 --- a/web/statik/statik.go +++ b/web/statik/statik.go @@ -36115,40 +36115,40 @@ XFrtR+aavtcw/0xFIYOvEPAWCTsmsKXAN+uFgcZeRx0iDQ== -----END COZY ASSET----- -----BEGIN COZY ASSET----- Name: /templates/login.html -Size: 5991 +Size: 6042 -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 -OnLv4Dlaq6LLHQ== +G5kXAKwK7Ab9G6P1bQhEAs3hj6DIL6f5PATtiD8pnaWj8kunnj1pXSI3tevm5B9i +KcDMBkwETdUgfXt2AyalmIysHP7PM4xHIiRGogTKvOzd5bV8Wm2XbH6vuFqFa01b +pGcwimVs2KVjhGtAHhV+YIZt5+GgxxLdIUvq/owZIg8B8ntYnLcxShMPUOU7cnWb +xNOb0ZmHFjLNZi1qWwltTHd3gQxHTHjFP2KCjibQZtjzgx4UhSFTE5fUvO8gYxr4 +1sOBU5JM2jzeoAypddNXtjZd0mdpChSNduxjxODkVey032H1nwzdiFzgbPm9v+vt +pW0XY2mJ3T/oU6tNuZRXd+bXKBOEtdsmwcZkmOMTOq0bhdOdon7gNd2ee7dSmi5R +hf4ygHuzuIIc7GrSwxYDK9lVFIoQaJC8bWwv9prDAooMfJJLbk2CZVXktS0O8jBm +GuRJOS/wf2+zASzLQaXawS5LlKSdxL9rXzdtXoIKGg/7w9BXfzx2y+gKNlAPZIpC +ZVilYh0EJAtwp1/bQ67TmHusJ22KdSW++b2HyV4f6uW3riGyd4uDmKjFz6Etp4oM +IPAHVb+s5Q5xldjk1xzYVwIaLP2DaL3cFGoE/tEj62S+QiRdegWoDpSwPRpFLx6n +TNUcRuyId37j9TPHR6cZxElUnxZK4w4MjuqUsajJYJt/IVQWDNvwRRda0a/emScz +vXXyh0zKArfAdjCFTeXtVS36NMdCU98nd7Oq2BYzpyQUz7eWDcYghZ/W3WSUm3jj +jEtySANOSJ6Xrty/TuSkKv+g4g/BcZRom1ssr2+8TPsdvfRTcRkGaKOZWLHVOK5L +EW8zRX+hQ93Llr7oIjAAa64DW6MHizbQGnSN3dA1hqEWMxZO9pyiYYerzgb5MsF+ +sU3pcupxwvpUpRp5E+kn7TW1lxgcDSuck+6wQkJji6aG5ctpt5GyfZ380OBw83hy +KFncjRyEcDVwbi1TBWJ46XkbQRG0PeHA4qtYT1/QQVQGNCu9ggu2d4MLS8h9yIty +JUnK1HO4SRfv+/lpoZkj9Z88mTkHARv7NthiS98vkmTUbkJrO+Js2yza2+eVp2gW +HNohI5HHZtE4OBv5sUMXTZ2zpi74cuuVVD6iJbRMunzoO17JMyjwy/1/fzoq8T0i +8VpsIyqtEd5hRwbHRKQdCFDLWykZSqX7YDOVta6jUfc/y90GSYRxHwpFirX3fw8F +4W1s7l8NFTo7vgfzhIecSG/jVLAwyUdIv0JfmLtZsoTMpfOCsPE5wT1qw7HBxtOD +Q98QeakjpK8kJUw+KNfCgSfHFeoF+gA1atOtTGq/h2pRP9GRte3RPCO872w0OE+x +/jAUOgisBOuti39yy9GWE5bHCvec1XnvoTlzET1QalA32yBtKy6lpVQrBNt0Tb+2 +GpEGZ5COzlZXcQDS66+WCrPaXPVyA3vXMqblalvaaGtLnGx4RBVRDYAv3gVIPXUN +VkiTF01c2I924ZmVgNU0XtFOG1qvsLfxxFOuQds5CVfsEt5lfV5GKjl5VzZcOH84 +sbsOyU4Qk+C2F2cBEwk7X6LI1J3cpwlEkSn8feQCUHpCjCuIIPXHaxIp8E5wDAtF +OdVrUxKqd++qwTpnvG6oR+8eLGMiHgkgU3nwxRy/daowG5rP+z89D+7R4Du3SDOL +R00MsRD+6SBMA1tqZMrKldkrRgzF9xGwP/Di708ltyZNFDeINxdLxMUWSdvBPpP0 +Lt4ksvPysUEsIyJbKq/YtXYScwHEMsZVR0kmglHx0HYMQ2LSb9gSeTDZVaVKa7dq +snirHRBWD6IRqlWxxC+5puLSFe9VmlpN1qKSFgt+45DtB6axeVtGBds7zTrnXe1z +nhwyxgtLjLqfYXjza1v1Is4R1VPKbMaO3iX2+w/1T+PKgRZAaJtbIHI90MOa7kUt +LIGIwbqNH0kDsUlkmVb4Q3Zznn5M/a7u+n4J+cUfyXAabMLyi9aozwoZdZ+s0Ttc +LG5fI/SKtP/ewXMVWPJQfnBAf8uZf8Rpu3vphce/TiaQ4bIYpQc= -----END COZY ASSET----- -----BEGIN COZY ASSET----- Name: /templates/magic_link_twofactor.html From df20ecc5e73128e1aec090a4029f3b0affd3ef76 Mon Sep 17 00:00:00 2001 From: Bruno Michel Date: Wed, 30 Oct 2024 12:14:53 +0100 Subject: [PATCH 2/2] Add a route GET /settings/sessions/current --- docs/settings.md | 35 +++++++++++++++++++++++++++++++++-- web/settings/settings.go | 9 +++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/docs/settings.md b/docs/settings.md index f8d8404544f..b297c1d718e 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -158,7 +158,7 @@ an HTML error page will appears. ```http HTTP/1.1 307 Temporary Redirect -Location: http://alice-settings.cozy.localhost:8080 +Location: http://alice-settings.cozy.localhost:8080 ``` @@ -367,7 +367,7 @@ route is necessary to actually update the passphrase. See below. A `"force": true` parameter can be added in the JSON to force a passphrase on a Cozy where authentication by password is disabled and the vault is empty. It allows to use Cozy Pass when the authentication on the Cozy is delegated via -OIDC. When forcing a password reset, you need to regenerate the +OIDC. When forcing a password reset, you need to regenerate the * public and private keys * encryption key @@ -923,6 +923,37 @@ Content-Type: application/json This route requires the application to have permissions on the `io.cozy.sessions` doctype with the `GET` verb. +### GET /settings/sessions/current + +This route returns information about the current session. + +``` +GET /settings/sessions/current HTTP/1.1 +Host: cozy.example.org +Cookie: ... +Authorization: Bearer ... +``` + +```http +HTTP/1.1 200 OK +Content-Type: application/json +``` + +```json +{ + "data": { + "id": "...", + "attributes": { + "last_seen": "", + "long_run": true + }, + "meta": { + "rev": "..." + } + } +} +``` + ## OAuth 2 clients ### GET /settings/clients diff --git a/web/settings/settings.go b/web/settings/settings.go index 4fdd4b2739f..686d69611fd 100644 --- a/web/settings/settings.go +++ b/web/settings/settings.go @@ -69,6 +69,14 @@ func (h *HTTPHandler) getSessions(c echo.Context) error { return jsonapi.DataList(c, http.StatusOK, objs, nil) } +func (h *HTTPHandler) getCurrentSession(c echo.Context) error { + sess, ok := middlewares.GetSession(c) + if !ok { + return jsonapi.NotFound(errors.New("no current session")) + } + return jsonapi.Data(c, http.StatusOK, &apiSession{sess}, nil) +} + func (h *HTTPHandler) listWarnings(c echo.Context) error { inst := middlewares.GetInstance(c) @@ -276,6 +284,7 @@ func (h *HTTPHandler) Register(router *echo.Group) { router.GET("/flags", h.getFlags) router.GET("/sessions", h.getSessions) + router.GET("/sessions/current", h.getCurrentSession) router.GET("/clients", h.listClients) router.DELETE("/clients/:id", h.revokeClient)