Repository: owncloud/ocis
Pull request #10185 (2024-09-30 06:57:59)

chore(deps-dev): bump i18next-parser from 8.13.0 to 9.0.2 in /services/idp
Bumps [i18next-parser](https://github.com/i18next/i18next-parser) from 8.13.0 to 9.0.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/i18next/i18next-parser/releases">i18next-parser's releases</a>.</em></p>
<blockquote>
<h2>9.0.1</h2>
<p>See <a href="https://github.com/i18next/i18next-parser/blob/master/docs/migration.md">Migration documentation here</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/i18next/i18next-parser/blob/master/CHANGELOG.md">i18next-parser's changelog</a>.</em></p>
<blockquote>
<h1>9.0.2</h1>
<ul>
<li>Fix cheerio dependency <a href="https://redirect.github.com/i18next/i18next-parser/issues/1045">#1045</a></li>
<li>Update dependencies</li>
</ul>
<h1>9.0.1</h1>
<ul>
<li>Fix plurals not being detected when count is a CallExpression <a href="https://redirect.github.com/i18next/i18next-parser/issues/1022">#1022</a> <a href="https://redirect.github.com/i18next/i18next-parser/issues/1015">#1015</a></li>
<li>Use utf-8 as default encoding to read files <a href="https://redirect.github.com/i18next/i18next-parser/issues/992">#992</a></li>
<li>Update dependencies</li>
</ul>
<h1>9.0.0</h1>
<ul>
<li>Custom contextSeparator fix <a href="https://redirect.github.com/i18next/i18next-parser/issues/1008">#1008</a></li>
<li>Remove VueLexer <a href="https://redirect.github.com/i18next/i18next-parser/issues/1007">#1007</a> <a href="https://redirect.github.com/i18next/i18next-parser/issues/617">#617</a></li>
<li>Fix t func in options <a href="https://redirect.github.com/i18next/i18next-parser/issues/994">#994</a> <a href="https://redirect.github.com/i18next/i18next-parser/issues/779">#779</a></li>
<li>Support for Node 16 is dropped. Node 18, 20 and 22 are supported.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/i18next/i18next-parser/commit/a668b2322fa754b0045a8ba00cf2e05d6f8339ac"><code>a668b23</code></a> Bump to 9.0.2</li>
<li><a href="https://github.com/i18next/i18next-parser/commit/6a48bd460ede9f01decbf9f2e3bbaa70ee781d83"><code>6a48bd4</code></a> Update cheerio dependency</li>
<li><a href="https://github.com/i18next/i18next-parser/commit/873bb18c783125e22f7e89df0672970f53e5177c"><code>873bb18</code></a> Merge pull request <a href="https://redirect.github.com/i18next/i18next-parser/issues/1032">#1032</a> from i18next/dependabot/npm_and_yarn/master/babel/pl...</li>
<li><a href="https://github.com/i18next/i18next-parser/commit/d2b28228e0ed44ca36e45e4aaec1d6b6fc377cdb"><code>d2b2822</code></a> Build(deps-dev): bump <code>@​babel/plugin-transform-runtime</code></li>
<li><a href="https://github.com/i18next/i18next-parser/commit/294265cb904dcaec8264ddfa629a22f121cc4ba3"><code>294265c</code></a> Merge pull request <a href="https://redirect.github.com/i18next/i18next-parser/issues/1034">#1034</a> from i18next/dependabot/npm_and_yarn/master/typescri...</li>
<li><a href="https://github.com/i18next/i18next-parser/commit/ef979c386f0c7a255770aaff192886ee36ee39f0"><code>ef979c3</code></a> Merge pull request <a href="https://redirect.github.com/i18next/i18next-parser/issues/1031">#1031</a> from i18next/dependabot/npm_and_yarn/master/c8-10.1.2</li>
<li><a href="https://github.com/i18next/i18next-parser/commit/3024dd00978746f6a33264340f80d88b5cd7f64e"><code>3024dd0</code></a> Merge pull request <a href="https://redirect.github.com/i18next/i18next-parser/issues/1035">#1035</a> from i18next/dependabot/npm_and_yarn/master/husky-9.1.4</li>
<li><a href="https://github.com/i18next/i18next-parser/commit/ce4c1e406f39c23c4f175b3d1793e53a423e757f"><code>ce4c1e4</code></a> Merge pull request <a href="https://redirect.github.com/i18next/i18next-parser/issues/1037">#1037</a> from i18next/dependabot/npm_and_yarn/master/babel/pr...</li>
<li><a href="https://github.com/i18next/i18next-parser/commit/9c96f37bf97ca38725e13ea824d7e755d3cca358"><code>9c96f37</code></a> Build(deps-dev): bump <code>@​babel/preset-env</code> from 7.25.0 to 7.25.3</li>
<li><a href="https://github.com/i18next/i18next-parser/commit/5fe59428a03989208b7738d743c3e9fb64aed6cb"><code>5fe5942</code></a> Build(deps-dev): bump husky from 9.0.11 to 9.1.4</li>
<li>Additional commits viewable in <a href="https://github.com/i18next/i18next-parser/compare/8.13.0...9.0.2">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=i18next-parser&package-manager=npm_and_yarn&previous-version=8.13.0&new-version=9.0.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a5a74eff603..41550f4c345 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -59,6 +59,7 @@ The following sections list the changes for unreleased.
 * Bugfix - Fixed proxy build info: [#10039](https://github.com/owncloud/ocis/pull/10039)
 * Bugfix - Fixed the ocm tocken: [#10050](https://github.com/owncloud/ocis/pull/10050)
 * Bugfix - Fix ocm space sharing: [#10060](https://github.com/owncloud/ocis/pull/10060)
+* Bugfix - Fix the error code for ocm space sharing: [#10079](https://github.com/owncloud/ocis/pull/10079)
 * Bugfix - Added LinkUpdated activity: [#10085](https://github.com/owncloud/ocis/pull/10085)
 * Bugfix - Fix Activities leak: [#10092](https://github.com/owncloud/ocis/pull/10092)
 * Bugfix - Include additional logs in the collaboration service: [#10101](https://github.com/owncloud/ocis/pull/10101)
@@ -78,6 +79,7 @@ The following sections list the changes for unreleased.
 * Enhancement - Load CSP configuration file if it exists: [#10139](https://github.com/owncloud/ocis/pull/10139)
 * Enhancement - Bump reva: [#10157](https://github.com/owncloud/ocis/pull/10157)
 * Enhancement - FileDownloaded Activity: [#10161](https://github.com/owncloud/ocis/pull/10161)
+* Enhancement - Add WOPI host URLs to the collaboration service: [#10174](https://github.com/owncloud/ocis/pull/10174)
 * Enhancement - Update web to v10.3.0: [#10177](https://github.com/owncloud/ocis/pull/10177)
 
 ## Details
@@ -114,6 +116,13 @@ The following sections list the changes for unreleased.
    https://github.com/owncloud/ocis/issues/10051
    https://github.com/owncloud/ocis/pull/10060
 
+* Bugfix - Fix the error code for ocm space sharing: [#10079](https://github.com/owncloud/ocis/pull/10079)
+
+   We fixed the error code for ocm space sharing
+
+   https://github.com/owncloud/ocis/issues/10051
+   https://github.com/owncloud/ocis/pull/10079
+
 * Bugfix - Added LinkUpdated activity: [#10085](https://github.com/owncloud/ocis/pull/10085)
 
    Added the LinkUpdated activity in the space context
@@ -257,6 +266,14 @@ The following sections list the changes for unreleased.
 
    https://github.com/owncloud/ocis/pull/10161
 
+* Enhancement - Add WOPI host URLs to the collaboration service: [#10174](https://github.com/owncloud/ocis/pull/10174)
+
+   We added the WOPI host urls to create a better integration with WOPI clients.
+   This allows the WOPI apps to display links to our sharing and versions panel in
+   the UI.
+
+   https://github.com/owncloud/ocis/pull/10174
+
 * Enhancement - Update web to v10.3.0: [#10177](https://github.com/owncloud/ocis/pull/10177)
 
    Tags: web
diff --git a/changelog/unreleased/fix-ocm-space-sharing-code.md b/changelog/unreleased/fix-ocm-space-sharing-code.md
new file mode 100644
index 00000000000..885ac91f3de
--- /dev/null
+++ b/changelog/unreleased/fix-ocm-space-sharing-code.md
@@ -0,0 +1,6 @@
+Bugfix: fix the error code for ocm space sharing
+
+We fixed the error code for ocm space sharing
+
+https://github.com/owncloud/ocis/pull/10079
+https://github.com/owncloud/ocis/issues/10051
diff --git a/changelog/unreleased/wopi-host-urls.md b/changelog/unreleased/wopi-host-urls.md
new file mode 100644
index 00000000000..a730f95b2af
--- /dev/null
+++ b/changelog/unreleased/wopi-host-urls.md
@@ -0,0 +1,5 @@
+Enhancement: Add WOPI host URLs to the collaboration service
+
+We added the WOPI host urls to create a better integration with WOPI clients. This allows the WOPI apps to display links to our sharing and versions panel in the UI.
+
+https://github.com/owncloud/ocis/pull/10174
diff --git a/go.mod b/go.mod
index dd499f0d5a3..65fb15a312c 100644
--- a/go.mod
+++ b/go.mod
@@ -58,7 +58,7 @@ require (
 	github.com/kovidgoyal/imaging v1.6.3
 	github.com/leonelquinteros/gotext v1.6.1
 	github.com/libregraph/idm v0.5.0
-	github.com/libregraph/lico v0.62.0
+	github.com/libregraph/lico v0.64.0
 	github.com/mitchellh/mapstructure v1.5.0
 	github.com/mna/pigeon v1.3.0
 	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
@@ -77,8 +77,8 @@ require (
 	github.com/prometheus/client_golang v1.20.4
 	github.com/r3labs/sse/v2 v2.10.0
 	github.com/riandyrn/otelchi v0.10.0
-	github.com/rogpeppe/go-internal v1.12.0
-	github.com/rs/cors v1.11.0
+	github.com/rogpeppe/go-internal v1.13.1
+	github.com/rs/cors v1.11.1
 	github.com/rs/zerolog v1.33.0
 	github.com/shamaton/msgpack/v2 v2.2.2
 	github.com/sirupsen/logrus v1.9.3
diff --git a/go.sum b/go.sum
index ceaa9220025..30d83cd5715 100644
--- a/go.sum
+++ b/go.sum
@@ -782,8 +782,8 @@ github.com/leonelquinteros/gotext v1.6.1 h1:PuTN8YUqHvfPZxW+fPXp7o0Fc2zN9L2wXBZr
 github.com/leonelquinteros/gotext v1.6.1/go.mod h1:qQRISjoonXYFdRGrTG1LARQ38Gpibad0IPeB4hpvyyM=
 github.com/libregraph/idm v0.5.0 h1:tDMwKbAOZzdeDYMxVlY5PbSqRKO7dbAW9KT42A51WSk=
 github.com/libregraph/idm v0.5.0/go.mod h1:BGMwIQ/6orJSPVzJ1x6kgG2JyG9GY05YFmbsnaD80k0=
-github.com/libregraph/lico v0.62.0 h1:4aa0hp8kLCj/oy/aGuGKQCzdQRLHY/cvDs25bdkdcXU=
-github.com/libregraph/lico v0.62.0/go.mod h1:Byuq0dALiJD9hpx2gvX5UTVZ6eWZs3sO0SeoXQQeFcE=
+github.com/libregraph/lico v0.64.0 h1:fbMV2ALjrOysGL0m58bhRrF+9e/HCL5RkoSwMN+xoWQ=
+github.com/libregraph/lico v0.64.0/go.mod h1:J2ZNe1DcO+K/5ptOOrQk2A2mn6OwXRdGUI4ASgw2WGg=
 github.com/libregraph/oidc-go v1.1.0 h1:RyudjL3UyQblqeBQI06W53PniWobqODeeyAy6v/HumA=
 github.com/libregraph/oidc-go v1.1.0/go.mod h1:qW9ubcXvZrfbbWZBaLMuk7bt5qAUMYyt9/NtXQt07Cw=
 github.com/linode/linodego v0.25.3/go.mod h1:GSBKPpjoQfxEfryoCRcgkuUOCuVtGHWhzI8OMdycNTE=
@@ -1050,10 +1050,10 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
 github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
-github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
-github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po=
-github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
+github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
 github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
 github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
 github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
diff --git a/services/collaboration/pkg/connector/fileconnector.go b/services/collaboration/pkg/connector/fileconnector.go
index a52b52fa76f..c771acdb834 100644
--- a/services/collaboration/pkg/connector/fileconnector.go
+++ b/services/collaboration/pkg/connector/fileconnector.go
@@ -1118,9 +1118,14 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
 	if err != nil {
 		return nil, err
 	}
+
+	fileRef := wopiContext.FileReference
+	// set path to empty string to get the full path from the stat
+	fileRef.Path = ""
 	statRes, err := gwc.Stat(ctx, &providerv1beta1.StatRequest{
-		Ref: wopiContext.FileReference,
+		Ref: fileRef,
 	})
+
 	if err != nil {
 		logger.Error().Err(err).Msg("CheckFileInfo: stat failed")
 		return nil, err
@@ -1175,18 +1180,17 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
 	}
 
 	breadcrumbFolderName := path.Dir(statRes.Info.Path)
-	if breadcrumbFolderName == "." || breadcrumbFolderName == "" {
+	if breadcrumbFolderName == "." || breadcrumbFolderName == "" || breadcrumbFolderName == "/" {
 		breadcrumbFolderName = statRes.GetInfo().GetSpace().GetName()
 	}
 
-	ocisUrl, err := url.Parse(f.cfg.Commons.OcisURL)
+	ocisURL, err := url.Parse(f.cfg.Commons.OcisURL)
 	if err != nil {
 		return nil, err
 	}
-	breadcrumbFolderURL, viewAppUrl, editAppUrl := *ocisUrl, *ocisUrl, *ocisUrl
-	breadcrumbFolderURL.Path = path.Join(breadcrumbFolderURL.Path, "f", storagespace.FormatResourceID(statRes.GetInfo().GetId()))
-	viewAppUrl.Path = path.Join(viewAppUrl.Path, "external"+strings.ToLower(f.cfg.App.Name))
-	editAppUrl.Path = path.Join(editAppUrl.Path, "external"+strings.ToLower(f.cfg.App.Name))
+	privateLinkURL := &url.URL{}
+	*privateLinkURL = *ocisURL
+	privateLinkURL.Path = path.Join(ocisURL.Path, "f", storagespace.FormatResourceID(statRes.GetInfo().GetId()))
 	// fileinfo map
 	infoMap := map[string]interface{}{
 		fileinfo.KeyOwnerID:           hexEncodedOwnerId,
@@ -1196,10 +1200,12 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
 		fileinfo.KeyBreadcrumbDocName: path.Base(statRes.GetInfo().GetPath()),
 		// to get the folder we actually need to do a GetPath() request
 		fileinfo.KeyBreadcrumbFolderName: breadcrumbFolderName,
-		fileinfo.KeyBreadcrumbFolderURL:  breadcrumbFolderURL.String(),
+		fileinfo.KeyBreadcrumbFolderURL:  privateLinkURL.String(),
 
-		//fileinfo.KeyHostViewURL: viewAppUrl.String(),
-		//fileinfo.KeyHostEditURL: editAppUrl.String(),
+		fileinfo.KeyHostViewURL:    createHostUrl("view", ocisURL, f.cfg.App.Name, statRes.GetInfo()),
+		fileinfo.KeyHostEditURL:    createHostUrl("write", ocisURL, f.cfg.App.Name, statRes.GetInfo()),
+		fileinfo.KeyFileSharingURL: createShareUrl(privateLinkURL),
+		fileinfo.KeyFileVersionURL: createVersionsUrl(privateLinkURL),
 
 		fileinfo.KeyEnableOwnerTermination:     true, // only for collabora
 		fileinfo.KeySupportsExtendedLockLength: true,
@@ -1240,6 +1246,42 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
 	return NewResponseSuccessBody(info), nil
 }
 
+func createHostUrl(mode string, ocisUrl *url.URL, appName string, info *providerv1beta1.ResourceInfo) string {
+	webUrl := createAppExternalURL(ocisUrl, appName, info)
+	addURLParams(webUrl, map[string]string{"view_mode": mode})
+	return webUrl.String()
+}
+
+func createShareUrl(ocisURL *url.URL) string {
+	shareURL := *ocisURL
+	addURLParams(&shareURL, map[string]string{"details": "sharing"})
+	return shareURL.String()
+}
+
+func createVersionsUrl(ocisURL *url.URL) string {
+	versionsURL := *ocisURL
+	addURLParams(&versionsURL, map[string]string{"details": "versions"})
+	return versionsURL.String()
+}
+
+func addURLParams(u *url.URL, params map[string]string) {
+	q := u.Query()
+	for k, v := range params {
+		q.Add(k, v)
+	}
+	u.RawQuery = q.Encode()
+}
+
+func createAppExternalURL(ocisURL *url.URL, appName string, info *providerv1beta1.ResourceInfo) *url.URL {
+	spaceAlias := utils.ReadPlainFromOpaque(info.GetSpace().GetOpaque(), "spaceAlias")
+	appExternalURL := *ocisURL
+	appExternalURL.Path = path.Join(ocisURL.Path, "external-"+strings.ToLower(appName), spaceAlias, info.GetPath())
+	q := ocisURL.Query()
+	q.Add("fileId", storagespace.FormatResourceID(info.GetId()))
+	appExternalURL.RawQuery = q.Encode()
+	return &appExternalURL
+}
+
 func (f *FileConnector) watermarkText(user *userv1beta1.User) string {
 	if user != nil {
 		return strings.TrimSpace(user.GetDisplayName() + " " + user.GetMail())
diff --git a/services/graph/pkg/service/v0/api_driveitem_permissions.go b/services/graph/pkg/service/v0/api_driveitem_permissions.go
index c76c61abe87..c43e358fe65 100644
--- a/services/graph/pkg/service/v0/api_driveitem_permissions.go
+++ b/services/graph/pkg/service/v0/api_driveitem_permissions.go
@@ -329,7 +329,7 @@ func (s DriveItemPermissionsService) SpaceRootInvite(ctx context.Context, driveI
 		objectID := invite.GetRecipients()[0].GetObjectId()
 		_, err := s.identityCache.GetAcceptedUser(ctx, objectID)
 		if err == nil {
-			return libregraph.Permission{}, errorcode.New(errorcode.NotAllowed, "federated user can not become a space member")
+			return libregraph.Permission{}, errorcode.New(errorcode.InvalidRequest, "federated user can not become a space member")
 		}
 	}
 
diff --git a/services/idp/package.json b/services/idp/package.json
index c919ecc0a2a..307cceaa098 100644
--- a/services/idp/package.json
+++ b/services/idp/package.json
@@ -133,7 +133,7 @@
     "file-loader": "6.2.0",
     "html-webpack-plugin": "5.6.0",
     "i18next-conv": "^14.1.0",
-    "i18next-parser": "^8.13.0",
+    "i18next-parser": "^9.0.2",
     "jest": "29.7.0",
     "license-checker-rseidelsohn": "4.3.0",
     "mini-css-extract-plugin": "1.6.2",
diff --git a/services/idp/pnpm-lock.yaml b/services/idp/pnpm-lock.yaml
index a9dc41adfb4..8c408f32cd8 100644
--- a/services/idp/pnpm-lock.yaml
+++ b/services/idp/pnpm-lock.yaml
@@ -193,8 +193,8 @@ importers:
         specifier: ^14.1.0
         version: 14.1.0
       i18next-parser:
-        specifier: ^8.13.0
-        version: 8.13.0
+        specifier: ^9.0.2
+        version: 9.0.2
       jest:
         specifier: 29.7.0
         version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)
@@ -1235,141 +1235,147 @@ packages:
   '@emotion/hash@0.8.0':
     resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==}
 
-  '@esbuild/aix-ppc64@0.20.2':
-    resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==}
-    engines: {node: '>=12'}
+  '@esbuild/aix-ppc64@0.23.1':
+    resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
+    engines: {node: '>=18'}
     cpu: [ppc64]
     os: [aix]
 
-  '@esbuild/android-arm64@0.20.2':
-    resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==}
-    engines: {node: '>=12'}
+  '@esbuild/android-arm64@0.23.1':
+    resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==}
+    engines: {node: '>=18'}
     cpu: [arm64]
     os: [android]
 
-  '@esbuild/android-arm@0.20.2':
-    resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==}
-    engines: {node: '>=12'}
+  '@esbuild/android-arm@0.23.1':
+    resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==}
+    engines: {node: '>=18'}
     cpu: [arm]
     os: [android]
 
-  '@esbuild/android-x64@0.20.2':
-    resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==}
-    engines: {node: '>=12'}
+  '@esbuild/android-x64@0.23.1':
+    resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==}
+    engines: {node: '>=18'}
     cpu: [x64]
     os: [android]
 
-  '@esbuild/darwin-arm64@0.20.2':
-    resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==}
-    engines: {node: '>=12'}
+  '@esbuild/darwin-arm64@0.23.1':
+    resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==}
+    engines: {node: '>=18'}
     cpu: [arm64]
     os: [darwin]
 
-  '@esbuild/darwin-x64@0.20.2':
-    resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==}
-    engines: {node: '>=12'}
+  '@esbuild/darwin-x64@0.23.1':
+    resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==}
+    engines: {node: '>=18'}
     cpu: [x64]
     os: [darwin]
 
-  '@esbuild/freebsd-arm64@0.20.2':
-    resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==}
-    engines: {node: '>=12'}
+  '@esbuild/freebsd-arm64@0.23.1':
+    resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==}
+    engines: {node: '>=18'}
     cpu: [arm64]
     os: [freebsd]
 
-  '@esbuild/freebsd-x64@0.20.2':
-    resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==}
-    engines: {node: '>=12'}
+  '@esbuild/freebsd-x64@0.23.1':
+    resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==}
+    engines: {node: '>=18'}
     cpu: [x64]
     os: [freebsd]
 
-  '@esbuild/linux-arm64@0.20.2':
-    resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==}
-    engines: {node: '>=12'}
+  '@esbuild/linux-arm64@0.23.1':
+    resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==}
+    engines: {node: '>=18'}
     cpu: [arm64]
     os: [linux]
 
-  '@esbuild/linux-arm@0.20.2':
-    resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==}
-    engines: {node: '>=12'}
+  '@esbuild/linux-arm@0.23.1':
+    resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==}
+    engines: {node: '>=18'}
     cpu: [arm]
     os: [linux]
 
-  '@esbuild/linux-ia32@0.20.2':
-    resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==}
-    engines: {node: '>=12'}
+  '@esbuild/linux-ia32@0.23.1':
+    resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==}
+    engines: {node: '>=18'}
     cpu: [ia32]
     os: [linux]
 
