133 Commits

Author SHA1 Message Date
Abhinav Raut baeade99a6 oidc: always read the redirect URL from settings, drop the session copy 2026-08-30 23:26:34 +05:30
malpou 8eeea388d6 oidc: resolve redirect URI once per login and propagate errors
Address CodeRabbit review on the live-lookup change:

- Resolve the redirect URI live in LoginURL and return it so the caller
  persists it in the session; ExchangeOIDCToken reuses that stored value
  instead of resolving again. The token exchange redirect_uri must match
  the one in the auth request (RFC 6749 4.1.3); resolving twice would let
  a Root URL change between login and callback produce a mismatch the IdP
  rejects.
- Propagate the redirect URL resolution error out of LoginURL rather
  than discarding it, so a setting read failure fails the login loudly
  instead of sending an empty redirect_uri.
- Pass rootURL as a formatting argument in oidc.RedirectURL instead of
  concatenating it into the format string, so a root URL containing a
  %-sequence (e.g. %2F) is not interpreted as a verb.
2026-08-29 11:51:43 +02:00
malpou 02e9d1d3bf oidc: resolve redirect URL live so Root URL changes without a restart
Auth providers captured the redirect URL as a string at build time, so
changing app.root_url in General settings left OIDC providers sending
the old redirect_uri until the process restarted. The identity provider
then rejected login with "redirect_uri is missing in the client
configuration" even though the database and the IdP client both held the
right value.

Make auth.Provider.RedirectURL a closure and resolve it in LoginURL and
ExchangeOIDCToken from the current root URL, matching the media store's
existing rootURL closure. The redirect URL is computed by a new
oidc.Manager.RedirectURL(id) helper so the path format stays in one
place. Other provider fields (client ID, provider URL) remain snapshotted
and are refreshed by reloadAuth on OIDC changes, as before.

This removes the reload requirement for Root URL entirely; the settings
handler no longer needs to know that auth depends on it.
2026-08-29 11:32:28 +02:00
Abhinav Raut 3da864b5dd remove comments that narrate rejected designs 2026-08-20 19:11:02 +05:30
Abhinav Raut c865748ca5 switch to Geist and cache help center pages
Geist replaces Instrument Sans and is served from static/ instead of Google
Fonts, so it works on installs with no internet access.

Public help center pages are cached in Redis via fastcache with ETags, and any
admin write clears the group so edits show up on the next load.
2026-08-20 18:01:42 +05:30
Abhinav Raut 048eb1acd5 add page template setting for help center with docs and classic layouts
Help centers now have a template setting with two layouts. Classic is
the default: the existing hero banner, large search bar and collection
cards. Docs is new: sticky top bar, collections sidebar on every page,
command palette search (Ctrl+K) with a no-JS fallback form, and an
on-page table of contents.

Backend adds a template column (default 'classic', checked to the two
values), threads it through insert/update queries and the request
validator, and resolves page template names as '<template>-<page>' when
rendering public pages. Docs pages also get the published tree for the
sidebar.

Public templates are restructured so each layout is fully isolated and
a third template is just a new directory plus its CSS file:
web-templates/help/shared/ holds the head, announcement, lang switcher,
icons and shared JS; help/classic/ and help/docs/ each hold their own
layout and five pages. The classic stylesheet is renamed to
help-center-classic.css so the head links help-center-<template>.css
directly. Template parsing now globs the help/ subdirectories too.

The admin create and edit forms get a template picker, and classic-only
styling fields (header background, collection layout, card icons) are
hidden when docs is selected.
2026-08-09 17:40:52 +05:30
Abhinav Raut aa54bfa48d fix slug, locale, theme and embedding bugs in help center
Batch of fixes from a review of the help-center branch.

Slugs. A long title made a slug longer than the 200 char cap, so the
save failed with a slug error on a form that has no slug field. The
"-2" dedup suffix could also push a slug past the cap after validation
ran, which locked the article out of every later edit. Slug generation
now truncates to fit, and collections get the same dedup pass articles
already had. Accented titles kept losing letters, so accents now fold
to their ASCII base. Titles in scripts with no ASCII form still fall
back to a random slug.

