Commit Graph

4946 Commits

Author SHA1 Message Date
ConnorYoh
801cc8a5f4 Alpha flag for file storage settings (#6044)
## Summary
- Added "Alpha" badge to the File Storage & Sharing nav item in the
settings sidebar
- Added "Alpha" badge to the File Storage & Sharing page title
- Removed the old inline "(Alpha)" text from the Enable Group Signing
label
- Restructured all toggle cards so the switch is anchored to the right
of each row
- Tightened spacing between cards for a more compact layout
- Extended `ConfigNavItem` interface with optional `badge` and
`badgeColor` fields for reuse elsewhere
<img width="1696" height="1057" alt="image"
src="https://github.com/user-attachments/assets/77ac8276-ed65-4cae-8470-65de8f56dd74"
/>
2026-04-01 17:18:48 +01:00
EthanHealy01
74153b6deb Bug/connection mode fixes (#5998) 2026-04-01 15:33:46 +01:00
Anthony Stirling
ecd1d3cad3 fix new line in redact (#6035) 2026-04-01 11:58:38 +01:00
Anthony Stirling
0a098cf7b7 idle cpu fix test (#6015) 2026-04-01 11:58:10 +01:00
Anthony Stirling
cfa8d1e5d7 qr split fixes (#6043) 2026-04-01 11:54:33 +01:00
Anthony Stirling
5ffa808c0f Remove gosu (#6036) 2026-04-01 11:54:12 +01:00
Matheus Saito
212f12a81f Added back ctrl+r as rotate if on desktop (#5982) (#5993)
Fix #5982

Behaviour of ctrl+r altered to support rotate on desktop, while the web
version continue to use refresh as default.
2026-04-01 11:48:53 +01:00
James Brunton
c31e4253dd Fix any type usage in proprietary/ (#5949)
# Description of Changes
Follow on from #5934, expanding `any` type usage ban to the
`proprietary/` folder
2026-04-01 08:21:26 +00:00
Peter Dave Hello
a96b95e198 Update and improve zh-TW Traditional Chinese locale (#6034) 2026-03-30 21:10:49 +01:00
Anthony Stirling
a06b6a4bac pdf layer toggle (#6028) 2026-03-30 17:04:53 +01:00
Anthony Stirling
cdc288e78d nonpdf-viewer (#6024)
Co-authored-by: a <a>
2026-03-30 16:39:11 +01:00
Anthony Stirling
82a3b8c770 Unlock account (#5984) 2026-03-30 16:07:57 +01:00
ConnorYoh
1e97a32d4b feat(desktop): gate shared signing behind self-hosted auth (#6002)
## Summary

This PR adds full desktop (Tauri) support for the shared signing feature
when connected to a self-hosted server, and fixes several bugs
discovered during that work.

### Feature gating

Shared signing, file sharing, and share links are proprietary server
features that require an authenticated self-hosted session. Previously
these were read directly from `config` with no awareness of connection
mode or auth state, meaning the UI could appear in SaaS/local mode or
when logged out.

- Introduce `useGroupSigningEnabled` and `useSharingEnabled` hooks with
core implementations (web behaviour unchanged) and desktop overrides
that require `selfhosted` mode + an active authenticated session
- Extract shared subscription logic into `useSelfHostedAuth` (connection
mode + auth state + config refetch)
- `QuickAccessBar` now derives all three flags from the hooks instead of
raw config

### Config timing fix

When a user logs in via the SetupWizard, the `jwt-available` event fires
a config fetch *before* the mode is switched to `selfhosted`. This meant
the config was fetched from the local bundled backend (port ~59567)
which has no knowledge of `storageGroupSigningEnabled`, causing the
group signing button to stay hidden until a full page refresh.
`useSelfHostedAuth` detects the mode transition and triggers a fresh
config fetch at the correct moment, after the self-hosted URL is active.

### Bug fixes

**`SignPopout.tsx`** — Manually setting `Content-Type:
multipart/form-data` on two `FormData` POST requests stripped the
auto-generated boundary, causing a `400 bad multipart` from the server.
Removed the explicit headers so Axios sets them correctly.

**`tauriHttpClient.ts`** — `response.json()` was called before
`response.ok` was checked. A plain-text error body from the server (e.g.
`"Cannot sign..."`) caused a `SyntaxError` that fell into the network
error catch block and was reported as `ERR_NETWORK`, hiding the real
failure. The fix checks `response.ok` first, reads error bodies as text,
and handles empty 200 bodies (returning `null` instead of throwing).

---

## Testing

### Prerequisites
- Desktop app running in self-hosted mode pointed at a local
Stirling-PDF instance (`http://localhost:8080`)
- The self-hosted instance has group signing and storage enabled in
settings
- At least two user accounts on the self-hosted instance

### 1. Feature gating — group signing button

| Step | Expected |
|---|---|
| Open the desktop app in **local mode** (no server configured) | Group
signing button absent from QuickAccessBar |
| Switch to self-hosted mode but **do not log in** | Group signing
button absent |
| Log in to the self-hosted server | Group signing button appears
without requiring a page refresh |
| Log out | Group signing button disappears immediately |
| Log back in | Group signing button reappears without a page refresh |

### 2. Feature gating — file sharing

Repeat the same steps above, verifying the share and share-link buttons
in the file manager follow the same visibility rules.

### 3. Create a signing session

1. Log in, open the group signing panel from QuickAccessBar
2. Select a PDF, add a participant, configure signature defaults and
submit
3. Verify the session is created successfully (no `400 bad multipart`
error)

### 4. Participant signing

1. As the invited participant, open the signing request from
QuickAccessBar
2. Upload or draw a signature and submit
3. Verify signing completes successfully (no `ERR_NETWORK` error)

### 5. Error surfacing

1. Attempt an action that the server rejects (e.g. sign a document with
an invalid certificate)
2. Verify the actual server error message is shown rather than a generic
network error
2026-03-30 14:37:45 +00:00
James Brunton
4a6b426651 Only allow Tauri imports in the desktop app (#5995)
# Description of Changes
Adds an eslint rule to disallow importing any Tauri APIs outside the
desktop folder to help hint to developers that they should be following
the frontend architecture.

While doing this, I also discovered that you can provide a custom
message in the `no-restricted-imports` rule, which is nicer than the
comments that I'd previously added to the eslint config file to explain
why they weren't allowed:

```text
/Users/jamesbrunton/Dev/spdf1/frontend/src/core/components/shared/config/configSections/GeneralSection.tsx
  19:1  error  'src/core/contexts/PreferencesContext' import is restricted from being used by a pattern. Use @app/* imports instead of absolute src/ imports              no-restricted-imports
  20:1  error  '../../../../../core/contexts/AppConfigContext' import is restricted from being used by a pattern. Use @app/* imports instead of relative imports          no-restricted-imports
  21:1  error  '@tauri-apps/core' import is restricted from being used by a pattern. Tauri APIs are desktop-only. Review frontend/DeveloperGuide.md for structure advice  no-restricted-imports
```
2026-03-30 14:24:16 +00:00
ConnorYoh
0e29640766 fix: get all Playwright E2E tests loading and expand CI to run full suite (#6009)
## Fix Playwright E2E tests and expand CI to run full suite

### Problem

The full Playwright suite was broken in two ways:

1. **`ConvertE2E.spec.ts` crashed at import time** —
`conversionEndpointDiscovery.ts` imported a React hook at the top level,
which pulled in the entire component tree. That chain eventually
required `material-symbols-icons.json` (a generated file that didn't
exist), crashing module resolution before any tests ran.

2. **CI only ran cert validation tests** — both `build.yml` and
`nightly.yml` hardcoded `src/core/tests/certValidation` as the test
path, silently ignoring everything else.

### Changes

**`ConvertE2E.spec.ts` — complete rewrite**
The old tests were useless in practice: all 9 dynamic conversion tests
were permanently skipped unless a real Spring Boot backend was running
(they called a live `/api/v1/config/endpoints-enabled` endpoint at
module load time). Replaced with 4 focused tests that use `page.route()`
mocking — no backend required, same pattern as
`CertificateValidationE2E`.

New tests cover:
- Convert button absent before a format pair is selected
- Successful PDF→PNG conversion shows a download button (mocked API
response)
- API error surfaces as an error notification
- Convert button appears and is enabled after selecting valid formats

**`conversionEndpointDiscovery.ts` — deleted**
Only existed to support the old tests. The `useConversionEndpoints`
React hook it exported was never imported anywhere else.

**`ReviewToolStep.tsx`**
Added `data-testid="download-result-button"` to the download button —
required for the happy-path test assertion.

**CI workflows (`build.yml`, `nightly.yml`)**
- Added a `Generate icons` step before Playwright runs (`node
scripts/generate-icons.js`) — the icon JSON is generated by `npm run
dev` locally but skipped by `npm ci` in CI
- Removed the `src/core/tests/certValidation` path filter so the full
suite runs
2026-03-30 11:27:55 +01:00
albanobattistella
05b4255751 Update Italian translations (#6014) 2026-03-30 11:04:11 +01:00
dependabot[bot]
1ab07a9027 build(deps): bump crazy-max/ghaction-github-labeler from 5.3.0 to 6.0.0 (#6019)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 11:03:11 +01:00
dependabot[bot]
75421b4223 build(deps): bump qrcode from 8.0 to 8.2 in /testing/cucumber (#6022)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 11:02:30 +01:00
dependabot[bot]
a7fe4e9a76 build(deps): bump pypdf from 6.7.5 to 6.9.2 in /testing/cucumber (#6020)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 11:02:12 +01:00
dependabot[bot]
10ab2872f6 build(deps): bump requests from 2.32.5 to 2.33.0 in /testing/cucumber (#6017)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 11:01:56 +01:00
Anthony Stirling
2fdc9c112f test reports for test.sh and fix test.sh deployments (#6027) 2026-03-29 23:35:45 +01:00
ConnorYoh
dd44de349c Shared Sign Cert Validation (#5996)
## PR: Certificate Pre-Validation for Document Signing

### Problem

When a participant uploaded a certificate to sign a document, there was
no validation at submission time. If the certificate had the wrong
password, was expired, or was incompatible with the signing algorithm,
the error only surfaced during **finalization** — potentially days
later, after all other participants had signed. At that point the
session is stuck with no way to recover.

Additionally, `buildKeystore` in the finalization service only
recognised `"P12"` as a cert type, causing a `400 Invalid certificate
type: PKCS12` error when the **owner** signed using the standard
`PKCS12` identifier.

---

### What this PR does

#### Backend — Certificate pre-validation service

Adds `CertificateSubmissionValidator`, which validates a keystore before
it is stored by:
1. Loading the keystore with the provided password (catches wrong
password / corrupt file)
2. Checking the certificate's validity dates (catches expired and
not-yet-valid certs)
3. Test-signing a blank PDF using the same `PdfSigningService` code path
as finalization (catches algorithm incompatibilities)

This runs on both the participant submission endpoint
(`WorkflowParticipantController`) and the owner signing endpoint
(`SigningSessionController`), so both flows are protected.

#### Backend — Bug fix

`SigningFinalizationService.buildKeystore` now accepts `"PKCS12"` and
`"PFX"` as aliases for `"P12"`, consistent with how the validator
already handles them. This fixes a `400` error when the owner signed
using the `PKCS12` cert type.

#### Frontend — Real-time validation feedback

`ParticipantView` gains a debounced validation call (600ms) triggered
whenever the cert file or password changes. The UI shows:
- A spinner while validating
- Green "Certificate valid until [date] · [subject name]" on success
- Red error message on failure (wrong password, expired, not yet valid)
- The submit button is disabled while validation is in flight

#### Tests — Three layers

| Layer | File | Coverage |
|---|---|---|
| Service unit | `CertificateSubmissionValidatorTest` | 11 tests — valid
P12/JKS, wrong password, corrupt bytes, expired, not-yet-valid, signing
failure, cert type aliases |
| Controller unit | `WorkflowParticipantValidateCertificateTest` | 4
tests — valid cert, invalid cert, missing file, invalid token |
| Controller integration | `CertificateValidationIntegrationTest` | 6
tests — real `.p12`/`.jks` files through the full controller → validator
stack |
| Frontend E2E | `CertificateValidationE2E.spec.ts` | 7 Playwright tests
— all feedback states, button behaviour, SERVER type bypass |

#### CI

- **PR**: Playwright runs on chromium when frontend files change (~2-3
min)
- **Nightly / on-demand**: All three browsers (chromium, firefox,
webkit) at 2 AM UTC, also manually triggerable via `workflow_dispatch`
2026-03-27 14:01:10 +00:00
James Brunton
e10c5f6283 Redesign Python AI engine (#5991)
# Description of Changes
Redesign the Python AI engine to be properly agentic and make use of
`pydantic-ai` instead of `langchain` for correctness and ergonomics.
This should be a good foundation for us to build our AI engine on going
forwards.
2026-03-26 10:35:47 +00:00
Anthony Stirling
9500acd69f Base docker image (#5958)
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-25 15:41:58 +00:00
Anthony Stirling
bb43e9dcdf dark mode PDF filter init (#5994)
Co-authored-by: a <a>
2026-03-25 15:38:42 +00:00
Anthony Stirling
28613caf8a fileshare (#5414)
Co-authored-by: ConnorYoh <40631091+ConnorYoh@users.noreply.github.com>
Co-authored-by: Connor Yoh <con.yoh13@gmail.com>
Co-authored-by: EthanHealy01 <80844253+EthanHealy01@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-03-25 11:00:40 +00:00
Rafael Roseira Machado
47cad0a131 fix pause-rounded icon typos and comments (#5992) v2.8.0 2026-03-24 18:56:51 +00:00
stirlingbot[bot]
4858608162 🤖 format everything with pre-commit by stirlingbot (#5946)
Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2026-03-24 18:55:37 +00:00
OUNZAR Aymane
a1f03c844b Enhance multi-page PDF layout with advanced customization options (#397, #3655) (#5859)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-24 17:27:56 +00:00
InstaZDLL
8bbfbd63d7 feat(security): add RFC 3161 PDF timestamp tool (#5855)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2026-03-24 17:00:33 +00:00
Anthony Stirling
7b3985e34a FileReadiness (#5985) 2026-03-24 15:25:33 +00:00
Anthony Stirling
f03f0d4adb junits (#5988) 2026-03-24 14:12:31 +00:00
Anthony Stirling
c3fc200c5d Remove images (#5966) 2026-03-24 14:11:27 +00:00
brios
c3530024c4 feat(pdf): replace PdfLib with Pdfium for form handling and general rendering tasks (#5899)
# Description of Changes

Improves PDF rendering in the viewer by adding digital signature field
support,
cleaning up overlay rendering, and migrating the contrast tool off
pdf-lib to PDFium WASM.

### Signature Field Overlay
- Added `SignatureFieldOverlay` component that renders digital signature
form fields
- Renders appearance streams when present; shows a fallback badge for
unsigned fields
- Uses PDFium WASM for bitmap extraction

### Overlay Rendering
- Integrated `SignatureFieldOverlay` and `ButtonAppearanceOverlay` into
`LocalEmbedPDF`
- Overlays are now clipped to page boundaries
- Clarified in `EmbedPdfViewer` that frontend overlays use PDFium WASM,
  backend overlays use PDFBox

### Contrast Tool Migration
- Replaced pdf-lib with PDFium WASM in `useAdjustContrastOperation`
- PDF page creation and image embedding now go through PDFium APIs
directly
- Updated bitmap handling and memory management accordingly

### Cleanup
- Fixed import ordering in viewer components
- Removed stale comments in the contrast operation hook

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### Translations (if applicable)

- [ ] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
Co-authored-by: Reece Browne <74901996+reecebrowne@users.noreply.github.com>
2026-03-24 13:34:52 +00:00
Reece Browne
3ea11352e3 Fix/v2/text selection 2 (#5990) 2026-03-24 12:51:52 +00:00
brios
1276e5675e chore(deps): bump pdfbox version to 3.0.7 (#5923) 2026-03-23 19:44:05 +00:00
dependabot[bot]
81c4718954 build(deps): bump sigstore/cosign-installer from 4.0.0 to 4.1.0 (#5975)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 19:40:01 +00:00
dependabot[bot]
1806b5d3be build(deps): bump actions/cache from 5.0.3 to 5.0.4 (#5976)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 19:38:07 +00:00
dependabot[bot]
81c0187bf1 build(deps): bump softprops/action-gh-release from 2.5.0 to 2.6.1 (#5979)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 19:37:37 +00:00
dependabot[bot]
9d51414fbb build(deps): bump docker/setup-qemu-action from 3.7.0 to 4.0.0 (#5977)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 19:37:06 +00:00
EthanHealy01
2e2b55e87d Desktop/remove hard requirement auth wall on desktop (#5956)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 19:36:48 +00:00
ConnorYoh
081b1ec49e Invite-link-issues (#5983) 2026-03-23 19:35:41 +00:00
EthanHealy01
c46156f37f Bump/embed pdfv2.8.0 (#5921)
please merge #5919, alternatively, just push this and delete that PR
because this is a continuation of that.

This PR bumps the embed PDF version to 2.8.0 and also adds comments
functionaliy

---------

Co-authored-by: ConnorYoh <40631091+ConnorYoh@users.noreply.github.com>
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2026-03-23 14:35:39 +00:00
Reece Browne
41945543e0 Fix save converted files (#5971)
Fix saving converted files on tauri
2026-03-23 13:51:40 +00:00
James Brunton
e5f6180dbe Remove cmd-r override for rotation because it interferes with refresh (#5981)
# Description of Changes
Currently, cmd-r is set to rotate the PDF in the viewer instead of
perform refresh in the browser. This is unintuitive and confusing for
Mac users, and for Windows users (who are less used to doing ctrl-r for
refresh) it only works some of the time, if the Viewer is active, so
removing the override is no great loss.
2026-03-23 13:26:10 +00:00
James Brunton
57c810ab9a Add frontend developer guide describing the path alias architecture (#5964)
# Description of Changes
Add frontend developer guide describing the path alias architecture.
There's probably more needed in here which we should flesh out over
time, but this is a start.
2026-03-23 10:16:52 +00:00
brios
b012f18a40 fix(gradle): bump gradle jar version to 9.3.1-bin (#5938) 2026-03-20 12:00:01 +00:00
Anthony Stirling
9e8606cab4 XSS for eml and others (#5967) 2026-03-20 11:55:23 +00:00
Achieve3318
55bcb92810 Add explicit Save As button for desktop viewer (issue #5928) (#5959)
## Description

Adds an explicit **“Save As”** button to the desktop viewer so users can
always save a copy of the current PDF to a different location, even if
the original file already has a local path.

This complements the existing smart **Save/Download** behavior:
- The existing download button continues to either save back to the
original path (when available) or prompt for a path when needed.
- The new **Save As** button always opens a save dialog to choose a
location/name for a new copy.

## Changes

- **RightRail (viewer controls)**
- Added a new **Save As** action icon in the right rail settings
section.
  - The button:
- Uses `viewerContext.exportActions.saveAsCopy()` to get the current
viewer state as a PDF.
- Calls `downloadFile` without a `localPath`, ensuring the desktop app
shows a **Save As** dialog.
- Picks the first selected file (if any) or the first active file as the
source for the filename.
- **Desktop / Web behavior**
  - In the desktop app (Tauri), clicking **Save As**:
- Opens a native save dialog so the user can choose a different folder
and filename.
- Writes a new copy without changing the existing file’s `localFilePath`
or dirty state.
- In the web app, the button behaves like a standard download of a copy
(browser-controlled save dialog / download).

## Motivation

- Users often want to apply operations on a PDF while **keeping the
original unmodified**.
- The existing smart Save behavior chooses between Save and Save As
automatically, but there was no way to explicitly request **Save As**.
- This change gives desktop users a clear, dedicated **“Save As”**
control while preserving the current Save/Download behavior.

## Notes

- No backend changes.
- No changes to the existing Save / Download button behavior.
- The new button uses existing viewer export and download utilities,
minimizing new logic.

---------

Co-authored-by: James Brunton <james@stirlingpdf.com>
2026-03-20 09:32:24 +00:00
Aarón Rosa Díaz
a7f2abcb22 Update Spanish translation (translation.toml) (#5965) 2026-03-19 17:15:42 +00:00