-  '@esbuild/linux-loong64@0.20.2':
-    resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==}
-    engines: {node: '>=12'}
+  '@esbuild/linux-loong64@0.23.1':
+    resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==}
+    engines: {node: '>=18'}
     cpu: [loong64]
     os: [linux]
 
-  '@esbuild/linux-mips64el@0.20.2':
-    resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==}
-    engines: {node: '>=12'}
+  '@esbuild/linux-mips64el@0.23.1':
+    resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==}
+    engines: {node: '>=18'}
     cpu: [mips64el]
     os: [linux]
 
-  '@esbuild/linux-ppc64@0.20.2':
-    resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==}
-    engines: {node: '>=12'}
+  '@esbuild/linux-ppc64@0.23.1':
+    resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==}
+    engines: {node: '>=18'}
     cpu: [ppc64]
     os: [linux]
 
-  '@esbuild/linux-riscv64@0.20.2':
-    resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==}
-    engines: {node: '>=12'}
+  '@esbuild/linux-riscv64@0.23.1':
+    resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==}
+    engines: {node: '>=18'}
     cpu: [riscv64]
     os: [linux]
 
-  '@esbuild/linux-s390x@0.20.2':
-    resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==}
-    engines: {node: '>=12'}
+  '@esbuild/linux-s390x@0.23.1':
+    resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==}
+    engines: {node: '>=18'}
     cpu: [s390x]
     os: [linux]
 