Locales. Removing a language from a help center stranded its
collections and articles. They had no admin UI path and no public URL,
but stayed in the AI index. Dropping a language that still holds
content is now rejected. Only languages the help center allows today
are checked, so an existing orphan can still be saved.

Theme. The luminance check only parsed 3 and 6 digit hex while the
sanitizer accepts 4 and 8 digit too, so an 8 digit header colour fell
back to dark text on a dark header. The free text colour fields had no
validation, so a bad value was silently thrown away on save while the
toast said it worked. The article editor was missing --hc-accent-ink,
which made button links invisible while editing.

Embeddings. The chunker changed the text it emits but the fingerprint
did not change, so nothing already indexed was ever re-chunked. The
chunker version now feeds the fingerprint. Deleting a collection or a
help center left the cascaded articles' vectors behind until the next
sweep, so those now clean up on delete.

Public API. The public JSON endpoints returned author name and avatar
even when the theme had authors turned off.

Media and search. Anonymous /uploads requests now hit a rate limit
before the DB lookup, and served files carry a one day cache header.
S3 redirects are no-store because a presigned URL expires. Public
search now enforces the same two character floor the typeahead uses,
so a one character query cannot seq-scan every article body.
2026-08-08 23:24:05 +05:30
Abhinav Raut 608910692a add live search suggestions and card icon layouts to help center
The search box now shows matching articles as you type, and you can pick
one with the arrow keys. Cards get an icon position setting (beside the
title, above it, or centered) and old search logs are cleaned up daily.
2026-08-02 13:07:29 +05:30
Abhinav Raut 6aa221a4fc merge origin/main into help-center
Resolved the AI embedding conflicts by keeping this branch's generic embedSource path and layering main's tag indexing on top. Search now covers snippets and help articles, tags stay excluded. Dropped SetContentID since main's link-message-media query stamps content_id itself.
2026-08-01 11:47:59 +05:30
Abhinav Raut 7b69690394 add SEO, localization, and drag reordering to the help center
Public pages were missing most of what a search engine needs. They now serve
a sitemap index at /sitemap.xml plus a robots.txt, and every page carries a
canonical URL, hreflang alternates, an x-default, and JSON-LD. Article pages
also send published and modified times. Search pages and the markdown view
are marked noindex. Requests from bots no longer bump the view counters, so
the insights numbers reflect real readers. Offscreen images in articles are
lazy loaded.

Public page text is now translated per locale instead of always using the
desk language, and pages with more than one translation show a language
switcher.

In the admin, collections and articles can be dragged to reorder, and an
article can be dragged into a different collection. Both save through new
sort order endpoints. Collections can have a lucide icon, picked from a new
icon picker backed by a sprite sheet. The landing page has layout options
for card grid or one per row, cards per row, and which details to show.

The help center list is a data table now, so HelpCenterCard is gone. The
tree page moved into AdminSplitLayout, its actions sit on their own row
below the breadcrumb, and it gained visit site and expand/collapse all.
2026-08-01 10:32:52 +05:30
Abhinav Raut 95b9993ea5 fall back to english for untranslated backend strings 2026-07-31 18:14:51 +05:30
Abhinav Raut 38983f173d Merge remote-tracking branch 'origin/main' into help-center
# Conflicts:
#	frontend/apps/main/src/features/contact/ContactNotes.vue
2026-07-30 01:15:21 +05:30
Abhinav Raut 49c5cb3493 make AI agent max steps and history size configurable
Two AI agent limits were hardcoded in Go: the tool-calling budget per reply
(6) and the number of conversation messages sent to the model as history
(30). Large installs need to tune these, so both are now read from
config.toml as ai_agent.max_steps and ai_agent.max_history_messages.

