Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
39a8a41
add debugger to settings auth
riofriz May 1, 2026
99f110f
add more setting auth cookies
riofriz May 1, 2026
ff3462b
harden route security and break down some routes into smaller ones or…
riofriz May 1, 2026
290c8f2
make extension descriptions scrollable
riofriz May 1, 2026
85266fe
make extension descriptions scrollable
riofriz May 1, 2026
a8c8031
store was using auth slightly different for no real reason just becau…
riofriz May 1, 2026
eed8b29
fix conflicts and push docs updates
riofriz May 1, 2026
f241170
fix positioning of types
riofriz May 2, 2026
45e5b93
Merge branch 'main' into develop
riofriz May 2, 2026
3f7799a
Add proxy auth when using fetch
May 2, 2026
ed9dc36
Fix default ports
May 2, 2026
b3e2b14
adjust rules around engine outbound domains
riofriz May 2, 2026
17ebe66
Merge branch 'develop' into fix/proxy-auth-fetch
riofriz May 2, 2026
3845437
fix bug around or operation
riofriz May 2, 2026
ab911f3
fix fixable dependency vulnerabilities in the image
riofriz May 3, 2026
882b911
add way to fetch via proxies for plugins and a way to sign image prox…
riofriz May 3, 2026
5e68549
fix hardcoded color around settings styling
riofriz May 3, 2026
5dcbaf1
fix border in dark mode on store
riofriz May 3, 2026
787ea2b
Merge branch 'develop' into fix/proxy-auth-fetch
riofriz May 3, 2026
0d59879
Merge pull request #106 from LaustDengsoe/fix/proxy-auth-fetch
fccview May 3, 2026
54df9a4
improve visibility of tabs when certain engines are selected
riofriz May 3, 2026
6859cb9
allow keypair in POST and fix small bug on media engines
riofriz May 3, 2026
071c3ef
remove shadow/border from the glance box
riofriz May 3, 2026
f3557d9
remove shadow/border from the glance box
riofriz May 3, 2026
836af38
Merge branch 'develop' into feature/api-key
riofriz May 3, 2026
37bcc06
start implementing API key
riofriz May 3, 2026
6d698d1
api key should be the only hidden part here
riofriz May 4, 2026
786dacf
fix tests post auth
riofriz May 4, 2026
6825be4
Merge pull request #110 from degoog-org/feature/api-key
fccview May 4, 2026
0ab7bc4
add search to settings, i love this so damn much
riofriz May 4, 2026
5a27f08
update at a glance to be much smarter
riofriz May 4, 2026
84a8535
update docs and fix minor issues
riofriz May 4, 2026
1fd1a78
Merge pull request #111 from degoog-org/feature/at-a-glance-smart
fccview May 4, 2026
64565b1
allow adding base url
riofriz May 5, 2026
5e19d8b
bump that fucker, too much stuff for a minor release
riofriz May 5, 2026
c929f3c
fix tests
riofriz May 5, 2026
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
10 changes: 5 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

# Coding standards

- **Functions that return a value** use arrow functions (e.g. `const getX = () => value`).
- **Functions that do not return** (side-effect only) use regular `function` declarations.
- **Internal / private helpers** prepend with `_` (e.g. `_parseQuery`, `_formatDate`).
- **CSS** Reuse existing app classes where possible (see [Styling](docs/styling.html) for a list). Must use SCSS/CSS variables (e.g. `$primary or var(--text-primary)`) so themes and light/dark mode keep working wel.
- **Structure** Keep things modular; follow the existing folder structure (e.g. one folder per plugin, one file or folder per engine).
- **Functions that return a value** - use arrow functions (e.g. `const getX = () => value`).
- **Functions that do not return** (side-effect only) - use regular `function` declarations.
- **Internal / private helpers** - prepend with `_` (e.g. `_parseQuery`, `_formatDate`).
- **CSS** - Reuse existing app classes where possible (see [Styling](docs/styling.html) for a list). Must use SCSS/CSS variables (e.g. `$primary or var(--text-primary)`) so themes and light/dark mode keep working wel.
- **Structure** - Keep things modular; follow the existing folder structure (e.g. one folder per plugin, one file or folder per engine).
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ COPY . .
RUN bun run build