-  '@esbuild/linux-x64@0.20.2':
-    resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==}
-    engines: {node: '>=12'}
+  '@esbuild/linux-x64@0.23.1':
+    resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==}
+    engines: {node: '>=18'}
     cpu: [x64]
     os: [linux]
 
-  '@esbuild/netbsd-x64@0.20.2':
-    resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==}
-    engines: {node: '>=12'}
+  '@esbuild/netbsd-x64@0.23.1':
+    resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==}
+    engines: {node: '>=18'}
     cpu: [x64]
     os: [netbsd]
 
-  '@esbuild/openbsd-x64@0.20.2':
-    resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==}
-    engines: {node: '>=12'}
+  '@esbuild/openbsd-arm64@0.23.1':
+    resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [openbsd]
+
+  '@esbuild/openbsd-x64@0.23.1':
+    resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==}
+    engines: {node: '>=18'}
     cpu: [x64]
     os: [openbsd]
 
-  '@esbuild/sunos-x64@0.20.2':
-    resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==}
-    engines: {node: '>=12'}
+  '@esbuild/sunos-x64@0.23.1':
+    resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==}
+    engines: {node: '>=18'}
     cpu: [x64]
     os: [sunos]
 
-  '@esbuild/win32-arm64@0.20.2':
-    resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==}
-    engines: {node: '>=12'}
+  '@esbuild/win32-arm64@0.23.1':
+    resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==}
+    engines: {node: '>=18'}
     cpu: [arm64]
     os: [win32]
 
-  '@esbuild/win32-ia32@0.20.2':
-    resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==}
-    engines: {node: '>=12'}
+  '@esbuild/win32-ia32@0.23.1':
+    resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==}
+    engines: {node: '>=18'}
     cpu: [ia32]
     os: [win32]
 
-  '@esbuild/win32-x64@0.20.2':
-    resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==}
-    engines: {node: '>=12'}
+  '@esbuild/win32-x64@0.23.1':
+    resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==}
+    engines: {node: '>=18'}
     cpu: [x64]
     os: [win32]
 
@@ -2285,9 +2291,9 @@ packages:
   cheerio-select@2.1.0:
     resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
 
-  cheerio@1.0.0-rc.12:
-    resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==}
-    engines: {node: '>= 6'}
+  cheerio@1.0.0:
+    resolution: {integrity: sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==}
+    engines: {node: '>=18.17'}
 
   chokidar@3.6.0:
     resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
@@ -2366,10 +2372,6 @@ packages:
     resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
     engines: {node: '>= 0.8'}
 
-  commander@11.1.0:
-    resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
-    engines: {node: '>=16'}
-
   commander@12.1.0:
     resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
     engines: {node: '>=18'}
@@ -2758,6 +2760,9 @@ packages:
     resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
     engines: {node: '>= 4'}
 
+  encoding-sniffer@0.2.0:
+    resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==}
+
   encoding@0.1.13:
     resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
 
@@ -2822,9 +2827,9 @@ packages:
     resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
     engines: {node: '>= 0.4'}
 
-  esbuild@0.20.2:
-    resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==}
-    engines: {node: '>=12'}
+  esbuild@0.23.1:
+    resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==}
+    engines: {node: '>=18'}
     hasBin: true
 
   escalade@3.1.2:
@@ -3388,8 +3393,8 @@ packages:
   htmlparser2@6.1.0:
     resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==}
 
-  htmlparser2@8.0.2:
-    resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
+  htmlparser2@9.1.0:
+    resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==}
 
   human-signals@2.1.0:
     resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
@@ -3409,9 +3414,9 @@ packages:
   i18next-http-backend@2.5.2:
     resolution: {integrity: sha512-+K8HbDfrvc1/2X8jpb7RLhI9ZxBDpx3xogYkQwGKlWAUXLSEGXzgdt3EcUjLlBCdMwdQY+K+EUF6oh8oB6rwHw==}
 
-  i18next-parser@8.13.0:
-    resolution: {integrity: sha512-XU7resoeNcpJazh29OncQQUH6HsgCxk06RqBBDAmLHldafxopfCHY1vElyG/o3EY0Sn7XjelAmPTV0SgddJEww==}
-    engines: {node: '>=16.0.0 || >=18.0.0 || >=20.0.0', npm: '>=6', yarn: '>=1'}
+  i18next-parser@9.0.2:
+    resolution: {integrity: sha512-Q1yTZljBp1DcVAQD7LxduEqFRpjIeZc+5VnQ+gU8qG9WvY3U5rqK0IVONRWNtngh3orb197bfy1Sz4wlwcplxg==}
+    engines: {node: '>=18.0.0 || >=20.0.0 || >=22.0.0', npm: '>=6', yarn: '>=1'}
     hasBin: true
 
   i18next-resources-to-backend@1.2.1:
@@ -4371,6 +4376,9 @@ packages:
   parse5-htmlparser2-tree-adapter@7.0.0:
     resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==}
 
+  parse5-parser-stream@7.1.2:
+    resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==}
+
   parse5@7.1.2:
     resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
 
@@ -5698,6 +5706,10 @@ packages:
   undici-types@5.26.5:
     resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
 
+  undici@6.19.8:
+    resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==}
+    engines: {node: '>=18.17'}
+
   unicode-canonical-property-names-ecmascript@2.0.0:
     resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==}
     engines: {node: '>=4'}
@@ -5850,9 +5862,17 @@ packages:
       webpack-cli:
         optional: true
 
+  whatwg-encoding@3.1.1:
+    resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
+    engines: {node: '>=18'}
+
   whatwg-fetch@3.6.20:
     resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==}
 
+  whatwg-mimetype@4.0.0:
+    resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
+    engines: {node: '>=18'}
+
   whatwg-url@5.0.0:
     resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
 
@@ -7230,73 +7250,76 @@ snapshots:
 
   '@emotion/hash@0.8.0': {}
 
-  '@esbuild/aix-ppc64@0.20.2':
+  '@esbuild/aix-ppc64@0.23.1':
+    optional: true
+
+  '@esbuild/android-arm64@0.23.1':
     optional: true
 
-  '@esbuild/android-arm64@0.20.2':
+  '@esbuild/android-arm@0.23.1':
     optional: true
 
-  '@esbuild/android-arm@0.20.2':
+  '@esbuild/android-x64@0.23.1':
     optional: true
 
-  '@esbuild/android-x64@0.20.2':
+  '@esbuild/darwin-arm64@0.23.1':
     optional: true
 
-  '@esbuild/darwin-arm64@0.20.2':
+  '@esbuild/darwin-x64@0.23.1':
     optional: true
 
-  '@esbuild/darwin-x64@0.20.2':
+  '@esbuild/freebsd-arm64@0.23.1':
     optional: true
 
-  '@esbuild/freebsd-arm64@0.20.2':
+  '@esbuild/freebsd-x64@0.23.1':
     optional: true
 
-  '@esbuild/freebsd-x64@0.20.2':
+  '@esbuild/linux-arm64@0.23.1':
     optional: true
 
-  '@esbuild/linux-arm64@0.20.2':
+  '@esbuild/linux-arm@0.23.1':
     optional: true
 
-  '@esbuild/linux-arm@0.20.2':
+  '@esbuild/linux-ia32@0.23.1':
     optional: true
 
-  '@esbuild/linux-ia32@0.20.2':
+  '@esbuild/linux-loong64@0.23.1':
     optional: true
 
-  '@esbuild/linux-loong64@0.20.2':
+  '@esbuild/linux-mips64el@0.23.1':
     optional: true
 
-  '@esbuild/linux-mips64el@0.20.2':
+  '@esbuild/linux-ppc64@0.23.1':
     optional: true
 
-  '@esbuild/linux-ppc64@0.20.2':
+  '@esbuild/linux-riscv64@0.23.1':
     optional: true
 
-  '@esbuild/linux-riscv64@0.20.2':
+  '@esbuild/linux-s390x@0.23.1':
     optional: true
 
-  '@esbuild/linux-s390x@0.20.2':
+  '@esbuild/linux-x64@0.23.1':
     optional: true
 
-  '@esbuild/linux-x64@0.20.2':
+  '@esbuild/netbsd-x64@0.23.1':
     optional: true
 
-  '@esbuild/netbsd-x64@0.20.2':
+  '@esbuild/openbsd-arm64@0.23.1':
     optional: true
 
-  '@esbuild/openbsd-x64@0.20.2':
+  '@esbuild/openbsd-x64@0.23.1':
     optional: true
 
-  '@esbuild/sunos-x64@0.20.2':
+  '@esbuild/sunos-x64@0.23.1':
     optional: true
 
-  '@esbuild/win32-arm64@0.20.2':
+  '@esbuild/win32-arm64@0.23.1':
     optional: true
 
-  '@esbuild/win32-ia32@0.20.2':
+  '@esbuild/win32-ia32@0.23.1':
     optional: true
 
-  '@esbuild/win32-x64@0.20.2':
+  '@esbuild/win32-x64@0.23.1':
     optional: true
 
   '@eslint/eslintrc@0.4.3':
@@ -8540,15 +8563,19 @@ snapshots:
       domhandler: 5.0.3
       domutils: 3.1.0
 
-  cheerio@1.0.0-rc.12:
+  cheerio@1.0.0:
     dependencies:
       cheerio-select: 2.1.0
       dom-serializer: 2.0.0
       domhandler: 5.0.3
       domutils: 3.1.0
-      htmlparser2: 8.0.2
+      encoding-sniffer: 0.2.0
+      htmlparser2: 9.1.0
       parse5: 7.1.2
       parse5-htmlparser2-tree-adapter: 7.0.0
