Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,31 @@ All notable changes to SearchMob Desktop are documented here. The version scheme

## [Unreleased]

### Added
- **Google-style search operators.** `"exact phrase"`, `-term`, `site:` / `-site:`, `intitle:`,
`inurl:`, `filetype:` (or `ext:`), `before:` / `after:` dates, and `OR`. Operators the upstream
engines understand are forwarded to them, and every structural filter is also enforced on your
device over the merged results, so they behave consistently across engines, in the app and on
the served pages. The served home page gains a collapsible operator cheat sheet, and relevance
ranking no longer lets scoping clauses (like the verticals' internal `site:` groups) pollute the
match score.

### Security
- **Cross-site request forgery fix for the served pages.** A literal `Origin: null`, which an
attacker page can forge on a cross-site POST, was treated as same-origin; it is now rejected,
and the server sends `Referrer-Policy: same-origin` so its own forms carry a real origin
(cross-origin navigation still leaks nothing).
- Every served response now carries `Content-Security-Policy`, `Cache-Control: no-store`, and
`Permissions-Policy` headers, so queries never persist in browser caches and no external
script/style/frame can ever load.
- The network-mode access token is compared in constant time and can be sent via
`Authorization: Bearer` or `X-SearchMob-Token` headers instead of only the `?token=` query
parameter (which stays for OpenSearch templates but leaks into browser history).

### Changed
- **The served pages are restyled to Material 3**: elevated search bar with focus states, rounded
cards, pill buttons, chip state layers, and theme-derived colors in every palette.

## 26.06.07 — 2026-06-19

### Fixed
Expand Down
9 changes: 6 additions & 3 deletions src/searchmob_desktop/engines/aggregator.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,11 @@ def _published_of(item: SearchResult) -> int | None:
# Fold a lexical query-match score into the RRF score so the final order leads with relevance
# (does the result actually contain the query's content words, especially the title) and keeps
# engine consensus as a strong secondary signal. Without this, near-tied RRF scores let an
# irrelevant result one engine ranked highly sit among the top hits.
terms = content_terms(ctx.query)
# irrelevant result one engine ranked highly sit among the top hits. Scoring reasons about the
# operator-free `ranking_terms` when set, so a scoping clause (a vertical's `site:` OR group,
# a user operator) never pollutes the lexical match; `ctx.query` is the fallback.
ranking_text = ctx.ranking_terms if ctx.ranking_terms is not None else ctx.query
terms = content_terms(ranking_text)

def _final_score(b: _Bucket) -> float:
# Navigational promotion: when the squished query names this result's domain (query
Expand All @@ -178,7 +181,7 @@ def _final_score(b: _Bucket) -> float:
blended_score(
b.score,
lexical_score(b.title, b.snippet, terms),
language_affinity(ctx.query, b.title, b.snippet),
language_affinity(ranking_text, b.title, b.snippet),
)
* nav
)
Expand Down
Loading