Defaults are unchanged, so an install that does not set the keys behaves
exactly as before. Values are clamped at the config read layer, 1-20 for
max_steps and 5-100 for history, so a typo cannot burn tokens on a runaway
loop or drop the model's context to nothing.

Also drop the dead re-slice in buildHistory. The message fetch already
limits to max_history_messages and the filter above it only removes
messages, so the second clamp could never fire.
2026-07-25 17:16:59 +05:30
Abhinav Raut baff30fc28 add help center with public pages, admin management and AI article indexing
Agents can now publish a public knowledge base per help center.

Backend:
- new internal/helpcenter package for help centers, collections and articles
- admin JSON API behind a new help_center:manage permission
- public /hc/{slug} pages, JSON API, search and sitemap, all rate limited
- migration v2.7.0 for the new tables

AI:
- published articles with the AI flag on get embedded, so the agent answers
  from them. Unpublishing or clearing the flag removes the embeddings.

Media:
- media rows now carry a private flag. Help article images are public so the
  public pages can serve them without auth, and only agents with
  help_center:manage can upload them.

Frontend:
- admin help center list, tree view and article editor
- the old TextEditor is split into ArticleEditor and ConversationEditor over a
  shared useTextEditor composable, so article-only tools like callouts,
  collapsibles and YouTube embeds stay out of the reply box
2026-07-25 14:19:38 +05:30
Abhinav Raut 6125f5ced0 harden AI agent knowledge base, OTP, and prompt injection defenses
Knowledge base: fold the embedding provider base URL into the snippet
fingerprint so re-pointing the provider triggers a reindex even when the
model name is unchanged. Reject empty knowledge base content. Cap
concurrent background snippet embeds at 4 and tie embedding work to the
app lifecycle context. Reindex when the embedding base URL changes, not
just the model or dimensions.

Prompt injection: neutralize << >> block delimiters in snippets,
transcripts, subjects, and contact fields so untrusted content can't
forge a boundary the model relies on.

OTP: set the verified flag inside the Lua match script so verification
is atomic. Only count codes that were actually emailed toward the resend
cap, and check the cap before sending instead of incrementing up front.

Tools: fetch only the enabled tools among the allowed IDs, and route all
registrations through one helper so custom tools can't shadow built-ins.

Agent queue: hand a dropped response job off to a human instead of
leaving the conversation assigned to the assistant with no reply.

Also let GetAllConversationMessages return every message when limit is
non-positive, populate admin forms without triggering validation, and
default the copilot name to Juno.
2026-07-22 14:56:49 +05:30
Abhinav Raut ea03339b0d address CodeRabbit review findings in the AI agent
Drop the deprecated webhook.allowed_hosts fallback from the SSRF setup.
It appended hostnames to allowed_cidrs, which only parses CIDRs, so those
entries were silently dropped anyway. Read the [ssrf] block only.

Link AI assistant messages to the specific assistant. postReply now stamps
the assistant id into the message meta, and the message bubble links to that
assistant's edit page, falling back to the assistants list for older messages
that lack the id.
2026-07-21 11:02:43 +05:30
Abhinav Raut bfc3b6e196 gate AI custom tools behind email OTP verification
Custom tools can now require a verified contact before they run. This gives tools a trustworthy signal about who the customer is without relying on DMARC or the JWT login.

ai_tools gets a requires_verification column, defaulting to true (fail-closed). A flagged tool is blocked in httpTool.Execute until the conversation is verified, and every tool call now carries an X-Libredesk-Contact-Verified header so tool authors can tell an OTP-verified contact from a self-claimed one.

The AI agent gets three native tools: send_email_verification emails a 6-digit code out of band, check_email_verification confirms it, and set_contact_email lets an anonymous visitor add an email to send the code to. Codes and the verified window live in Redis, scoped per conversation, with attempt and resend caps. JWT livechat contacts stay trusted without OTP; email contacts and visitors verify by code.