+      parse5-parser-stream: 7.1.2
+      undici: 6.19.8
+      whatwg-mimetype: 4.0.0
 
   chokidar@3.6.0:
     dependencies:
@@ -8630,8 +8657,6 @@ snapshots:
     dependencies:
       delayed-stream: 1.0.0
 
-  commander@11.1.0: {}
-
   commander@12.1.0: {}
 
   commander@2.20.3: {}
@@ -8870,7 +8895,8 @@ snapshots:
       es-errors: 1.3.0
       is-data-view: 1.0.1
 
-  de-indent@1.0.2: {}
+  de-indent@1.0.2:
+    optional: true
 
   debug@2.6.9:
     dependencies:
@@ -9032,6 +9058,11 @@ snapshots:
 
   emojis-list@3.0.0: {}
 
+  encoding-sniffer@0.2.0:
+    dependencies:
+      iconv-lite: 0.6.3
+      whatwg-encoding: 3.1.1
+
   encoding@0.1.13:
     dependencies:
       iconv-lite: 0.6.3
@@ -9164,31 +9195,32 @@ snapshots:
       is-date-object: 1.0.5
       is-symbol: 1.0.4
 
-  esbuild@0.20.2:
+  esbuild@0.23.1:
     optionalDependencies:
-      '@esbuild/aix-ppc64': 0.20.2
-      '@esbuild/android-arm': 0.20.2
-      '@esbuild/android-arm64': 0.20.2
-      '@esbuild/android-x64': 0.20.2
-      '@esbuild/darwin-arm64': 0.20.2
-      '@esbuild/darwin-x64': 0.20.2
-      '@esbuild/freebsd-arm64': 0.20.2
-      '@esbuild/freebsd-x64': 0.20.2
-      '@esbuild/linux-arm': 0.20.2
-      '@esbuild/linux-arm64': 0.20.2
-      '@esbuild/linux-ia32': 0.20.2
-      '@esbuild/linux-loong64': 0.20.2
-      '@esbuild/linux-mips64el': 0.20.2
-      '@esbuild/linux-ppc64': 0.20.2
-      '@esbuild/linux-riscv64': 0.20.2
-      '@esbuild/linux-s390x': 0.20.2
-      '@esbuild/linux-x64': 0.20.2
-      '@esbuild/netbsd-x64': 0.20.2
-      '@esbuild/openbsd-x64': 0.20.2
-      '@esbuild/sunos-x64': 0.20.2
-      '@esbuild/win32-arm64': 0.20.2
-      '@esbuild/win32-ia32': 0.20.2
-      '@esbuild/win32-x64': 0.20.2
+      '@esbuild/aix-ppc64': 0.23.1
+      '@esbuild/android-arm': 0.23.1
+      '@esbuild/android-arm64': 0.23.1
+      '@esbuild/android-x64': 0.23.1
+      '@esbuild/darwin-arm64': 0.23.1
+      '@esbuild/darwin-x64': 0.23.1
+      '@esbuild/freebsd-arm64': 0.23.1
+      '@esbuild/freebsd-x64': 0.23.1
+      '@esbuild/linux-arm': 0.23.1
+      '@esbuild/linux-arm64': 0.23.1
+      '@esbuild/linux-ia32': 0.23.1
+      '@esbuild/linux-loong64': 0.23.1
+      '@esbuild/linux-mips64el': 0.23.1
+      '@esbuild/linux-ppc64': 0.23.1
+      '@esbuild/linux-riscv64': 0.23.1
+      '@esbuild/linux-s390x': 0.23.1
+      '@esbuild/linux-x64': 0.23.1
+      '@esbuild/netbsd-x64': 0.23.1
+      '@esbuild/openbsd-arm64': 0.23.1
+      '@esbuild/openbsd-x64': 0.23.1
+      '@esbuild/sunos-x64': 0.23.1
+      '@esbuild/win32-arm64': 0.23.1
+      '@esbuild/win32-ia32': 0.23.1
+      '@esbuild/win32-x64': 0.23.1
 
   escalade@3.1.2: {}
 
@@ -9882,7 +9914,7 @@ snapshots:
       domutils: 2.8.0
       entities: 2.2.0
 
-  htmlparser2@8.0.2:
+  htmlparser2@9.1.0:
     dependencies:
       domelementtype: 2.3.0
       domhandler: 5.0.3
@@ -9913,15 +9945,15 @@ snapshots:
     transitivePeerDependencies:
       - encoding
 
-  i18next-parser@8.13.0:
+  i18next-parser@9.0.2:
     dependencies:
       '@babel/runtime': 7.24.8
       broccoli-plugin: 4.0.7
-      cheerio: 1.0.0-rc.12
+      cheerio: 1.0.0
       colors: 1.4.0
-      commander: 11.1.0
+      commander: 12.1.0
       eol: 0.9.1
-      esbuild: 0.20.2
+      esbuild: 0.23.1
       fs-extra: 11.2.0
       gulp-sort: 2.0.0
       i18next: 23.13.0
@@ -9932,7 +9964,6 @@ snapshots:
       typescript: 5.5.3
       vinyl: 3.0.0
       vinyl-fs: 4.0.0
-      vue-template-compiler: 2.7.16
     transitivePeerDependencies:
       - supports-color
 
@@ -11053,6 +11084,10 @@ snapshots:
       domhandler: 5.0.3
       parse5: 7.1.2
 
+  parse5-parser-stream@7.1.2:
+    dependencies:
+      parse5: 7.1.2
+
   parse5@7.1.2:
     dependencies:
       entities: 4.5.0
@@ -12515,6 +12550,8 @@ snapshots:
 
   undici-types@5.26.5: {}
 
+  undici@6.19.8: {}
+
   unicode-canonical-property-names-ecmascript@2.0.0: {}
 
   unicode-match-property-ecmascript@2.0.0:
@@ -12627,6 +12664,7 @@ snapshots:
     dependencies:
       de-indent: 1.0.2
       he: 1.2.0
+    optional: true
 
   walk-sync@2.2.0:
     dependencies:
@@ -12698,8 +12736,14 @@ snapshots:
       - esbuild
       - uglify-js
 
+  whatwg-encoding@3.1.1:
+    dependencies:
+      iconv-lite: 0.6.3
+
   whatwg-fetch@3.6.20: {}
 
+  whatwg-mimetype@4.0.0: {}
+
   whatwg-url@5.0.0:
     dependencies:
       tr46: 0.0.3
diff --git a/vendor/github.com/libregraph/lico/CHANGELOG.md b/vendor/github.com/libregraph/lico/CHANGELOG.md
index 69c670360c7..4e998708aec 100644
--- a/vendor/github.com/libregraph/lico/CHANGELOG.md
+++ b/vendor/github.com/libregraph/lico/CHANGELOG.md
@@ -4,6 +4,30 @@
 
 
 
+## v0.64.0 (2024-09-18)
+
+- Implement refresh and revoke for lg identifier backend session
+- Pass real src ip and user agent to lg identifier backend
+- Fix variable shadowing making error checks ineffective
+
+
+## v0.63.0 (2024-09-10)
+
+- Bump semver from 5.7.1 to 5.7.2 in /identifier
+- Ignore js license ranger border check warnings
+- Fix js license ranger for new source-map-explorer
+- Bump source-map-explorer to 2.5.3 in /identifier
+- Update linter CI version
+- Fix access token sid claim when provided via lg backend
+- Bump google.golang.org/protobuf from 1.30.0 to 1.33.0
+- Bump github.com/rs/cors from 1.10.1 to 1.11.1
+- Add password visibility icon in login dialog
+- Bump github.com/spf13/cobra from 1.7.0 to 1.8.1
+- Remove :443 from Host header for secure referrer/origin check
+- Allow authorize requests wihout openid scope
+- Bump github.com/gorilla/schema from 1.2.0 to 1.4.1
+
+
 ## v0.62.0 (2024-05-08)
 
 - Update golangci-lint config
diff --git a/vendor/github.com/libregraph/lico/Caddyfile.dev b/vendor/github.com/libregraph/lico/Caddyfile.dev
index 38ff2b35e89..3e0d453ddfe 100644
--- a/vendor/github.com/libregraph/lico/Caddyfile.dev
+++ b/vendor/github.com/libregraph/lico/Caddyfile.dev
@@ -12,13 +12,27 @@
 	tls self_signed
 
 	# konnect oidc
