diff --git a/api-docs/openapi.json b/api-docs/openapi.json index b65b212a..b9c1b967 100644 --- a/api-docs/openapi.json +++ b/api-docs/openapi.json @@ -4,7 +4,7 @@ "description": "REST API for Cosmos Cloud server management", "title": "Cosmos Server API", "contact": {}, - "version": "0.22.23" + "version": "0.22.24" }, "paths": { "/_logs": { diff --git a/api-docs/swagger.json b/api-docs/swagger.json index 4a819cce..fc5b1e3d 100644 --- a/api-docs/swagger.json +++ b/api-docs/swagger.json @@ -4,7 +4,7 @@ "description": "REST API for Cosmos Cloud server management", "title": "Cosmos Server API", "contact": {}, - "version": "0.22.23" + "version": "0.22.24" }, "basePath": "/cosmos", "paths": { diff --git a/api-docs/swagger.yaml b/api-docs/swagger.yaml index fbccb0ba..7e6de298 100644 --- a/api-docs/swagger.yaml +++ b/api-docs/swagger.yaml @@ -2059,7 +2059,7 @@ info: contact: {} description: REST API for Cosmos Cloud server management title: Cosmos Server API - version: 0.22.23 + version: 0.22.24 paths: /_logs: get: diff --git a/changelog.md b/changelog.md index 4296c164..4ffd0c5b 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,7 @@ +## Version 0.22.24 + - Fix OpenID for tunneled routes + - Fix tunnels being duplicated when saving + ## Version 0.22.23 - Add RootProtocol and RootHostname to cosmos-installer in cosmos-compose diff --git a/client/src/api/market.demo.json b/client/src/api/market.demo.json index ab908e77..9ff6952f 100644 --- a/client/src/api/market.demo.json +++ b/client/src/api/market.demo.json @@ -92,6 +92,117 @@ "arm64" ] }, + { + "name": "Plurality", + "description": "Free, self-hosted AI assistant you can see and steer in real time. Run quick conversations or long-running agents that spawn parallel sub-agents — every tool call, edit and sub-agent shown inline as a conversation. Any model via LiteLLM, sandboxed agents, MCP, image generation, CRON, webhooks and per-tool approval. One Flutter app on web, desktop and mobile. Self-contained SQLite. MIT.", + "url": "", + "longDescription": "\u003cp\u003ePlurality is a free, self-hosted AI assistant you can see in action, steer in real time, and easily debug. Spawn a plain conversation for a quick answer, or hand an agent a goal and let it keep working after you walk away — for minutes, hours, or days — calling tools, monitoring things, and spawning parallel sub-agents.\u003c/p\u003e\u003cp\u003eWhere other platforms only let an agent text you updates, Plurality shows every inference the agent made as a conversation you can open at any moment to watch, stop, steer, or debug. Tool calls render inline with their arguments, file edits show as git-style diffs, long jobs show a live checklist, and even sub-agents appear as nested sub-conversations under the agent that spawned them. Every message carries its token counts and dollar cost.\u003c/p\u003e\u003cp\u003eIt runs (almost) any model from (almost) any provider through a local LiteLLM proxy (OpenAI, Anthropic, Gemini, Fireworks, OpenRouter and more) from a single YAML file, with keys staying on your box. Agents are sandboxed with full control over their virtual environment, support tool calls, MCP, shell execution, image generation, skills and a custom harness with per-tool approval (Off / Ask / On). Attach a folder to any conversation to code in it, draft documents, or organize files. Other features include a CRON scheduler, signed webhook triggers, multimodal support (vision, image generation/editing, speech-to-text, TTS), reusable preset mini-apps, hybrid full-text + semantic search, and local accounts or OpenID/OIDC single sign-on. A single Flutter client runs on web, desktop and mobile. Self-contained per-user SQLite, no external database. MIT licensed.\u003c/p\u003e", + "translation": { + "en": { + "description": "", + "longDescription": "" + }, + "de": { + "description": "", + "longDescription": "" + }, + "de-CH": { + "description": "", + "longDescription": "" + }, + "en-GB": { + "description": "", + "longDescription": "" + }, + "cn": { + "description": "", + "longDescription": "" + }, + "cn-TW": { + "description": "", + "longDescription": "" + }, + "es": { + "description": "", + "longDescription": "" + }, + "fr": { + "description": "", + "longDescription": "" + }, + "hi": { + "description": "", + "longDescription": "" + }, + "it": { + "description": "", + "longDescription": "" + }, + "jp": { + "description": "", + "longDescription": "" + }, + "kr": { + "description": "", + "longDescription": "" + }, + "nl": { + "description": "", + "longDescription": "" + }, + "pl": { + "description": "", + "longDescription": "" + }, + "pt": { + "description": "", + "longDescription": "" + }, + "ru": { + "description": "", + "longDescription": "" + }, + "tr": { + "description": "", + "longDescription": "" + }, + "ar": { + "description": "", + "longDescription": "" + }, + "en-FUNNYSHAKESPEARE": { + "description": "", + "longDescription": "" + } + }, + "tags": [ + "AI", + "assistant", + "chatbot", + "LLM", + "OpenRouter", + "self-hosted", + "multi-user", + "privacy-focused", + "open-source", + "Docker" + ], + "repository": "https://github.com/azukaar/plurality", + "image": "https://hub.docker.com/r/azukaar/plurality", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/screenshots/2.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/screenshots/3.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/screenshots/4.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/screenshots/5.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, { "name": "Nextcloud", "description": "Nextcloud is an open-source, self-hosted file share and collaboration platform, similar to Dropbox. It offers features such as file sharing, syncing, encryption, and collaboration tools. With its extensible app ecosystem, you can tailor your cloud storage service to your needs. Nextcloud is compatible with numerous platforms and can be integrated with many IT infrastructure systems.", @@ -4830,6 +4941,117 @@ "arm64" ] }, + { + "name": "Plurality", + "description": "Free, self-hosted AI assistant you can see and steer in real time. Run quick conversations or long-running agents that spawn parallel sub-agents — every tool call, edit and sub-agent shown inline as a conversation. Any model via LiteLLM, sandboxed agents, MCP, image generation, CRON, webhooks and per-tool approval. One Flutter app on web, desktop and mobile. Self-contained SQLite. MIT.", + "url": "", + "longDescription": "\u003cp\u003ePlurality is a free, self-hosted AI assistant you can see in action, steer in real time, and easily debug. Spawn a plain conversation for a quick answer, or hand an agent a goal and let it keep working after you walk away — for minutes, hours, or days — calling tools, monitoring things, and spawning parallel sub-agents.\u003c/p\u003e\u003cp\u003eWhere other platforms only let an agent text you updates, Plurality shows every inference the agent made as a conversation you can open at any moment to watch, stop, steer, or debug. Tool calls render inline with their arguments, file edits show as git-style diffs, long jobs show a live checklist, and even sub-agents appear as nested sub-conversations under the agent that spawned them. Every message carries its token counts and dollar cost.\u003c/p\u003e\u003cp\u003eIt runs (almost) any model from (almost) any provider through a local LiteLLM proxy (OpenAI, Anthropic, Gemini, Fireworks, OpenRouter and more) from a single YAML file, with keys staying on your box. Agents are sandboxed with full control over their virtual environment, support tool calls, MCP, shell execution, image generation, skills and a custom harness with per-tool approval (Off / Ask / On). Attach a folder to any conversation to code in it, draft documents, or organize files. Other features include a CRON scheduler, signed webhook triggers, multimodal support (vision, image generation/editing, speech-to-text, TTS), reusable preset mini-apps, hybrid full-text + semantic search, and local accounts or OpenID/OIDC single sign-on. A single Flutter client runs on web, desktop and mobile. Self-contained per-user SQLite, no external database. MIT licensed.\u003c/p\u003e", + "translation": { + "en": { + "description": "", + "longDescription": "" + }, + "de": { + "description": "", + "longDescription": "" + }, + "de-CH": { + "description": "", + "longDescription": "" + }, + "en-GB": { + "description": "", + "longDescription": "" + }, + "cn": { + "description": "", + "longDescription": "" + }, + "cn-TW": { + "description": "", + "longDescription": "" + }, + "es": { + "description": "", + "longDescription": "" + }, + "fr": { + "description": "", + "longDescription": "" + }, + "hi": { + "description": "", + "longDescription": "" + }, + "it": { + "description": "", + "longDescription": "" + }, + "jp": { + "description": "", + "longDescription": "" + }, + "kr": { + "description": "", + "longDescription": "" + }, + "nl": { + "description": "", + "longDescription": "" + }, + "pl": { + "description": "", + "longDescription": "" + }, + "pt": { + "description": "", + "longDescription": "" + }, + "ru": { + "description": "", + "longDescription": "" + }, + "tr": { + "description": "", + "longDescription": "" + }, + "ar": { + "description": "", + "longDescription": "" + }, + "en-FUNNYSHAKESPEARE": { + "description": "", + "longDescription": "" + } + }, + "tags": [ + "AI", + "assistant", + "chatbot", + "LLM", + "OpenRouter", + "self-hosted", + "multi-user", + "privacy-focused", + "open-source", + "Docker" + ], + "repository": "https://github.com/azukaar/plurality", + "image": "https://hub.docker.com/r/azukaar/plurality", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/screenshots/2.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/screenshots/3.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/screenshots/4.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/screenshots/5.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Plurality/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, { "name": "Grav", "description": "Grav is an open-source, self-hosted, flat-file content management system (CMS). It offers features like content filtering, multi-language support, flexible templating with Twig, and simple content creation with Markdown. Grav can be extended with plugins and themes. It can be run on Windows, Linux, MacOS, and Docker.", diff --git a/client/src/pages/config/users/proxyman.jsx b/client/src/pages/config/users/proxyman.jsx index 1572c114..afed5750 100644 --- a/client/src/pages/config/users/proxyman.jsx +++ b/client/src/pages/config/users/proxyman.jsx @@ -94,7 +94,10 @@ const ProxyManagement = () => { ...config.HTTPConfig, ProxyConfig: { ...config.HTTPConfig.ProxyConfig, - Routes: routes, + // Tunnel routes are merged into the list for display only (see the render + // below); they live in the constellation tunnel cache, not in the proxy + // config. Strip them here so no save path persists them as local routes. + Routes: routes.filter((r) => !r._IsTunnel), }, }, }; diff --git a/go-sdk/client.gen.go b/go-sdk/client.gen.go index cd332a72..6bf6120d 100644 --- a/go-sdk/client.gen.go +++ b/go-sdk/client.gen.go @@ -27262,7 +27262,7 @@ var swaggerSpec = []string{ "ujPuSpXW7qYDZbqpVzxYc1WVLKVyeSSSgPORDeZsaBKe+IPyFpJvdKYMmwESqvS63bT+tfDEPppTPgvO", "kDB+1z1Z/5rncdP3ky9ZY5PgyroGHrgen3ypfIuiyGMDRPbg3wGVIA9zK+WacxzMrWRaoJZLKMD+YyWl", "FYhlzOz761csFjMVztFBU9Q9buQ8uT4Z32Ck8lRIYouXkaNE5DGxpT1IuirLY4Q4jS67ruHYNjm8OhtU", - "HBMGr0dv3oze/FLUQaEZG7wd/DJ6PXrt8sLgFg8+o37n7Z8DR0bXo7l0LrlLQ2bnScQMY1UJVTYBGuNE", + "HBMGr0dv3oze/FrUQaEZG7wd/DJ6PXrt8sLgFg8+o37n7Z8DR0bXo7l0LrlLQ2bnScQMY1UJVTYBGuNE", "wxdNbOk1t0aXFFTws3jwdvAbGEBUyMKsezJO+eb16+JgCm89+KIPcEzEfMTnWnaaCeNULj2uyhtnevkP", "s/VfX//ccop2NYCqph7PpB84dQABsZ3+l285/amQExbHgMT/b61P91HmPnMFggt4xOY1zMKotSpO/evT", "10/DgcpTQ1AxwvyeJ4LGFVDDvJoYaPivgY2OHnwyYx7QjB18TiF14lcj9NpmJMckGU4P6RL5uDVj7KGN", diff --git a/go-sdk/version.go b/go-sdk/version.go index 7abe7c95..3915cf98 100644 --- a/go-sdk/version.go +++ b/go-sdk/version.go @@ -1,4 +1,4 @@ package cosmossdk // Version is the SDK version, synced with Cosmos Server at build time. -const Version = "0.22.23" +const Version = "0.22.24" diff --git a/package.json b/package.json index f9993e30..87fc3af0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cosmos-server", - "version": "0.22.23", + "version": "0.22.24", "description": "", "main": "test-server.js", "bugs": { diff --git a/src/authorizationserver/oauth2.go b/src/authorizationserver/oauth2.go index b3b17b76..e82559c2 100644 --- a/src/authorizationserver/oauth2.go +++ b/src/authorizationserver/oauth2.go @@ -228,6 +228,11 @@ func detectCallbackEndpoint(w http.ResponseWriter, req *http.Request) { } _, route := utils.FindRouteByReqHost(req.Host) + if route == nil { + utils.Error("OpenID callback: no route found for host "+req.Host, nil) + http.Error(w, "Invalid callback host", http.StatusBadRequest) + return + } client := utils.GetProxyOIDCredentials(*route, false) utils.Log("OpenID Direct: Exchanging code for token for client: " + client.ID) diff --git a/src/index.go b/src/index.go index d5078e6e..5349e00e 100644 --- a/src/index.go +++ b/src/index.go @@ -206,7 +206,7 @@ func main() { } // @title Cosmos Server API -// @version 0.22.23 +// @version 0.22.24 // @description REST API for Cosmos Cloud server management // @BasePath /cosmos // @securityDefinitions.apikey BearerAuth diff --git a/src/utils/utils.go b/src/utils/utils.go index 4bcc1300..411f5bb7 100644 --- a/src/utils/utils.go +++ b/src/utils/utils.go @@ -1342,9 +1342,19 @@ func FindRouteByReqHost(hostname string) (string, *ProxyRouteConfig) { } var proxyRoute *ProxyRouteConfig - for _, route := range config.HTTPConfig.ProxyConfig.Routes { + + // Constellation tunnel routes are not stored in ProxyConfig.Routes (they live in the + // tunnel cache), so a host lookup must consult both collections or it will miss any + // tunneled host - e.g. the OpenID detect-callback landing on a tunnel host would find + // no route and callers dereferencing the result would panic. Copy into a fresh slice + // so the append never writes into the shared config backing array. + allRoutes := append([]ProxyRouteConfig{}, config.HTTPConfig.ProxyConfig.Routes...) + allRoutes = append(allRoutes, GetConstellationTunnelRoutes()...) + + for _, route := range allRoutes { if route.Host == hostname { - proxyRoute = &route + r := route + proxyRoute = &r break } }