The tool admin form gets a "require verified contact" toggle (default on) with a confirm dialog when turning it off.
2026-07-20 17:48:41 +05:30
Abhinav Raut 9566dcbf4d apply SSRF guard to all admin-configured outbound URLs
Move the webhook SSRF guard into a shared internal/ssrf package and wire it
into every place the server fetches an admin-set URL: webhooks, OIDC discovery,
the AI provider base URL, and custom AI tool calls. Add a global [ssrf] config
block, off by default with an allowed_cidrs bypass, so single-tenant self-hosters
keep reaching internal hosts while multi-tenant or hosted deploys can turn it on.
The old [webhook] allowed_hosts key is still read for backward compat and folds
into the guard.
2026-07-16 12:58:12 +05:30
Abhinav Raut 7186c95e40 add WIP autonomous AI agent that replies to assigned conversations
Medium (title + short body):
add WIP autonomous AI agent

New internal/aiagent package runs AI assistants that reply to customers
on conversations assigned to them, grounded on a knowledge base. Also mines
resolved conversations for FAQ suggestions. Adds admin UI and the v2.7.0
schema. Still work in progress.
2026-07-11 04:54:49 +05:30
Abhinav Raut 0ecd783941 add AI copilot backed by a knowledge base and custom tools
Adds two agent-facing AI features: a copilot chat panel in the conversation
sidebar and a generate-reply button in the reply box. Both run an agentic
tool-calling loop whose first tool searches the knowledge base.

Snippets are chunked and embedded on save, then searched in memory with
brute-force cosine similarity (no pgvector). Providers are split into completion
and embedding types. Both are OpenAI-compatible and the API key is encrypted at
rest. Admins can also register custom HTTP tools the model can call.

A new admin AI settings page covers provider config, snippets, and tools. The
v2.6.0 migration and schema add the ai_knowledge_base, embeddings, and ai_tools
tables plus the ai_providers type column.
2026-07-10 15:51:27 +05:30
Abhinav Raut f987224cee perf: avoid DB lookups when building email From name 2026-06-07 14:45:51 +05:30
Abhinav Raut 1fccfceb4c feat: add customisable From display name template for outgoing emails
Adds a from_name_template field to email inboxes. When set and the sender is an agent, the template renders with agent and inbox variables and becomes the From display name; the inbox email address is unchanged. Any render failure, or a system-user sender, falls back to the plain inbox From so a misconfigured template never blocks delivery.

Variables: .Agent.FirstName, .Agent.LastName, .Agent.FullName, .Inbox.Name (the inbox name). Based on #249.

Co-authored-by: josephsellers <6892567+josephsellers@users.noreply.github.com>
2026-06-07 14:20:56 +05:30
Abhinav Raut 29881f2f82 fix: close ws stale-perm gaps and resub on reconnect
Reject disabled agents in FilterAuthorizedListUUIDs, kick role members on
permission removal or role delete, and re-sub the list and open conv on
ws reconnect using local state. Also plug the app logger into the ws
package so kicks no longer log when no connections exist.
2026-05-28 20:07:19 +05:30
Abhinav Raut dd6c8f93a0 add conversation.subject_ref_format config for customizing outgoing email subject marker 2026-04-23 03:11:36 +05:30
Abhinav Raut 2d3958fe49 Merge pull request #294 from abhinavxd/more-view-filters
More fields in view filters.
2026-04-21 21:18:38 +05:30
Abhinav Raut 15021bf22b Make session lifetime configurable 2026-04-21 20:27:40 +05:30
Abhinav Raut 5bbd0f7c8d Increase default rate limits 2026-04-21 18:06:52 +05:30
Abhinav Raut 785c989a6b Flatten continuity config into [conversation] as continuity_scan_interval 2026-04-17 00:03:37 +05:30
Abhinav Raut de740245c1 Simplify custom static dir to single mapping that mirrors built-in static/ structure 2026-04-09 00:24:05 +05:30
Abhinav Raut 88a58c0f3b Custom static directory support, self hosted installations can pass static dir path to override csat and other web-templates, js and css files. Allowing instances to be fully customizable.
- New meta JSONB field in CSAT responses to capture random adhoc data as that might be needed for custom CSAT pages.
- Add support prefilled rating for csat pages picked from query param
2026-04-09 00:04:00 +05:30
Abhinav Raut 6abb6ad017 Move continuity config and intervals to live chat inbox form from toml.
- Refactor widget.js.
- Fix possible race conditions in inbox reload logic.
- Reload only the updated inbox when an inbox is updated / created not all.
- Retain last inbox while navigatin back from admin -> inbox
2026-04-04 21:35:04 +05:30
Abhinav Raut 73ea8741a2 Fix dev backend failing to start without the frontend being built. 2026-04-04 18:40:52 +05:30
Abhinav Raut 9610c15603 Simplify notification toggle check 2026-03-30 18:51:58 +05:30
Abhinav Raut 13db8d2843 Fix command palette macros not working due to previous variable rename causing issues.
Improve sidebar navigation to retain open conversation