-	proxy /.well-known/openid-configuration 127.0.0.1:8777
-	proxy /konnect/v1/jwks.json 127.0.0.1:8777
-	proxy /konnect/v1/token 127.0.0.1:8777
-	proxy /konnect/v1/userinfo 127.0.0.1:8777
-	proxy /konnect/v1/static 127.0.0.1:8777
-	proxy /konnect/v1/session 127.0.0.1:8777
-	proxy /konnect/v1/register 127.0.0.1:8777
+	proxy /.well-known/openid-configuration 127.0.0.1:8777 {
+		transparent
+	}
+	proxy /konnect/v1/jwks.json 127.0.0.1:8777 {
+		transparent
+	}
+	proxy /konnect/v1/token 127.0.0.1:8777 {
+		transparent
+	}
+	proxy /konnect/v1/userinfo 127.0.0.1:8777 {
+		transparent
+	}
+	proxy /konnect/v1/static 127.0.0.1:8777 {
+		transparent
+	}
+	proxy /konnect/v1/session 127.0.0.1:8777 {
+		transparent
+	}
+	proxy /konnect/v1/register 127.0.0.1:8777 {
+		transparent
+	}
 
 	# konnect identifier development via webpack-dev-server
 	proxy /signin/v1/ 127.0.0.1:3001 {
@@ -46,6 +60,7 @@
 	#proxy /provider/simple/konnect/v1/authorize 127.0.0.1:8777 {
 	#	without /provider/simple
 	#	header_upstream X-Forwarded-Prefix /provider/simple
+	#   transparent
 	#}
 
 	# konnect cookieserver, start with python3 ./examples/cookieserver.py 8088
diff --git a/vendor/github.com/libregraph/lico/Caddyfile.example b/vendor/github.com/libregraph/lico/Caddyfile.example
index 734d8f9cf04..9dc807a7059 100644
--- a/vendor/github.com/libregraph/lico/Caddyfile.example
+++ b/vendor/github.com/libregraph/lico/Caddyfile.example
@@ -9,13 +9,27 @@
 	tls self_signed
 
 	# konnect oidc
-	proxy /.well-known/openid-configuration 127.0.0.1:8777
-	proxy /konnect/v1/jwks.json 127.0.0.1:8777
-	proxy /konnect/v1/token 127.0.0.1:8777
-	proxy /konnect/v1/userinfo 127.0.0.1:8777
-	proxy /konnect/v1/static 127.0.0.1:8777
-	proxy /konnect/v1/session 127.0.0.1:8777
-	proxy /konnect/v1/register 127.0.0.1:8777
+	proxy /.well-known/openid-configuration 127.0.0.1:8777 {
+		transparent
+	}
+	proxy /konnect/v1/jwks.json 127.0.0.1:8777 {
+		transparent
+	}
+	proxy /konnect/v1/token 127.0.0.1:8777 {
+		transparent
+	}
+	proxy /konnect/v1/userinfo 127.0.0.1:8777 {
+		transparent
+	}
+	proxy /konnect/v1/static 127.0.0.1:8777 {
+		transparent
+	}
+	proxy /konnect/v1/session 127.0.0.1:8777 {
+		transparent
+	}
+	proxy /konnect/v1/register 127.0.0.1:8777 {
+		transparent
+	}
 
 	# konnect identifier login area
 	proxy /signin/ 127.0.0.1:8777 {
diff --git a/vendor/github.com/libregraph/lico/context.go b/vendor/github.com/libregraph/lico/context.go
index c1906ac3aea..e755c1c5075 100644
--- a/vendor/github.com/libregraph/lico/context.go
+++ b/vendor/github.com/libregraph/lico/context.go
@@ -19,6 +19,7 @@ package lico
 
 import (
 	"context"
+	"net/http"
 
 	"github.com/golang-jwt/jwt/v4"
 )
@@ -30,7 +31,10 @@ type key int
 // claimsKey is the key for claims in contexts. It is
 // unexported; clients use konnect.NewClaimsContext and
 // connect.FromClaimsContext instead of using this key directly.
-var claimsKey key
+const (
+	claimsKey key = iota
+	requestKey
+)
 
 // NewClaimsContext returns a new Context that carries value auth.
 func NewClaimsContext(ctx context.Context, claims jwt.Claims) context.Context {
@@ -42,3 +46,14 @@ func FromClaimsContext(ctx context.Context) (jwt.Claims, bool) {
 	claims, ok := ctx.Value(claimsKey).(jwt.Claims)
 	return claims, ok
 }
+
+// NewRequestContext returns a new Context that carries a request object.
+func NewRequestContext(ctx context.Context, req *http.Request) context.Context {
+	return context.WithValue(ctx, requestKey, req)
+}
+
+// FromRequestContext returns the Request object stored in ctx, if any.
+func FromRequestContext(ctx context.Context) (*http.Request, bool) {
+	req, ok := ctx.Value(requestKey).(*http.Request)
+	return req, ok
+}
diff --git a/vendor/github.com/libregraph/lico/identifier/backends/libregraph/libregraph.go b/vendor/github.com/libregraph/lico/identifier/backends/libregraph/libregraph.go
index 4ec90c39516..ad99909e4c6 100644
--- a/vendor/github.com/libregraph/lico/identifier/backends/libregraph/libregraph.go
+++ b/vendor/github.com/libregraph/lico/identifier/backends/libregraph/libregraph.go
@@ -54,8 +54,9 @@ const (
 )
 
 const (
-	apiPathMe    = "/api/v1/me"
-	apiPathUsers = "/api/v1/users"
+	apiPathMe                  = "/api/v1/me"
+	apiPathUsers               = "/api/v1/users"
+	apiPathRevokeSignInSession = "/api/v1/me/revokeSignInSession"
 )
 
 var libreGraphSpportedScopes = []string{
@@ -66,6 +67,8 @@ var libreGraphSpportedScopes = []string{
 }
 
 type LibreGraphIdentifierBackend struct {
+	config *config.Config
+
 	supportedScopes []string
 
 	logger    logrus.FieldLogger
@@ -245,7 +248,7 @@ func (u *libreGraphUser) setRequiredScopes(selectedScope string, scopeMap *order
 }
 
 func (u *libreGraphUser) sessionID() string {
-	if accessTokenClaims, ok := u.identityClaims[""].(map[string]interface{}); ok {
+	if accessTokenClaims, ok := u.identityClaims[konnect.InternalExtraAccessTokenClaimsClaim].(map[string]interface{}); ok {
 		if sessionID, withSessionID := accessTokenClaims[oidc.SessionIDClaim].(string); withSessionID {
 			if sessionID != "" {
 				return sessionID
@@ -297,6 +300,8 @@ func NewLibreGraphIdentifierBackend(
 	transport.IdleConnTimeout = 30 * time.Second
 
 	b := &LibreGraphIdentifierBackend{
+		config: c,
+
 		supportedScopes: supportedScopes,
 
 		logger:    c.Logger,
@@ -348,16 +353,27 @@ func (b *LibreGraphIdentifierBackend) Logon(ctx context.Context, audience, usern
 	}
 	req.SetBasicAuth(username, password)
 
+	if record == nil {
+		record, _ = identifier.RecordFromRequestContext(ctx, b.config)
+	}
 	if record != nil {
 		// Inject HTTP headers.
-		if record.HelloRequest.Flow != "" {
-			req.Header.Set("X-Flow", record.HelloRequest.Flow)
+		if record.HelloRequest != nil {
+			if record.HelloRequest.Flow != "" {
+				req.Header.Set("X-Flow", record.HelloRequest.Flow)
+			}
+			if record.HelloRequest.RawScope != "" {
+				req.Header.Set("X-Scope", record.HelloRequest.RawScope)
+			}
+			if record.HelloRequest.RawPrompt != "" {
+				req.Header.Set("X-Prompt", record.HelloRequest.RawPrompt)
+			}
 		}
-		if record.HelloRequest.RawScope != "" {
-			req.Header.Set("X-Scope", record.HelloRequest.RawScope)
+		if record.RealIP != "" {
+			req.Header.Set("X-User-Real-IP", record.RealIP)
 		}
-		if record.HelloRequest.RawPrompt != "" {
-			req.Header.Set("X-Prompt", record.HelloRequest.RawPrompt)
+		if record.UserAgent != "" {
+			req.Header.Set("X-User-Real-User-Agent", record.UserAgent)
 		}
 	}
 	req.Header.Set("User-Agent", utils.DefaultHTTPUserAgent)
@@ -407,7 +423,7 @@ func (b *LibreGraphIdentifierBackend) Logon(ctx context.Context, audience, usern
 
 	// Put the user into the record (if any).
 	if record != nil {
-		record.UserFromBackend = user
+		record.BackendUser = user
 	}
 
 	return true, &userID, &sessionID, user, nil
@@ -419,8 +435,8 @@ func (b *LibreGraphIdentifierBackend) Logon(ctx context.Context, audience, usern
 func (b *LibreGraphIdentifierBackend) GetUser(ctx context.Context, entryID string, sessionRef *string, requestedScopes map[string]bool) (backends.UserFromBackend, error) {
 	record, _ := identifier.FromRecordContext(ctx)
 	if record != nil {
-		if record.UserFromBackend != nil {
-			if user, ok := record.UserFromBackend.(*libreGraphUser); ok {
+		if record.BackendUser != nil {
+			if user, ok := record.BackendUser.(*libreGraphUser); ok {
 				// Fastpath, if logon previously injected the user.
 				if user.ID == entryID {
 					return user, nil
@@ -455,6 +471,23 @@ func (b *LibreGraphIdentifierBackend) GetUser(ctx context.Context, entryID strin
 			req.Header.Set("X-SessionID", sessionID)
 		}
 	}
+
+	if record == nil {
+		record, _ = identifier.RecordFromRequestContext(ctx, b.config)
+	}
+	if record != nil {
+		if record.IdentifiedUser != nil {
+			if ok, ts := record.IdentifiedUser.LoggedOn(); ok {
+				req.Header.Set("X-User-Logon-At", ts.UTC().Format(http.TimeFormat))
+			}
+		}
+		if record.RealIP != "" {
+			req.Header.Set("X-User-Real-IP", record.RealIP)
+		}
+		if record.UserAgent != "" {
+			req.Header.Set("X-User-Real-User-Agent", record.UserAgent)
+		}
+	}
 	req.Header.Set("User-Agent", utils.DefaultHTTPUserAgent)
 
 	// Inject select parameter.
@@ -489,7 +522,7 @@ func (b *LibreGraphIdentifierBackend) GetUser(ctx context.Context, entryID strin
 	return user, nil
 }
 
-// ResolveUserByUsername implements the Beckend interface, providing lookup for
+// ResolveUserByUsername implements the Backend interface, providing lookup for
 // user by providing the username. Requests are bound to the provided context.
 func (b *LibreGraphIdentifierBackend) ResolveUserByUsername(ctx context.Context, username string) (backends.UserFromBackend, error) {
 	// Libregraph backend accept both user name and ID lookups, so this is
@@ -499,11 +532,72 @@ func (b *LibreGraphIdentifierBackend) ResolveUserByUsername(ctx context.Context,
 
 // RefreshSession implements the Backend interface.
 func (b *LibreGraphIdentifierBackend) RefreshSession(ctx context.Context, userID string, sessionRef *string, claims map[string]interface{}) error {
+	user, err := b.GetUser(ctx, userID, sessionRef, nil)
+	if err != nil {
+		return err
+	}
+	if user == nil {
+		return fmt.Errorf("refresh session did not yield a user")
+	}
 	return nil
 }
 
-// DestroySession implements the Backend interface providing destroy to KC session.
+// DestroySession implements the Backend interface providing explicit revoke
+// of the backend session.
 func (b *LibreGraphIdentifierBackend) DestroySession(ctx context.Context, sessionRef *string) error {
+	var requestedScopes map[string]bool
+	record, _ := identifier.FromRecordContext(ctx)
+	if record != nil {
+		if record.HelloRequest != nil {
+			requestedScopes = record.HelloRequest.Scopes
+		}
+	}
+
+	_, revokeSessionURL := b.getRevokeSigninSessionURL(requestedScopes)
+	req, err := http.NewRequestWithContext(ctx, http.MethodPost, revokeSessionURL, http.NoBody)
+	if err != nil {
+		return fmt.Errorf("libregraph identifier backend destroy session request error: %w", err)
+	}
+
+	if sessionRef != nil {
+		sessionID := *sessionRef
+		if !strings.HasPrefix(sessionID, libreGraphIdentifierBackendName+":") {
+			// Only send the session ID if it is not a ref generated by lico.
+			req.Header.Set("X-SessionID", sessionID)
+		}
+	}
+
+	if record == nil {
+		record, _ = identifier.RecordFromRequestContext(ctx, b.config)
+	}
+	if record != nil {
+		// Inject HTTP headers.
+		if record.RealIP != "" {
+			req.Header.Set("X-User-Real-IP", record.RealIP)
+		}
+		if record.UserAgent != "" {
+			req.Header.Set("X-User-Real-User-Agent", record.UserAgent)
+		}
+	}
+	req.Header.Set("User-Agent", utils.DefaultHTTPUserAgent)
+
+	response, err := b.client.Do(req)
+	if err != nil {
+		return fmt.Errorf("libregraph identifier backend destroy session request failed: %w", err)
+	}
+	defer response.Body.Close()
+
+	switch response.StatusCode {
+	case http.StatusOK:
+		// breaks
+	case http.StatusNotFound:
+		return nil
+	case http.StatusUnauthorized:
+		return nil
+	default:
+		return fmt.Errorf("libregraph identifier backend logon request unexpected response status: %d", response.StatusCode)
+	}
+
 	return nil
 }
 
@@ -558,3 +652,9 @@ func (b *LibreGraphIdentifierBackend) getUserURL(requestedScopes map[string]bool
 
 	return scope, baseURL + apiPathUsers
 }
+
+func (b *LibreGraphIdentifierBackend) getRevokeSigninSessionURL(requestedScopes map[string]bool) (string, string) {
+	scope, baseURL := b.getBaseURL(requestedScopes)
+
+	return scope, baseURL + apiPathRevokeSignInSession
+}
diff --git a/vendor/github.com/libregraph/lico/identifier/context.go b/vendor/github.com/libregraph/lico/identifier/context.go
index 0fca3ed24d9..0bcc68f7a78 100644
--- a/vendor/github.com/libregraph/lico/identifier/context.go
+++ b/vendor/github.com/libregraph/lico/identifier/context.go
@@ -19,26 +19,56 @@ package identifier
 
 import (
 	"context"
+	"net"
+	"net/http"
 
+	konnect "github.com/libregraph/lico"
+	"github.com/libregraph/lico/config"
 	"github.com/libregraph/lico/identifier/backends"
+	"github.com/libregraph/lico/utils"
 )
 
 // Record is the struct which the identifier puts into the context.
 type Record struct {
-	HelloRequest    *HelloRequest
-	UserFromBackend backends.UserFromBackend
+	HelloRequest *HelloRequest
+	RealIP       string
+	UserAgent    string
+
+	BackendUser    backends.UserFromBackend
+	IdentifiedUser *IdentifiedUser
+}
+
+func NewRecord(req *http.Request, c *config.Config) *Record {
+	record := &Record{
+		UserAgent: req.UserAgent(),
+	}
+
+	trusted, _ := utils.IsRequestFromTrustedSource(req, c.TrustedProxyIPs, c.TrustedProxyNets)
+
+	if trusted {
+		record.RealIP = req.Header.Get("X-Real-Ip")
+	}
+	if record.RealIP == "" {
+		if ip, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
+			record.RealIP = ip
+		}
+	}
+
+	return record
 }
 
 // key is an unexported type for keys defined in this package.
 // This prevents collisions with keys defined in other packages.
 type key int
 
-// recordKey is the key for identifier.Record in Contexts. It is
-// unexported; clients use identifier.NewContext and identifier.FromContext
-// instead of using this key directly.
-var recordKey key
+// Keys for context data.
+// Unexported; Clients use identifier.New{?}Context and
+// identifier.From{?}Context functions instead of using these keys directly.
+const (
+	recordKey key = iota
+)
 
-// NewRecordContext returns a new Context that carries value HelloRequest.
+// NewRecordContext returns a new Context that carries the Record.
 func NewRecordContext(ctx context.Context, record *Record) context.Context {
 	return context.WithValue(ctx, recordKey, record)
 }
@@ -48,3 +78,12 @@ func FromRecordContext(ctx context.Context) (*Record, bool) {
 	record, ok := ctx.Value(recordKey).(*Record)
 	return record, ok
 }
+
+// RecordFromRequestContext returns a new Record value based on the request
+// stored in ctx, if any.
+func RecordFromRequestContext(ctx context.Context, c *config.Config) (*Record, bool) {
+	if req, ok := konnect.FromRequestContext(ctx); ok {
+		return NewRecord(req, c), true
+	}
+	return nil, false
+}
diff --git a/vendor/github.com/libregraph/lico/identifier/handlers.go b/vendor/github.com/libregraph/lico/identifier/handlers.go
index a326d8e36eb..d637ab2b261 100644
--- a/vendor/github.com/libregraph/lico/identifier/handlers.go
+++ b/vendor/github.com/libregraph/lico/identifier/handlers.go
@@ -21,6 +21,7 @@ import (
 	"encoding/json"
 	"encoding/xml"
 	"fmt"
+	"net"
 	"net/http"
 	"net/url"
 	"strings"
@@ -28,6 +29,7 @@ import (
 
 	"github.com/sirupsen/logrus"
 
+	konnect "github.com/libregraph/lico"
 	"github.com/libregraph/lico/identity/authorities"
 	"github.com/libregraph/lico/utils"
 )
@@ -57,6 +59,14 @@ func (i *Identifier) secureHandler(handler http.Handler) http.Handler {
 		// NOTE: this does not protect from DNS rebinding. Protection for that
 		// should be added at the frontend proxy.
 		requiredHost := req.Host
+		if host, port, splitErr := net.SplitHostPort(requiredHost); splitErr == nil {
+			if port == "443" {
+				// Ignore the port 443 as it is the default port and it is
+				// usually not part of any of the urls. It might be in the
+				// request for HTTP/3 requests.
+				requiredHost = host
+			}
+		}
 
 		// This follows https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
 		for {
@@ -172,7 +182,7 @@ func (i *Identifier) handleLogon(rw http.ResponseWriter, req *http.Request) {
 
 	addNoCacheResponseHeaders(rw.Header())
 
-	record := &Record{}
+	record := NewRecord(req, i.Config.Config)
 
 	if r.Hello != nil {
 		err = r.Hello.parse()
@@ -184,7 +194,7 @@ func (i *Identifier) handleLogon(rw http.ResponseWriter, req *http.Request) {
 		record.HelloRequest = r.Hello
 	}
 
-	req = req.WithContext(NewRecordContext(req.Context(), record))
+	req = req.WithContext(NewRecordContext(konnect.NewRequestContext(req.Context(), req), record))
 
 	// Params is an array like this [$username, $password, $mode], defining a
 	// extensible way to extend login modes over time. The minimal length of
diff --git a/vendor/github.com/libregraph/lico/identifier/package.json b/vendor/github.com/libregraph/lico/identifier/package.json
index 8ad257719ba..8f72418e381 100644
--- a/vendor/github.com/libregraph/lico/identifier/package.json
+++ b/vendor/github.com/libregraph/lico/identifier/package.json
@@ -33,7 +33,7 @@
     "serve": "vite preview",
     "test": "vitest",
     "lint": "eslint --max-warnings=0 src/**/*.{ts,tsx,js,jsx}",
-    "licenses": "NODE_PATH=./node_modules node ../scripts/js-license-ranger.js",
+    "licenses": "node ../scripts/js-license-ranger.mjs",
     "analyze": "source-map-explorer 'build/static/assets/*.js'"
   },
   "devDependencies": {
@@ -59,7 +59,7 @@
     "i18next-parser": "^5.4.0",
     "if-node-version": "^1.1.1",
     "jsdom": "^22.1.0",
-    "source-map-explorer": "^1.8.0",
+    "source-map-explorer": "^2.5.3",
     "typescript": "^5.2.2",
     "vite": "^4.5.2",
     "vite-plugin-checker": "^0.6.2",
diff --git a/vendor/github.com/libregraph/lico/identity/context.go b/vendor/github.com/libregraph/lico/identity/context.go
index a3dc2b10702..13b6b0e938e 100644
--- a/vendor/github.com/libregraph/lico/identity/context.go
+++ b/vendor/github.com/libregraph/lico/identity/context.go
@@ -28,7 +28,9 @@ type key int
 // authRecordKey is the key for identity.AuthRecord in Contexts. It is
 // unexported; clients use identity.NewContext and identity.FromContext
 // instead of using this key directly.
-var authRecordKey key
+const (
+	authRecordKey key = iota
+)
 
 // NewContext returns a new Context that carries value auth.
 func NewContext(ctx context.Context, auth AuthRecord) context.Context {
diff --git a/vendor/github.com/libregraph/lico/identity/managers/identifier.go b/vendor/github.com/libregraph/lico/identity/managers/identifier.go
index e01e53de5fd..c832b38c632 100644
--- a/vendor/github.com/libregraph/lico/identity/managers/identifier.go
+++ b/vendor/github.com/libregraph/lico/identity/managers/identifier.go
@@ -200,6 +200,10 @@ func (im *IdentifierIdentityManager) Authenticate(ctx context.Context, rw http.R
 		}
 
 		if user != nil {
+			record := identifier.NewRecord(req, im.identifier.Config.Config)
+			record.IdentifiedUser = user.IdentifiedUser
+			ctx = identifier.NewRecordContext(ctx, record)
+
 			// Inject required scopes into request.
 			for scope, ok := range user.RequiredScopes() {
 				ar.Scopes[scope] = ok
diff --git a/vendor/github.com/libregraph/lico/oidc/payload/authentication.go b/vendor/github.com/libregraph/lico/oidc/payload/authentication.go
index 6348406a778..2080b5fe8e1 100644
--- a/vendor/github.com/libregraph/lico/oidc/payload/authentication.go
+++ b/vendor/github.com/libregraph/lico/oidc/payload/authentication.go
@@ -265,28 +265,36 @@ func (ar *AuthenticationRequest) ApplyRequestObject(roc *RequestObjectClaims, me
 
 // Validate validates the request data of the accociated authentication request.
 func (ar *AuthenticationRequest) Validate(keyFunc jwt.Keyfunc) error {
-	if _, ok := ar.Scopes[oidc.ScopeOpenID]; !ok {
-		return ar.NewBadRequest(oidc.ErrorCodeOAuth2InvalidRequest, "missing openid scope in request")
-	}
-
 	switch ar.RawResponseType {
 	case oidc.ResponseTypeCode:
 		// Code flow.
 		// breaks
 	case oidc.ResponseTypeCodeIDToken:
 		// Hybgrid flow.
+		if _, ok := ar.Scopes[oidc.ScopeOpenID]; !ok {
+			return ar.NewBadRequest(oidc.ErrorCodeOAuth2InvalidRequest, "missing openid scope in request")
+		}
 		// breaks
 	case oidc.ResponseTypeCodeToken:
 		// Hybgrid flow.
 		// breaks
 	case oidc.ResponseTypeCodeIDTokenToken:
 		// Hybgrid flow.
+		if _, ok := ar.Scopes[oidc.ScopeOpenID]; !ok {
+			return ar.NewBadRequest(oidc.ErrorCodeOAuth2InvalidRequest, "missing openid scope in request")
+		}
 		// breaks
 	case oidc.ResponseTypeIDToken:
 		// Implicit flow.
+		if _, ok := ar.Scopes[oidc.ScopeOpenID]; !ok {
+			return ar.NewBadRequest(oidc.ErrorCodeOAuth2InvalidRequest, "missing openid scope in request")
+		}
 		fallthrough
 	case oidc.ResponseTypeIDTokenToken:
 		// Implicit flow with access token.
+		if _, ok := ar.Scopes[oidc.ScopeOpenID]; !ok {
+			return ar.NewBadRequest(oidc.ErrorCodeOAuth2InvalidRequest, "missing openid scope in request")
+		}
 		if ar.Nonce == "" {
 			return ar.NewError(oidc.ErrorCodeOAuth2InvalidRequest, "nonce is required for implicit flow")
 		}
diff --git a/vendor/github.com/libregraph/lico/oidc/provider/handlers.go b/vendor/github.com/libregraph/lico/oidc/provider/handlers.go
index 3cc4621314b..78e046b3fd5 100644
--- a/vendor/github.com/libregraph/lico/oidc/provider/handlers.go
+++ b/vendor/github.com/libregraph/lico/oidc/provider/handlers.go
@@ -93,6 +93,8 @@ func (p *Provider) AuthorizeHandler(rw http.ResponseWriter, req *http.Request) {
 
 	addResponseHeaders(rw.Header())
 
+	ctx := konnect.NewRequestContext(req.Context(), req)
+
 	// OpenID Connect 1.0 authentication request validation.
 	// http://openid.net/specs/openid-connect-core-1_0.html#ImplicitValidation
 	err = req.ParseForm()
@@ -106,7 +108,7 @@ func (p *Provider) AuthorizeHandler(rw http.ResponseWriter, req *http.Request) {
 		if claims, ok := token.Claims.(*payload.RequestObjectClaims); ok {
 			// Validate signed request tokens according to spec defined at
 			// https://openid.net/specs/openid-connect-core-1_0.html#SignedRequestObject
-			registration, _ := p.clients.Get(req.Context(), claims.ClientID)
+			registration, _ := p.clients.Get(ctx, claims.ClientID)
 			if registration != nil {
 				if registration.RawRequestObjectSigningAlg != "" {
 					if token.Method.Alg() != registration.RawRequestObjectSigningAlg {
@@ -156,7 +158,7 @@ func (p *Provider) AuthorizeHandler(rw http.ResponseWriter, req *http.Request) {
 	}
 
 	// Inject implicit scopes set by client registration.
-	if registration, _ := p.clients.Get(req.Context(), ar.ClientID); registration != nil {
+	if registration, _ := p.clients.Get(ctx, ar.ClientID); registration != nil {
 		err = registration.ApplyImplicitScopes(ar.Scopes)
 		if err != nil {
 			p.logger.WithError(err).Debugln("failed to apply implicit scopes")
@@ -171,7 +173,7 @@ func (p *Provider) AuthorizeHandler(rw http.ResponseWriter, req *http.Request) {
 
 	// Authorization Server Authenticates End-User
 	// http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthenticates
-	auth, err = p.identityManager.Authenticate(req.Context(), rw, req, ar, p.guestManager)
+	auth, err = p.identityManager.Authenticate(ctx, rw, req, ar, p.guestManager)
 	if err != nil {
 		goto done
 	}
@@ -190,7 +192,7 @@ func (p *Provider) AuthorizeHandler(rw http.ResponseWriter, req *http.Request) {
 
 	// Authorization Server Obtains End-User Consent/Authorization
 	// http://openid.net/specs/openid-connect-core-1_0.html#ImplicitConsent
-	auth, err = auth.Manager().Authorize(req.Context(), rw, req, ar, auth)
+	auth, err = auth.Manager().Authorize(ctx, rw, req, ar, auth)
 	if err != nil {
 		goto done
 	}
@@ -213,7 +215,7 @@ func (p *Provider) AuthorizeResponse(rw http.ResponseWriter, req *http.Request,
 		goto done
 	}
 
-	ctx = identity.NewContext(req.Context(), auth)
+	ctx = identity.NewContext(konnect.NewRequestContext(req.Context(), req), auth)
 
 	// Create session.
 	session, err = p.updateOrCreateSession(rw, req, ar, auth)
@@ -336,6 +338,8 @@ func (p *Provider) TokenHandler(rw http.ResponseWriter, req *http.Request) {
 	rw.Header().Set("Cache-Control", "no-store")
 	rw.Header().Set("Pragma", "no-cache")
 
+	ctx := konnect.NewRequestContext(req.Context(), req)
+
 	// Validate request method
 	switch req.Method {
 	case http.MethodPost:
@@ -367,7 +371,7 @@ func (p *Provider) TokenHandler(rw http.ResponseWriter, req *http.Request) {
 	}
 
 	// Additional validations according to https://tools.ietf.org/html/rfc6749#section-4.1.3
-	clientDetails, err = p.clients.Lookup(req.Context(), tr.ClientID, tr.ClientSecret, tr.RedirectURI, "", false)
+	clientDetails, err = p.clients.Lookup(ctx, tr.ClientID, tr.ClientSecret, tr.RedirectURI, "", false)
 	if err != nil {
 		err = konnectoidc.NewOAuth2Error(oidc.ErrorCodeOAuth2AccessDenied, err.Error())
 		goto done
@@ -410,8 +414,8 @@ func (p *Provider) TokenHandler(rw http.ResponseWriter, req *http.Request) {
 			}
 		}
 
-		if _, ok := identity.FromContext(req.Context()); !ok {
-			req = req.WithContext(identity.NewContext(req.Context(), auth))
+		if _, ok := identity.FromContext(ctx); !ok {
+			ctx = identity.NewContext(ctx, auth)
 		}
 
 	case oidc.GrantTypeRefreshToken:
@@ -437,10 +441,11 @@ func (p *Provider) TokenHandler(rw http.ResponseWriter, req *http.Request) {
 			goto done
 		}
 
-		ctx := konnect.NewClaimsContext(req.Context(), claims)
+		ctx = konnect.NewClaimsContext(ctx, claims)
 
-		currentIdentityManager, err := p.getIdentityManagerFromClaims(claims.IdentityProvider, claims.IdentityClaims)
-		if err != nil {
+		currentIdentityManager, claimsErr := p.getIdentityManagerFromClaims(claims.IdentityProvider, claims.IdentityClaims)
+		if claimsErr != nil {
+			err = claimsErr
 			goto done
 		}
 
@@ -499,16 +504,16 @@ func (p *Provider) TokenHandler(rw http.ResponseWriter, req *http.Request) {
 	}
 
 	// Create access token.
-	accessTokenString, err = p.makeAccessToken(req.Context(), ar.ClientID, auth, signinMethod)
+	accessTokenString, err = p.makeAccessToken(ctx, ar.ClientID, auth, signinMethod)
 	if err != nil {
 		goto done
 	}
 
 	switch tr.GrantType {
 	case oidc.GrantTypeAuthorizationCode:
-		// Create ID token when not previously requested.
-		if !ar.ResponseTypes[oidc.ResponseTypeIDToken] {
-			idTokenString, err = p.makeIDToken(req.Context(), ar, auth, session, accessTokenString, "", signinMethod)
+		// Create ID token when not previously requested amd openid scope is authorized.
+		if !ar.ResponseTypes[oidc.ResponseTypeIDToken] && authorizedScopes[oidc.ScopeOpenID] {
+			idTokenString, err = p.makeIDToken(ctx, ar, auth, session, accessTokenString, "", signinMethod)
 			if err != nil {
 				goto done
 			}
@@ -516,7 +521,7 @@ func (p *Provider) TokenHandler(rw http.ResponseWriter, req *http.Request) {
 
 		// Create refresh token when granted.
 		if authorizedScopes[oidc.ScopeOfflineAccess] {
-			refreshTokenString, err = p.makeRefreshToken(req.Context(), ar.ClientID, auth, nil)
+			refreshTokenString, err = p.makeRefreshToken(ctx, ar.ClientID, auth, nil)
 			if err != nil {
 				goto done
 			}
@@ -595,7 +600,7 @@ func (p *Provider) UserInfoHandler(rw http.ResponseWriter, req *http.Request) {
 
 	userID, sessionRef := p.getUserIDAndSessionRefFromClaims(&claims.StandardClaims, claims.SessionClaims, claims.IdentityClaims)
 
-	ctx := konnect.NewClaimsContext(req.Context(), claims)
+	ctx := konnect.NewClaimsContext(konnect.NewRequestContext(req.Context(), req), claims)
 
 	currentIdentityManager, err := p.getIdentityManagerFromClaims(claims.IdentityProvider, claims.IdentityClaims)
 	if err != nil {
@@ -712,7 +717,7 @@ done:
 	// Support returning signed user info if the registered client requested it
 	// as specified in https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse and
 	// https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
-	registration, _ := p.clients.Get(req.Context(), claims.Audience)
+	registration, _ := p.clients.Get(ctx, claims.Audience)
 	if registration != nil {
 		if registration.RawUserInfoSignedResponseAlg != "" {
 			// Get alg.
@@ -720,7 +725,7 @@ done:
 			// Set extra claims.
 			responseAsMap[oidc.IssuerIdentifierClaim] = p.issuerIdentifier
 			responseAsMap[oidc.AudienceClaim] = registration.ID
-			tokenString, err := p.makeJWT(req.Context(), alg, jwt.MapClaims(responseAsMap))
+			tokenString, err := p.makeJWT(ctx, alg, jwt.MapClaims(responseAsMap))
 			if err != nil {
 				p.logger.WithFields(utils.ErrorAsFields(err)).Debugln("userinfo request failed to encode jwt")
 				p.ErrorPage(rw, http.StatusInternalServerError, "", err.Error())
@@ -749,6 +754,8 @@ func (p *Provider) EndSessionHandler(rw http.ResponseWriter, req *http.Request)
 
 	addResponseHeaders(rw.Header())
 
+	ctx := konnect.NewRequestContext(req.Context(), req)
+
 	// Validate request.
 	err = req.ParseForm()
 	if err != nil {
@@ -783,7 +790,7 @@ func (p *Provider) EndSessionHandler(rw http.ResponseWriter, req *http.Request)
 	}
 
 	// Authorization unauthenticates end user.
-	err = currentIdentityManager.EndSession(req.Context(), rw, req, esr)
+	err = currentIdentityManager.EndSession(ctx, rw, req, esr)
 	if err != nil {
 		goto done
 	}
diff --git a/vendor/github.com/rs/cors/cors.go b/vendor/github.com/rs/cors/cors.go
index da80d343b3d..724f242ac6f 100644
--- a/vendor/github.com/rs/cors/cors.go
+++ b/vendor/github.com/rs/cors/cors.go
@@ -364,9 +364,11 @@ func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
 	// Note: the Fetch standard guarantees that at most one
 	// Access-Control-Request-Headers header is present in the preflight request;
 	// see step 5.2 in https://fetch.spec.whatwg.org/#cors-preflight-fetch-0.
-	reqHeaders, found := first(r.Header, "Access-Control-Request-Headers")
-	if found && !c.allowedHeadersAll && !c.allowedHeaders.Subsumes(reqHeaders[0]) {
-		c.logf("  Preflight aborted: headers '%v' not allowed", reqHeaders[0])
+	// However, some gateways split that header into multiple headers of the same name;
+	// see https://github.com/rs/cors/issues/184.
+	reqHeaders, found := r.Header["Access-Control-Request-Headers"]
+	if found && !c.allowedHeadersAll && !c.allowedHeaders.Accepts(reqHeaders) {
+		c.logf("  Preflight aborted: headers '%v' not allowed", reqHeaders)
 		return
 	}
 	if c.allowedOriginsAll {
@@ -391,9 +393,7 @@ func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
 	if len(c.maxAge) > 0 {
 		headers["Access-Control-Max-Age"] = c.maxAge
 	}
-	if c.Log != nil {
-		c.logf("  Preflight response headers: %v", headers)
-	}
+	c.logf("  Preflight response headers: %v", headers)
 }
 
 // handleActualRequest handles simple cross-origin requests, actual request or redirects
@@ -440,9 +440,7 @@ func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) {
 	if c.allowCredentials {
 		headers["Access-Control-Allow-Credentials"] = headerTrue
 	}
-	if c.Log != nil {
-		c.logf("  Actual response added headers: %v", headers)
-	}
+	c.logf("  Actual response added headers: %v", headers)
 }
 
 // convenience method. checks if a logger is set.
diff --git a/vendor/github.com/rs/cors/internal/sortedset.go b/vendor/github.com/rs/cors/internal/sortedset.go
index 513da20f7d0..844f3f9e035 100644
--- a/vendor/github.com/rs/cors/internal/sortedset.go
+++ b/vendor/github.com/rs/cors/internal/sortedset.go
@@ -52,46 +52,134 @@ func (set SortedSet) String() string {
 	return strings.Join(elems, ",")
 }
 
-// Subsumes reports whether csv is a sequence of comma-separated names that are
-//   - all elements of set,
-//   - sorted in lexicographically order,
+// Accepts reports whether values is a sequence of list-based field values
+// whose elements are
+//   - all members of set,
+//   - sorted in lexicographical order,
 //   - unique.
-func (set SortedSet) Subsumes(csv string) bool {
-	if csv == "" {
-		return true
+func (set SortedSet) Accepts(values []string) bool {
+	var ( // effectively constant
+		maxLen = maxOWSBytes + set.maxLen + maxOWSBytes + 1 // +1 for comma
+	)
+	var (
+		posOfLastNameSeen = -1
+		name              string
+		commaFound        bool
+		emptyElements     int
+		ok                bool
+	)
+	for _, s := range values {
+		for {
+			// As a defense against maliciously long names in s,
+			// we process only a small number of s's leading bytes per iteration.
+			name, s, commaFound = cutAtComma(s, maxLen)
+			name, ok = trimOWS(name, maxOWSBytes)
+			if !ok {
+				return false
+			}
+			if name == "" {
+				// RFC 9110 requires recipients to tolerate
+				// "a reasonable number of empty list elements"; see
+				// https://httpwg.org/specs/rfc9110.html#abnf.extension.recipient.
+				emptyElements++
+				if emptyElements > maxEmptyElements {
+					return false
+				}
+				if !commaFound { // We have now exhausted the names in s.
+					break
+				}
+				continue
+			}
+			pos, ok := set.m[name]
+			if !ok {
+				return false
+			}
+			// The names in s are expected to be sorted in lexicographical order
+			// and to each appear at most once.
+			// Therefore, the positions (in set) of the names that
+			// appear in s should form a strictly increasing sequence.
+			// If that's not actually the case, bail out.
+			if pos <= posOfLastNameSeen {
+				return false
+			}
+			posOfLastNameSeen = pos
+			if !commaFound { // We have now exhausted the names in s.
+				break
+			}
+		}
+	}
+	return true
+}
+
+const (
+	maxOWSBytes      = 1  // number of leading/trailing OWS bytes tolerated
+	maxEmptyElements = 16 // number of empty list elements tolerated
+)
+
+func cutAtComma(s string, n int) (before, after string, found bool) {
+	// Note: this implementation draws inspiration from strings.Cut's.
+	end := min(len(s), n)
+	if i := strings.IndexByte(s[:end], ','); i >= 0 {
+		after = s[i+1:] // deal with this first to save one bounds check
+		return s[:i], after, true
+	}
+	return s, "", false
+}
+
+// TrimOWS trims up to n bytes of [optional whitespace (OWS)]
+// from the start of and/or the end of s.
+// If no more than n bytes of OWS are found at the start of s
+// and no more than n bytes of OWS are found at the end of s,
+// it returns the trimmed result and true.
+// Otherwise, it returns the original string and false.
+//
+// [optional whitespace (OWS)]: https://httpwg.org/specs/rfc9110.html#whitespace
+func trimOWS(s string, n int) (trimmed string, ok bool) {
+	if s == "" {
+		return s, true
+	}
+	trimmed, ok = trimRightOWS(s, n)
+	if !ok {
+		return s, false
 	}
-	posOfLastNameSeen := -1
-	chunkSize := set.maxLen + 1 // (to accommodate for at least one comma)
-	for {
-		// As a defense against maliciously long names in csv,
-		// we only process at most chunkSize bytes per iteration.
-		end := min(len(csv), chunkSize)
-		comma := strings.IndexByte(csv[:end], ',')
-		var name string
-		if comma == -1 {
-			name = csv
-		} else {
-			name = csv[:comma]
+	trimmed, ok = trimLeftOWS(trimmed, n)
+	if !ok {
+		return s, false
+	}
+	return trimmed, true
+}
+
+func trimLeftOWS(s string, n int) (string, bool) {
+	sCopy := s
+	var i int
+	for len(s) > 0 {
+		if i > n {
+			return sCopy, false
 		}
-		pos, found := set.m[name]
-		if !found {
-			return false
+		if !(s[0] == ' ' || s[0] == '\t') {
+			break
 		}
-		// The names in csv are expected to be sorted in lexicographical order
-		// and appear at most once in csv.
-		// Therefore, the positions (in set) of the names that
-		// appear in csv should form a strictly increasing sequence.
-		// If that's not actually the case, bail out.
-		if pos <= posOfLastNameSeen {
-			return false
+		s = s[1:]
+		i++
+	}
+	return s, true
+}
+
+func trimRightOWS(s string, n int) (string, bool) {
+	sCopy := s
+	var i int
+	for len(s) > 0 {
+		if i > n {
+			return sCopy, false
 		}
-		posOfLastNameSeen = pos
-		if comma < 0 { // We've now processed all the names in csv.
+		last := len(s) - 1
+		if !(s[last] == ' ' || s[last] == '\t') {
 			break
 		}
-		csv = csv[comma+1:]
+		s = s[:last]
+		i++
 	}
-	return true
+	return s, true
 }
 
 // TODO: when updating go directive to 1.21 or later,
diff --git a/vendor/github.com/rs/cors/utils.go b/vendor/github.com/rs/cors/utils.go
index 7019f45cd9c..41b0c2836a3 100644
--- a/vendor/github.com/rs/cors/utils.go
+++ b/vendor/github.com/rs/cors/utils.go
@@ -1,7 +1,6 @@
 package cors
 
 import (
-	"net/http"
 	"strings"
 )
 
@@ -24,11 +23,3 @@ func convert(s []string, f func(string) string) []string {
 	}
 	return out
 }
-
-func first(hdrs http.Header, k string) ([]string, bool) {
-	v, found := hdrs[k]
-	if !found || len(v) == 0 {
-		return nil, false
-	}
-	return v[:1], true
-}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 1db70c8132e..9ab21616c4c 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1300,7 +1300,7 @@ github.com/libregraph/idm/server
 github.com/libregraph/idm/server/handler
 github.com/libregraph/idm/server/handler/boltdb
 github.com/libregraph/idm/server/handler/ldif
-# github.com/libregraph/lico v0.62.0
+# github.com/libregraph/lico v0.64.0
 ## explicit; go 1.18
 github.com/libregraph/lico
 github.com/libregraph/lico/bootstrap
@@ -1716,14 +1716,14 @@ github.com/riandyrn/otelchi
 # github.com/rivo/uniseg v0.4.7
 ## explicit; go 1.18
 github.com/rivo/uniseg
-# github.com/rogpeppe/go-internal v1.12.0
-## explicit; go 1.20
+# github.com/rogpeppe/go-internal v1.13.1
+## explicit; go 1.22
 github.com/rogpeppe/go-internal/internal/syscall/windows
 github.com/rogpeppe/go-internal/internal/syscall/windows/sysdll
 github.com/rogpeppe/go-internal/lockedfile
 github.com/rogpeppe/go-internal/lockedfile/internal/filelock
 github.com/rogpeppe/go-internal/semver
-# github.com/rs/cors v1.11.0
+# github.com/rs/cors v1.11.1
 ## explicit; go 1.13
 github.com/rs/cors
 github.com/rs/cors/internal


Test patch:
diff --git a/services/collaboration/pkg/connector/fileconnector_test.go b/services/collaboration/pkg/connector/fileconnector_test.go
index 94b8e4e3c2b..7a776ea8b94 100644
--- a/services/collaboration/pkg/connector/fileconnector_test.go
+++ b/services/collaboration/pkg/connector/fileconnector_test.go
@@ -45,6 +45,7 @@ var _ = Describe("FileConnector", func() {
 			},
 			App: config.App{
 				LockName: "testName_for_unittests", // Only the LockName is used
+				Name:     "test",
 			},
 			Wopi: config.Wopi{
 				WopiSrc: "https://ocis.server.prv",
@@ -1672,16 +1673,14 @@ var _ = Describe("FileConnector", func() {
 			}, nil)
 
 			expectedFileInfo := &fileinfo.Microsoft{
-				OwnerID:                 "61616262636340637573746f6d496470", // hex of aabbcc@customIdp
-				Size:                    int64(998877),
-				Version:                 "v162738490",
-				BaseFileName:            "test.txt",
-				BreadcrumbDocName:       "test.txt",
-				BreadcrumbFolderName:    "/path/to",
-				BreadcrumbFolderURL:     "https://ocis.example.prv/f/storageid$spaceid%21opaqueid",
-				UserCanNotWriteRelative: false,
-				//HostViewURL:                "http://test.ex.prv/view",
-				//HostEditURL:                "http://test.ex.prv/edit",
+				OwnerID:                    "61616262636340637573746f6d496470", // hex of aabbcc@customIdp
+				Size:                       int64(998877),
+				Version:                    "v162738490",
+				BaseFileName:               "test.txt",
+				BreadcrumbDocName:          "test.txt",
+				BreadcrumbFolderName:       "/path/to",
+				BreadcrumbFolderURL:        "https://ocis.example.prv/f/storageid$spaceid%21opaqueid",
+				UserCanNotWriteRelative:    false,
 				SupportsExtendedLockLength: true,
 				SupportsGetLock:            true,
 				SupportsLocks:              true,
@@ -1692,6 +1691,10 @@ var _ = Describe("FileConnector", func() {
 				UserCanRename:              true,
 				UserID:                     "61646d696e40637573746f6d496470", // hex of admin@customIdp
 				UserFriendlyName:           "Pet Shaft",
+				FileSharingURL:             "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=sharing",
+				FileVersionURL:             "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=versions",
+				HostEditURL:                "https://ocis.example.prv/external-test/path/to/test.txt?fileId=storageid%24spaceid%21opaqueid&view_mode=write",
+				HostViewURL:                "https://ocis.example.prv/external-test/path/to/test.txt?fileId=storageid%24spaceid%21opaqueid&view_mode=view",
 			}
 
 			response, err := fc.CheckFileInfo(ctx)
diff --git a/tests/acceptance/features/apiCollaboration/checkFileInfo.feature b/tests/acceptance/features/apiCollaboration/checkFileInfo.feature
index f9767905c8d..7751e09ef85 100644
--- a/tests/acceptance/features/apiCollaboration/checkFileInfo.feature
+++ b/tests/acceptance/features/apiCollaboration/checkFileInfo.feature
@@ -235,7 +235,10 @@ Feature: check file info with different wopi apps
           "UserCanWrite",
           "SupportsLocks",
           "SupportsRename",
-          "SupportsUpdate"
+          "SupportsUpdate",
+          "HostEditUrl",
+          "FileSharingUrl",
+          "FileVersionUrl"
         ],
         "properties": {
           "BaseFileName": {
@@ -285,6 +288,15 @@ Feature: check file info with different wopi apps
           },
           "PostMessageOrigin": {
             "type": "string"
+          },
+          "FileSharingUrl": {
+            "type": "string"
+          },
+          "HostEditUrl": {
+            "type": "string"
+          },
+          "FileVersionUrl": {
+            "type": "string"
           }
         }
       }
@@ -315,7 +327,10 @@ Feature: check file info with different wopi apps
           "UserCanWrite",
           "SupportsLocks",
           "SupportsRename",
-          "SupportsUpdate"
+          "SupportsUpdate",
+          "HostEditUrl",
+          "FileSharingUrl",
+          "FileVersionUrl"
         ],
         "properties": {
           "BaseFileName": {
@@ -365,6 +380,15 @@ Feature: check file info with different wopi apps
           },
           "PostMessageOrigin": {
             "type": "string"
+          },
+          "FileSharingUrl": {
+            "type": "string"
+          },
+          "HostEditUrl": {
+            "type": "string"
+          },
+          "FileVersionUrl": {
+            "type": "string"
           }
         }
       }