FROM base AS release
RUN apk add --no-cache git ca-certificates gosu curl
RUN apk add --no-cache git ca-certificates su-exec curl

COPY --from=install /app/node_modules ./node_modules
COPY --from=build /app/src ./src
Expand Down
6 changes: 3 additions & 3 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/aliases.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Aliases Degoog docs</title>
<title>Aliases - Degoog docs</title>
<script>
(function () {
try {
Expand Down
30 changes: 29 additions & 1 deletion docs/api.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>API reference Degoog docs</title>
<title>API reference - Degoog docs</title>
<script>
(function () {
try {
Expand Down Expand Up @@ -152,6 +152,28 @@ <h2>Overview</h2>
Server, and these limits will apply to every caller.
</p>

<h2>API key protection (optional)</h2>
<p>
In Settings -> Server you can require authentication for search, search
stream, search retry, and suggest. When that is enabled for a route,
requests without valid credentials receive
<code>401</code> and a JSON body such as
<code>{"error":"Unauthorized"}</code>.
</p>
<p>
For external callers (scripts, integrations,
<code>curl</code>, Open WebUI, etc.), use the API key from the same
settings screen (the 64-character hexadecimal value) as a Bearer token.
The server compares it to the stored secret; only that exact key is
accepted.
</p>
<pre><code>curl -H "Authorization: Bearer YOUR_API_KEY_HERE" \
"http://localhost:4444/api/search?q=hello"</code></pre>
<p>
The in-browser UI does not rely on this header; it uses a separate
short-lived nonce supplied with the page when protection is on.
</p>

<h2><code>GET /api/search</code></h2>
<p>Run a metasearch and get merged and scored results.</p>
<table>
Expand Down Expand Up @@ -296,6 +318,12 @@ <h2>
Just remember to replace <code>http://127.0.0.1:4444</code> with
your actual Degoog address.
</p>
<p>
If you enabled API key protection for search, configure your client to
send <code>Authorization: Bearer …</code> with your instance key as
described above (Open WebUI must support custom headers for the search
URL if you use that mode).
</p>
</main>
</div>
<div id="ade-backdrop" class="ade-backdrop"></div>
Expand Down
27 changes: 14 additions & 13 deletions docs/engines.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Search engines Degoog docs</title>
<title>Search engines - Degoog docs</title>
<script>
(function () {
try {
Expand Down Expand Up @@ -303,6 +303,16 @@ <h2>Language &amp; time filters</h2>
target a specific thumbnail container first.
</td>
</tr>
<tr>
<td><code>context.signProxyUrl(url)</code></td>
<td><code>(url: string) =&gt; string</code></td>
<td>
Returns a signed <code>/api/proxy/image</code> URL for the
given external image URL. Use this when you include thumbnails
in your results so they load correctly regardless of the
outgoing allowlist configuration.
</td>
</tr>
</tbody>
</table>
<p>
Expand Down Expand Up @@ -388,16 +398,8 @@ <h2>Proxies</h2>
Use <code>context.fetch</code> for every outbound HTTP request
instead of the global <code>fetch</code>.
</li>
<li>
Export <strong>outgoingHosts</strong> as an array of hostname
strings without the protocol or path. These hostnames get added to
the proxy allowlist. Only use <code>["*"]</code> if your engine
needs to fetch from random user provided URLs.
</li>
</ol>
<pre><code>export const outgoingHosts = ["www.example.com", "example.com"];

export default class MyEngine {
<pre><code>export default class MyEngine {
name = "My Search";
async executeSearch(query, page = 1, _timeFilter, context) {
const url = `https://www.example.com/search?q=${encodeURIComponent(query)}`;
Expand Down Expand Up @@ -457,9 +459,8 @@ <h2>Examples from the official store</h2>
rel="noopener"
>Ecosia</a
>
is a web engine using <code>outgoingHosts</code> and
<code>bangShortcut</code> while correctly utilizing
<code>context.fetch</code>.
is a web engine using <code>bangShortcut</code> while correctly
utilizing <code>context.fetch</code>.
</li>
<li>
<a
Expand Down
64 changes: 47 additions & 17 deletions docs/env.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Environment variables Degoog docs</title>
<title>Environment variables - Degoog docs</title>
<script>
(function () {
try {
Expand Down Expand Up @@ -152,6 +152,25 @@ <h2>General</h2>
<td>The port your server listens on.</td>
<td><code>4444</code></td>
</tr>
<tr>
<td><code>DEGOOG_BASE_URL</code></td>
<td>
Base path for serving Degoog behind a reverse proxy at a
sub-path. The expected value is a path like
<code>/degoog</code>. A full URL is also accepted -
<code>https://example.com/degoog</code> behaves the same as
<code>/degoog</code> since only the path portion is used.
A bare domain with no sub-path (e.g.
<code>https://degoog.org</code>) has no effect since there
is no path to prepend. When unset, Degoog is served at the
root <code>/</code> as usual.
<br /><br />
<strong>Note:</strong> the OpenSearch XML descriptor always
uses only the path portion of this value so that its URLs
remain valid regardless of how the variable was set.
</td>
<td></td>
</tr>
<tr>
<td><code>DEGOOG_SETTINGS_PASSWORDS</code></td>
<td>
Expand Down Expand Up @@ -187,34 +206,33 @@ <h2>General</h2>
<tr>
<td><code>DEGOOG_DEFAULT_SEARCH_LANGUAGE</code></td>
<td>
The default ISO 639 1 language code applied to all searches
when a user does not select a specific language (like
<code>en</code>, <code>de</code>, or <code>it</code>).
Default ISO 639-1 language code applied to all searches when
searches when no language is selected by the user (e.g.
<code>en</code>, <code>de</code>, <code>it</code>).
</td>
<td><code>en-US</code></td>
</tr>
<tr>
<td><code>DEGOOG_I18N</code></td>
<td>
This forces the UI locale for all requests and overrides the
<code>Accept-Language</code> header (for example
<code>en-US</code> or <code>fr-FR</code>). When you set this,
the normal locale pipeline runs but uses this as the source.
If left empty, it falls back to the
<code>Accept-Language</code> header.
Forces the UI locale for all requests, overriding the
<code>Accept-Language</code> header (e.g. <code>en-US</code>,
<code>fr-FR</code>). When set, the same locale pipeline runs
as normal - only the source changes. Unset or empty:
<code>Accept-Language</code> is used as today.
</td>
<td></td>
</tr>
<tr>
<td><code>LOG_LEVEL</code></td>
<td>
Controls how verbose your server console output is. Supported
levels from most to least severe are <code>fatal</code>,
<code>error</code>, <code>warn</code>, <code>info</code>,
<code>log</code>, and <code>debug</code>. Each level includes
all messages of higher severity. Use <code>debug</code> to
print absolutely everything, including your plugin execution
times. If you use Docker, you can view your logs by running
Controls the verbosity of server-side console output.
Supported levels from most to least severe:
<code>fatal</code>, <code>error</code>, <code>warn</code>,
<code>info</code>, <code>log</code>, <code>debug</code>. Each
level includes all levels of higher severity. Set to
<code>debug</code> to print all messages, including plugin
execution times. If you use docker you can view your logs with
<code>docker compose logs -f</code>.
</td>
<td><code>info</code></td>
Expand Down Expand Up @@ -293,6 +311,18 @@ <h2>Plugins, themes, engines</h2>
</td>
<td><code>data/plugin-settings.json</code></td>
</tr>
<tr>
<td><code>DEGOOG_DEFAULT_ENGINES_FILE</code></td>
<td>
Path to the JSON file storing default enabled/disabled engines
</td>
<td><code>data/default-engines.json</code></td>
</tr>
<tr>
<td><code>DEGOOG_SETTINGS_TOKENS_FILE</code></td>
<td>Path to the JSON file storing settings tokens</td>
<td><code>data/settings-tokens.json</code></td>
</tr>
<tr>
<td><code>DEGOOG_ALIASES_FILE</code></td>
<td>
Expand Down
2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Degoog Documentation</title>
<title>Degoog - Documentation</title>
<script>
(function () {
try {
Expand Down
50 changes: 44 additions & 6 deletions docs/plugins.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Plugins Degoog docs</title>
<title>Plugins - Degoog docs</title>
<script>
(function () {
try {
Expand Down Expand Up @@ -199,7 +199,37 @@ <h3>Plugin context and init()</h3>
// ctx.template contains your template.html
// ctx.dir is the absolute path to your plugin folder
// ctx.readFile is an async function to read any file from your plugin folder
// ctx.signProxyUrl(url) returns a signed /api/proxy/image URL for any external image
// ctx.fetch(url, init?) is a proxy-aware fetch, respects your outgoing proxy settings
// ctx.createCache(defaultTtlMs) returns an in-memory TTL cache { get, set, clear }
}</code></pre>
<h3>TTL cache (<code>createCache</code>)</h3>
<p>
Both <code>init(ctx)</code> and slot <code>execute(query, context)</code>
receive <strong><code>createCache</code></strong>: a factory compatible with
the built-in server helper. Call
<code>ctx.createCache&lt;T&gt;(defaultTtlMs)</code> (or
<code>context.createCache&lt;T&gt;(defaultTtlMs)</code> in slots) to get an
object with <code>get(key)</code>, <code>set(key, value, ttlMs?)</code>, and
<code>clear()</code>. Keys are strings; values are typed by your generic
<code>T</code>. Entries expire automatically after the TTL (milliseconds).
</p>
<p>
Built-in and third-party code paths share this API: typical usage is to
call <code>createCache</code> once in <code>init</code>, keep the returned
cache on a module-level variable, and reuse <code>get</code> /
<code>set</code> from <code>execute</code> (for example for fetched page
excerpts). Prefer <strong>always</strong> using
<code>ctx.createCache</code> / <code>context.createCache</code> rather than
importing cache helpers from server internals so plugins behave the same in
every environment.
</p>
<p>
Store <code>ctx.fetch</code> during <code>init</code> if your plugin
makes outgoing HTTP requests outside of <code>execute()</code>, for
example inside custom plugin routes. Using it keeps your requests
consistent with the proxy settings configured in Settings.
</p>
<p>
For example, you might build a plugin that uses both a command
template and a separate card template. The
Expand Down Expand Up @@ -242,7 +272,11 @@ <h2 id="bang-commands">Bang commands</h2>
<p>
The second argument passed to <code>execute</code> is
<code>context</code>, which might contain your
<code>clientIp</code> and <code>page</code>.
<code>clientIp</code>, <code>page</code>, and
<code>signProxyUrl(url)</code>. Call
<code>context.signProxyUrl</code> to get a signed
<code>/api/proxy/image</code> URL for any external image you want to
serve through the built-in image proxy.
</p>
<p>
You can also include optional properties like
Expand Down Expand Up @@ -388,10 +422,14 @@ <h2>Slot plugins</h2>
<strong>execute(query, context)</strong> (async): Return an object
with an optional <code>title</code> string and an
<code>html</code> string. If you return an empty string for the
html, nothing will show up. The <code>context</code> contains the
<code>clientIp</code> and an array of <code>results</code>. Note
that the results array is only populated if you set
<code>waitForResults: true</code> on your plugin.
html, nothing will show up. The <code>context</code> includes
<code>clientIp</code>; <code>results</code> (only when
<code>waitForResults: true</code>); proxy-aware
<code>fetch(url, init?)</code>; <code>signProxyUrl(url)</code> for
external images; and <code>createCache(defaultTtlMs)</code> for the same
TTL cache factory as in <code>init(ctx)</code>. Note that the results
array is only populated if you set <code>waitForResults: true</code> on
your plugin.
</li>
</ul>
<p>
Expand Down
2 changes: 1 addition & 1 deletion docs/store.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Store repositories Degoog docs</title>
<title>Store repositories - Degoog docs</title>
<script>
(function () {
try {
Expand Down
2 changes: 1 addition & 1 deletion docs/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ html[data-theme="dark"] {
--ade-bg: #0f0e0d;
--ade-surface: #171614;
--ade-sidebar-bg: #131210;
--ade-border: #2c2b27;
--ade-border: #636055;
--ade-text: #e2dfd6;
--ade-text-muted: #857f74;
--ade-active-bg: #252420;
Expand Down
2 changes: 1 addition & 1 deletion docs/styling.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Styling Degoog docs</title>
<title>Styling - Degoog docs</title>
<script>
(function () {
try {
Expand Down
2 changes: 1 addition & 1 deletion docs/themes.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Themes Degoog docs</title>
<title>Themes - Degoog docs</title>
<script>
(function () {
try {
Expand Down
Loading
Loading