Fix notification when disabled app still tries sending emails.
2026-03-30 18:51:23 +05:30
Abhinav Raut b1bef238cf Feat: context links, context links allow admins to set urls to external system from sidebar with encrypted payload in query parameters. 2026-03-30 16:00:37 +05:30
Abhinav Raut fb3ab68ef6 Sign avatar URLs in widget WS broadcasts, add CORS for launcher settings 2026-03-29 19:08:09 +05:30
Abhinav Raut 48175300ab Add rate limiting to public endpoints (auth, CSAT), fix rate limiter race condition and missing Content-Type header. Refactor rateLimitWidget into generic rateLimit middleware with config defaults. 2026-03-22 16:59:55 +05:30
Abhinav Raut eb0a7b437d Add page visit tracking to widget
- fix duplicate initialization guard
- notification bell for agents
- Refactor and clean up dead code
- Fixes to pre chat form
- Add new column country to users table
- Update ratelimit pkg to be generic
2026-03-11 03:52:07 +05:30
Abhinav Raut 4eb5dce12c Merge branch 'main' into feat/live-chat-channel 2026-02-22 15:13:36 +05:30
Abhinav Raut 727213631c SSRF protection to webhooks
- New config webhook option to allow certain CIDR ranges in webhooks.
2026-02-16 02:40:05 +05:30
Abhinav Raut 107f1adb0d fix issues with threading with widget messages
- fix: live chat email inbox not being initialized.
- make launcher logo take entire launcher space.
- New columns last_interaction_sender_id and last_message_sender_id to track who sent last message in conversation
2026-01-18 13:47:07 +05:30
Abhinav Raut 2421b964b7 fix merge conflcits 2026-01-14 15:53:15 +05:30
Abhinav Raut 7958d7e212 Merge branch 'main' into feat/live-chat-channel 2026-01-14 00:33:51 +05:30
Abhinav Raut 173493a0ed handle panics in importer, translate messages and fix bugs 2026-01-09 03:26:22 +05:30
Abhinav Raut 91445d7dda Merge branch 'main' into feat-notifications 2026-01-09 01:06:34 +05:30
Abhinav Raut a8fee6d9db feat: notification dispatcher for handling in-app, WS, and email notifications centrally 2026-01-06 12:27:29 +05:30
Abhinav Raut 3c908178e1 set default expiry for fs signed urls to 1 hr.
- remove double media fetch from db
2026-01-05 15:57:43 +05:30
Abhinav Raut 902158b1b8 feat: implement signed URL support for filesystem media access 2026-01-02 14:04:45 +05:30
Abhinav Raut 4bab16c21a feat: user app notification system with bell icon in the sidebar
- notifications for: mention', 'assignment', 'sla_warning', 'sla_breach'
- new table `user_notifications` and migrations for the same.
2026-01-02 01:46:47 +05:30
Abhinav Raut 2468b91c8e translate oauth changes in email inbox form
- log warnings when sample encryption key is used for libredesk and when encrytion key is not 32 chars
2025-12-26 04:10:04 +05:30