diff --git a/app/desktop/package.json b/app/desktop/package.json index d9ec2f81..72f30c94 100644 --- a/app/desktop/package.json +++ b/app/desktop/package.json @@ -27,11 +27,9 @@ "dependencies": { "@lobehub/icons": "^5.10.0", "@tanstack/react-query": "^5.100.14", - "@tanstack/react-virtual": "^3.14.2", "@tauri-apps/api": "^2.11.0", "@tauri-apps/plugin-dialog": "2.7.1", "@tauri-apps/plugin-shell": "^2.2.0", - "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "i18next": "^26.2.0", "lucide-react": "^1.16.0", diff --git a/app/desktop/src-tauri/Cargo.toml b/app/desktop/src-tauri/Cargo.toml index dc9619cc..956240dc 100644 --- a/app/desktop/src-tauri/Cargo.toml +++ b/app/desktop/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "agenthub-desktop" -version = "0.1.0" +version = "0.2.0" edition = "2021" [lib] diff --git a/app/desktop/tsconfig.json b/app/desktop/tsconfig.json index b24ab3f7..67d5f84a 100644 --- a/app/desktop/tsconfig.json +++ b/app/desktop/tsconfig.json @@ -6,7 +6,7 @@ "jsx": "react-jsx", "strict": true, "noUncheckedIndexedAccess": true, - "exactOptionalPropertyTypes": false, + "exactOptionalPropertyTypes": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, diff --git a/app/mobile/package.json b/app/mobile/package.json index c37a0fae..0f2040fa 100644 --- a/app/mobile/package.json +++ b/app/mobile/package.json @@ -25,8 +25,8 @@ "clsx": "^2.1.1", "i18next": "^26.2.0", "lucide-react": "^1.16.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", + "react": "^19.2.7", + "react-dom": "^19.2.7", "react-i18next": "^17.0.8", "zustand": "^5.0.13" }, diff --git a/app/shared/package.json b/app/shared/package.json index 4bb98248..07b3fb66 100644 --- a/app/shared/package.json +++ b/app/shared/package.json @@ -32,12 +32,11 @@ }, "peerDependencies": { "lucide-react": ">=0.400.0 <2.0.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "react-i18next": "^15.0.0" + "react": ">=19.2.7", + "react-dom": ">=19.2.7", + "react-i18next": ">=15.0.0" }, "dependencies": { - "@pierre/diffs": "^1.1.0-beta.18", "diff": "^8.0.2", "prismjs": "^1.30.0" }, @@ -50,8 +49,8 @@ "@types/react-dom": "^19.1.0", "jsdom": "^29.1.1", "lucide-react": "^1.16.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "react": "^19.2.7", + "react-dom": "^19.2.7", "typescript": "~5.8.0", "vitest": "^4.1.7" } diff --git a/app/web/package.json b/app/web/package.json index be49c3cf..72004e23 100644 --- a/app/web/package.json +++ b/app/web/package.json @@ -16,7 +16,6 @@ "dependencies": { "@lobehub/icons": "^5.10.0", "@tanstack/react-query": "^5.100.14", - "@tanstack/react-virtual": "^3.14.2", "i18next": "^26.2.0", "lucide-react": "^1.16.0", "react": "^19.2.7", @@ -24,7 +23,6 @@ "react-i18next": "^17.0.8", "react-markdown": "^10.1.0", "react-syntax-highlighter": "^16.1.1", - "zod": "^4.4.3", "zustand": "^5.0.13" }, "devDependencies": { diff --git a/edge-server/internal/httpserver/server.go b/edge-server/internal/httpserver/server.go index 8b1af2e4..be5f18c8 100644 --- a/edge-server/internal/httpserver/server.go +++ b/edge-server/internal/httpserver/server.go @@ -421,6 +421,8 @@ func corsMiddleware(next http.Handler, remoteMode bool) http.Handler { w.Header().Set("Vary", "Origin") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PATCH, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-AgentHub-Edge-Token") + // Explicitly deny credential forwarding; edge uses Authorization headers, not cookies. + w.Header().Set("Access-Control-Allow-Credentials", "false") } if r.Method == http.MethodOptions { diff --git a/hub-server/internal/repository/message.go b/hub-server/internal/repository/message.go index 171d2285..10206cfd 100644 --- a/hub-server/internal/repository/message.go +++ b/hub-server/internal/repository/message.go @@ -2,6 +2,7 @@ package repository import ( "errors" + "strings" "gorm.io/gorm" @@ -131,11 +132,19 @@ func GetMessagesBySessionAndIDs(db *gorm.DB, sessionID string, ids []string) ([] return msgs, err } +// escapeILIKE escapes ILIKE wildcards so user input cannot match arbitrary patterns. +func escapeILIKE(s string) string { + s = strings.ReplaceAll(s, `\`, `\\`) + s = strings.ReplaceAll(s, `%`, `\%`) + s = strings.ReplaceAll(s, `_`, `\_`) + return s +} + func SearchMessages(db *gorm.DB, q, sessionID, contentType, from, to string) ([]model.Message, error) { var msgs []model.Message query := db.Where("session_id = ?", sessionID). Where("recalled = false"). - Where("content->>'text' ILIKE ?", "%"+q+"%") + Where("content->>'text' ILIKE ?", "%"+escapeILIKE(q)+"%") if contentType != "" { query = query.Where("content_type = ?", contentType) } @@ -156,7 +165,7 @@ func SearchAllMessages(db *gorm.DB, userID, q, contentType, from, to string) ([] WHERE sm.member_type = ? AND sm.member_id = ? AND sm.left_at IS NULL AND m.recalled = false AND m.content->>'text' ILIKE ?` - args := []interface{}{"user", userID, "%" + q + "%"} + args := []interface{}{"user", userID, "%" + escapeILIKE(q) + "%"} if contentType != "" { sql += " AND m.content_type = ?" diff --git a/hub-server/internal/service/oidc.go b/hub-server/internal/service/oidc.go index b6082c27..cbea0203 100644 --- a/hub-server/internal/service/oidc.go +++ b/hub-server/internal/service/oidc.go @@ -284,12 +284,17 @@ func (s *OIDCService) exchangeCode(ctx context.Context, code, codeVerifier, redi } if resp.StatusCode != http.StatusOK { + // Truncate body to avoid logging potentially sensitive token exchange data. + bodyPreview := string(body) + if len(bodyPreview) > 128 { + bodyPreview = bodyPreview[:128] + "...(truncated)" + } slog.Error("oidc token endpoint returned non-200", "status", resp.StatusCode, - "response_body", string(body), + "response_body_preview", bodyPreview, "redirect_uri_sent", redirectURI, ) - return nil, fmt.Errorf("token endpoint returned %d: %s", resp.StatusCode, string(body)) + return nil, fmt.Errorf("token endpoint returned %d", resp.StatusCode) } var tokenResp tokenEndpointResponse