314 Commits

Author SHA1 Message Date
Andrey Antukh
405a73e8ba
Add climit impl and config for file snapshot methods (#9722)
*  Add dedicated concurrency limit for restore-file-snapshot

This adds a dedicated climit configuration for the restore-file-snapshot
RPC method with :permits 1 per profile (plus queue of 2 and 60s timeout)
and a global limit of 3. Previously the method only used the generic
root/by-profile and root/global limits, allowing up to 7 concurrent
restore operations per profile which caused database row lock contention
on FOR UPDATE and connection pool exhaustion.

*  Skip locking on restore! to avoid blocking other operations

Changes the row lock acquisition in restore! from a blocking FOR UPDATE
to FOR UPDATE SKIP LOCKED. If the file row is already locked by another
concurrent operation (e.g., another restore or an update-file), the query
returns no rows and the caller fails fast with a clear conflict error
instead of blocking indefinitely holding a database connection.

*  Add queue and timeout limits to root/by-profile concurrency limit

Previously root/by-profile had no queue limit (unbounded Integer/MAX_VALUE)
and no timeout, allowing requests to pile up indefinitely behind a profile
whose permits were exhausted by long-running operations. This could lead
to memory pressure and cascading failures. Now limited to 30 queued
requests with a 30-second timeout so excess requests fail fast.

*  Move backup snapshot creation outside restore transaction

The backup snapshot (fsnap/create!) is now created in its own short-lived
connection before the actual restore transaction begins. This ensures the
backup is persisted independently of the restore outcome and reduces the
restore transaction window.

The restore itself runs inside a db/tx-run! block with an optimistic
locking check: it reads the file with FOR UPDATE and compares its revn
against the value captured at backup time. If the file was edited
concurrently, the restore aborts with a conflict error to prevent data
loss.

Co-dependent with the SKIP LOCKED change in restore! — the FOR UPDATE
acquired here is in the same transaction as restore!, so the SKIP LOCKED
inside restore! correctly sees the row as unlocked (same transaction).

* ♻️ Remove unused private function get-minimal-file

The local get-minimal-file function in file_snapshots.clj is no longer
used since restore! switched to direct exec-one! with FOR UPDATE SKIP
LOCKED. The sql:get-minimal-file SQL constant is still used directly.

*  Add minor improvements on db connection management

* ♻️ Refactor create-file-snapshot to use explicit transaction management

Remove automatic transaction wrapping (`::db/transaction true`) and
pass `cfg` through the call chain instead of destructured `conn`.
Wrap `fsnap/create!` in an explicit `db/tx-run!` for clearer
transaction boundaries.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

*  Add dedicated concurrency limit for create-file-snapshot

This adds a dedicated climit configuration for the create-file-snapshot
RPC method with :permits 1 per profile (plus queue of 2 and 60s timeout)
and a global limit of 3. Previously the method only used the generic
root/by-profile and root/global limits, allowing up to 10 concurrent
snapshot creation operations per profile which could cause database
contention and connection pool exhaustion.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-05-19 14:30:44 +02:00
Andrey Antukh
9de25c5404
🐛 Fix incorrect content-type on doc endpoint response (#9681)
The /api/main/doc endpoint was returning HTML content with a
text/plain content-type header instead of text/html. This caused
browsers to render the response as plain text.

Added content-type: text/html; charset=utf-8 header to the
response in the doc handler and added a regression test to
verify the fix.

Closes #9680

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-05-18 12:54:16 +02:00
Andrey Antukh
ff23f786b4 🐛 Fix broken authentication on /assets handlers
- Add ::setup/props and ::db/pool to :app.http.assets/routes config
  so session renewal works correctly for asset requests.
- Add actoken/authz middleware to the assets middleware chain so
  access tokens are properly recognized.
- Add authenticated? helper that checks both ::session/profile-id
  and ::actoken/profile-id, fixing 401 errors when accessing
  protected assets with a valid access token.
- Add comprehensive test suite for assets auth scenarios.

Closes #9677

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-05-15 12:05:02 +02:00
Andrey Antukh
67d9567971
🐛 Prevent CSS injection vulnerability in font family names
Add a shared `schema:font-family` whitelist validator in
app.common.types.font that only allows letters, digits, spaces,
hyphens, underscores, and dots in font family names. Apply the schema
to create-font-variant and update-font RPC endpoints on the
backend, and add client-side validation in the dashboard fonts UI.
Include unit tests for the schema and integration tests for the RPC
handlers.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-05-14 13:46:02 +02:00
Andrey Antukh
947f6d392d
🎉 Add chunked upload support for font variants (#9551)
*  Add additional logging and validation for image upload

* 🎉 Add chunked upload support for font variants

Extend the font variant upload flow across frontend, backend, and common
to support the standardized chunked upload protocol.

**Backend:**
- Add \`:font-max-file-size\` config default (30 MiB) and schema entry
- Add \`validate-font-size!\` in \`media.clj\` (mirrors
  \`validate-media-size!\`, raises \`:font-max-file-size-reached\`)
- Extend \`schema:create-font-variant\` to accept either \`:data\`
  (legacy bytes or chunk-vector) or \`:uploads\` (new chunked session
  map), with a validator requiring exactly one
- Add \`prepare-font-data-from-uploads\`: assembles each chunked
  session via \`cmedia/assemble-chunks\`, validates type+size
- Add \`prepare-font-data-from-legacy\`: normalises legacy byte/chunk
  entries, writing to a tempfile (joining via SequenceInputStream),
  validates type+size
- Add structured logging ("init"/"end") with \`:size\`, \`:mtypes\`,
  and \`:elapsed\` in \`create-font-variant\`

**Frontend:**
- \`upload-blob-chunked\` accepts a per-caller \`:chunk-size\` option
- Add \`font-upload-chunk-size\` (10 MiB) and \`upload-font-variant\`
  fn that uploads each mtype as a separate chunked session
- \`on-upload*\` in dashboard fonts now calls \`upload-font-variant\`
  instead of issuing \`create-font-variant\` RPC directly
- \`process-upload\` stores raw ArrayBuffer instead of chunking
  client-side

**Common:**
- Replace \`"font/opentype"\` with \`"font/woff2"\` in \`font-types\`

**Tests:**
- 25 tests / 224 assertions covering all three upload paths (direct
  bytes, legacy chunk-vector, new chunked sessions), size validation,
  and media type validation

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* 📎 Add a script for check the commit format locally

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-05-12 18:30:19 +02:00
Andrey Antukh
7d4be33d4f 🎉 Add telemetry anonymous event collection (#9483)
* 🎉 Add telemetry anonymous event collection

Rewrite the audit logging subsystem to support three operating modes and
add anonymous telemetry event collection:

Modes:
- A (audit-log only): events persisted with full context
- B (audit-log + telemetry): same as A, plus events are collected for
  telemetry shipping
- C (telemetry-only): events stored anonymously with PII stripped,
  telemetry flag active, audit-log flag inactive

Audit system refactoring (app.loggers.audit):
- Replace qualified map keys (::audit/name etc.) with plain keywords
- Rename submit! -> submit, insert! -> insert, prepare-event ->
  prepare-rpc-event
- Add submit* as a lower-level public API
- Add process-event dispatch function that handles all three modes and
  webhooks in a single tx-run!
- Add :id to event schema (auto-generated if omitted)
- Add filter-telemetry-props: anonymises event props per event type.
  Keeps UUID/boolean/number values; for login/identify events preserves
  lang, auth-backend, email-domain; for navigate events preserves route,
  file-id, team-id, page-id; instance-start trigger passes through.
- Add filter-telemetry-context: retains only safe context keys.
  Backend: version, initiator, client-version, client-user-agent.
  Frontend: browser, os, locale, screen metrics, event-origin.
- Timestamps truncated to day precision via ct/truncate for telemetry
  storage
- PII stripped: props emptied, ip-addr zeroed, session-linking and
  access-token fields removed from context

Config (app.config):
- Derive :enable-telemetry flag from telemetry-enabled config option

Email utilities (app.email):
- Add email/clean and email/get-domain helper functions for domain
  extraction from email addresses

Setup (app.setup):
- Emit instance-start trigger event at system startup
- Simplify handle-instance-id (remove read-only check)

RPC layer (app.rpc):
- wrap-audit now activates when :telemetry flag is set
- Add :request-id to RPC params context for event correlation

RPC commands (management, teams_invitations, verify_token, OIDC auth,
webhooks): migrate all audit call sites to use the new plain-key API

SREPL (app.srepl.main):
- Migrate all audit/insert! calls to audit/insert with plain keys

Telemetry task (app.tasks.telemetry):
- Restructure legacy report into make-legacy-request; distinguish
  payload type as :telemetry-legacy-report
- Add collect-and-send-audit-events: loop fetching up to 10,000 rows
  per iteration, encodes and sends each page, deletes on success,
  stops immediately on failure for retry
- Add send-event-batch: POSTs fressian+zstd batch (base64 via
  blob/encode-str) to the telemetry endpoint with instance-id per event
- Add gc-telemetry-events: enforces 100,000-row safety cap by dropping
  oldest rows first
- Add delete-sent-events: deletes successfully shipped rows by id

Blob utilities (app.util.blob):
- Add encode-str/decode-str: combine fressian+zstd encoding with URL-
  safe base64 for JSON-safe string transport

Database:
- Add migration 0145: index on audit_log (source, created_at ASC) for
  efficient telemetry batch collection queries

Frontend:
- Always initialize event system regardless of :audit-log flag
- Defer auth events (signin identify) to after profile is set
- Refactor event subsystem for telemetry support

Tests (21 test vars, 94 assertions in tasks-telemetry-test):
- Cover all code paths: disabled/enabled telemetry, no-events no-op,
  happy-path batch send and delete, failure retention, payload anonymity,
  context stripping, timestamp day precision, batch encoding round-trip,
  multi-page iteration, GC cap enforcement, partial failure handling
- blob encode-str/decode-str round-trip tests (14 test vars)
- RPC audit integration tests (5 test vars)

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* 📎 Add pr feedback changes

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-05-11 12:42:01 +02:00
Andrey Antukh
279231240d
🐛 Harden outbound HTTP requests against SSRF and restrict assets handlers (#9390)
* ⬆️ Update root deps

* 🐛 Harden outbound HTTP requests against SSRF and restrict unauthenticated asset access

- Add app.util.ssrf URL/host validator that resolves hostnames and blocks
  loopback, link-local, site-local, cloud metadata, and operator-supplied CIDRs
- Add app.media.sanitize image EOF truncator that strips trailing data after
  PNG IEND, JPEG EOI, GIF trailer, and WebP RIFF markers
- Disable HTTP client auto-redirect; add req-with-redirects! helper that
  revalidates every redirect hop against the SSRF blocklist
- Wire SSRF validation and EOF sanitization into media/download-image
- Validate webhook URLs and OIDC profile picture URLs against SSRF
- Restrict /assets/by-id to require authentication for non-public buckets
  (profile) while keeping public access for file-media-object,
  file-object-thumbnail, team-font-variant, and file-data-fragment
- Add config knobs: ssrf-protection-enabled, ssrf-allowed-hosts,
  ssrf-extra-blocked-cidrs

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-05-08 09:18:22 +02:00
Andrey Antukh
9e681260cc
🐛 Fix incorrect invitation token handling on register process (#9380)
* 🐛 Fix incorrect invitation token handling on register process

- Reject prepare-register-profile when an active profile already
  exists for the requested email.
- Stop embedding an existing profile's :profile-id into the
  prepared-register JWE. Profile resolution in register-profile is
  now done exclusively by email lookup, never by a JWE claim.
- Add created? guard to the invitation-success branch in
  register-profile, so existing profiles (active or not) cannot
  reach session creation via anonymous registration.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* ♻️ Restructure invitation handling inside register-profile

Move the invitation-success branch into the created? sub-cond so it
sits alongside the other post-creation branches, making the control
flow consistent.

- Active new profile + matching invitation: mint session and return
  :invitation-token (frontend redirects to :auth-verify-token).
- Not-yet-active new profile + matching invitation: embed the
  invitation token inside the verify-email JWE and send the
  verification email. When the user clicks the link, they get
  logged in and the frontend completes the team-invitation flow.
- Extend send-email-verification! with an optional invitation-token
  parameter propagated into the verify-email JWE claims.
- Update the frontend verify-email handler to navigate to
  :auth-verify-token when the response carries :invitation-token.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* 🐛 Handle email-already-exists error on registration form

Add a specific handler for the [:validation :email-already-exists] error
code in the registration form's on-error callback. The backend raises
this error when an active profile already exists for the requested email,
but the frontend was falling through to the generic error message.

Now it shows the existing "Email already used" i18n message instead of
the generic "Something wrong has happened" toast.

* 🐛 Reset submitted state on registration form error

The on-error handler in the registration form was not resetting the
submitted? state, causing the submit button to remain disabled after
any error. The completion callback in rx/subs! only fires on success,
not on error.

Add (reset! submitted? false) at the beginning of the on-error handler
so the form becomes submittable again after any error, allowing the user
to fix their input and retry.

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-05-06 14:20:55 +02:00
Yamila Moreno
d627d1cfac
Improve team name validation (#9176) 2026-04-29 08:59:09 +02:00
Andrey Antukh
feec89679a Merge remote-tracking branch 'origin/main' into main-staging 2026-04-27 09:58:13 +02:00
Yamila Moreno
7031052c4e 🐛 Prevent invitations to blacklisted domains 2026-04-24 16:48:59 +02:00
Andrey Antukh
fd38f5b431 Merge remote-tracking branch 'origin/main' into main-staging 2026-04-24 08:18:55 +02:00
Yamila Moreno
5f7de04efe
🚑 Fix email blacklisting (#9122) 2026-04-23 09:42:40 +02:00
Andrey Antukh
97d234a566 Add 2h min-age threshold to storage/gc_touched task
Skip storage objects touched less than 2 hours ago, matching the pattern
used by upload-session-gc. Update all affected tests to advance the clock
past the threshold using ct/*clock* bindings.
2026-04-22 08:48:04 +02:00
Andrey Antukh
e5f9c1e863 🎉 Add chunked upload API for large media and binary files
Introduce a purpose-agnostic three-step session-based upload API that
allows uploading large binary blobs (media files and .penpot imports)
without hitting multipart size limits.

Backend:
- Migration 0147: new `upload_session` table (profile_id, total_chunks,
  created_at) with indexes on profile_id and created_at.
- Three new RPC commands in media.clj:
    * `create-upload-session`  – allocates a session row; enforces
      `upload-sessions-per-profile` and `upload-chunks-per-session`
      quota limits (configurable in config.clj, defaults 5 / 20).
    * `upload-chunk`           – stores each slice as a storage object;
      validates chunk index bounds and profile ownership.
    * `assemble-file-media-object` – reassembles chunks via the shared
      `assemble-chunks!` helper and creates the final media object.
- `assemble-chunks!` is a public helper in media.clj shared by both
  `assemble-file-media-object` and `import-binfile`.
- `import-binfile` (binfile.clj): accepts an optional `upload-id` param;
  when provided, materialises the temp file from chunks instead of
  expecting an inline multipart body, removing the 200 MiB body limit
  on .penpot imports.  Schema updated with an `:and` validator requiring
  either `:file` or `:upload-id`.
- quotes.clj: new `upload-sessions-per-profile` quota check.
- Background GC task (`tasks/upload_session_gc.clj`): deletes stalled
  (never-completed) sessions older than 1 hour; scheduled daily at
  midnight via the cron system in main.clj.
- backend/AGENTS.md: document the background-task wiring pattern.

Frontend:
- New `app.main.data.uploads` namespace: generic `upload-blob-chunked`
  helper drives steps 1–2 (create session + upload all chunks with a
  concurrency cap of 2) and emits `{:session-id uuid}` for callers.
- `config.cljs`: expose `upload-chunk-size` (default 25 MiB, overridable
  via `penpotUploadChunkSize` global).
- `workspace/media.cljs`: blobs ≥ chunk-size go through the chunked path
  (`upload-blob-chunked` → `assemble-file-media-object`); smaller blobs
  use the existing direct `upload-file-media-object` path.
  `handle-media-error` simplified; `on-error` callback removed.
- `worker/import.cljs`: new `import-blob-via-upload` helper replaces the
  inline multipart approach for both binfile-v1 and binfile-v3 imports.
- `repo.cljs`: `:upload-chunk` derived as a `::multipart-upload`;
  `form-data?` removed from `import-binfile` (JSON params only).

Tests:
- Backend (rpc_media_test.clj): happy path, idempotency, permission
  isolation, invalid media type, missing chunks, session-not-found,
  chunk-index out-of-range, and quota-limit scenarios.
- Frontend (uploads_test.cljs): session creation and chunk-count
  correctness for `upload-blob-chunked`.
- Frontend (workspace_media_test.cljs): direct-upload path for small
  blobs, chunked path for large blobs, and chunk-count correctness for
  `process-blobs`.
- `helpers/http.cljs`: shared fetch-mock helpers (`install-fetch-mock!`,
  `make-json-response`, `make-transit-response`, `url->cmd`).

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-04-21 18:51:10 +00:00
Andrey Antukh
3a39676969 Backport MCP from staging (part 1) 2026-04-20 19:37:02 +02:00
Andrey Antukh
c8675c5b7e
♻️ Normalize newsletter-updates checbox on different register flows (#8839)
*  Add newsletter opt-in checkbox to registration validation form

Add accept-newsletter-updates support through the full registration
token flow. The newsletter checkbox is now available on the
registration validation form, allowing users to opt-in during the
email verification step.

Backend changes:
- Refactor prepare-register to consolidate UTM params and newsletter
  preference into props at token creation time
- Add accept-newsletter-updates to prepare-register-profile and
  register-profile schemas
- Handle newsletter-updates in register-profile by updating token
  claims props on second step

Frontend changes:
- Add newsletter-options component to register-validate-form
- Add accept-newsletter-updates to validation schema
- Fix subscription finalize/error handling in register form

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* ♻️ Refactor auth register components to modern style

Migrate all components in app.main.ui.auth.register and
app.main.ui.auth.login/demo-warning to use the modern * suffix
convention, removing deprecated ::mf/props :obj metadata and
updating all invocations from [:& name] to [:> name*] syntax.

Components updated:
- terms-and-privacy -> terms-and-privacy*
- register-form -> register-form*
- register-methods -> register-methods*
- register-page -> register-page*
- register-success-page -> register-success-page*
- terms-register -> terms-register*
- register-validate-form -> register-validate-form*
- register-validate-page -> register-validate-page*
- demo-warning -> demo-warning*

Also remove unused old context-notification import in login.cljs.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* 🔥 Remove unused onboarding-newsletter component

The newsletter opt-in is now handled directly in the registration
form via the newsletter-options* component, making the standalone
onboarding-newsletter modal obsolete.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* 🐛 Fix register test for UTM params to use prepare-register step

UTM params are now extracted and stored in token props during the
prepare-register step, not at register-profile time. Move utm_campaign
and mtm_campaign from the register-profile call to the
prepare-register-profile call in the test.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-04-08 17:00:52 +02:00
Andrey Antukh
81b1b253f1
Add unique email domains to telemetry report (#8819)
Extend the telemetry payload with a sorted list of unique email domains
extracted from all registered profile email addresses. The new
:email-domains field is populated via a single SQL query using
split_part and DISTINCT, and is included in the stats sent when
telemetry is enabled.

Also update the tasks-telemetry-test to assert the new field is present
and contains the expected domain values.
2026-04-01 11:49:50 +02:00
Andrey Antukh
ab90500ec8 🐛 Fix download-image to properly handle network errors and non-2xx responses (#8554)
The download-image function in app.media silently succeeded when the
remote image URL was unreachable or returned an error status code,
causing create-file-media-object-from-url to report success with no
actual image stored.

Add exception handling for connection refused, timeouts, and I/O errors
around the HTTP request, and validate the HTTP status code in
parse-and-validate before processing the response body.

Fixes #8499

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-03-10 15:01:23 +01:00
Andrey Antukh
77955d7f91 Add several redundant checks for library-id on file rpc methods 2026-03-09 10:01:29 +01:00
Andrey Antukh
4a7b89a1da
Merge pull request #8327 from penpot/niwinz-develop-rlimit-notifications
 Add proper mattermost notifications for rlimit rejects
2026-02-13 17:11:54 +01:00
Andrey Antukh
f08700945a Merge remote-tracking branch 'origin/staging' into develop 2026-02-10 11:58:09 +01:00
Andrey Antukh
06e5825c8a 🐛 Add proper input checking to font related RCP method 2026-02-10 10:36:57 +01:00
Andrey Antukh
d80ba1856a
Add several improvements to frontend error reporting
*  Add major improvement on error handling

*  Add the ability to store frontend reports

* 📎 Add PR feedback changes
2026-02-04 12:45:38 +01:00
Pablo Alba
4ca82821c1
🐛 Fix shared keys init should be by keywords (2) (#8230) 2026-01-28 13:41:37 +01:00
Andrey Antukh
f5996a7235 ♻️ Make several improvements to management API authentication 2026-01-27 15:14:32 +01:00
Andrey Antukh
0ab126748f
💄 Add format rule for code comments (#8211)
* 💄 Add format rule for code comments

* ⬆️ Update linter and formatter on devenv
2026-01-27 15:07:18 +01:00
Andrey Antukh
bcaf76d055 Make the virtual clock by profile and not global
And make it affect only RPC/HTTP requests and not worker
tasks.
2026-01-09 12:58:44 +01:00
Andrey Antukh
7b5817f407
♻️ Make several adjustments to the dashboard deleted page (#7999)
* ♻️ Make several sustantial adjustments to the dashboard deleted page

* 📎 Add PR feedback changes
2025-12-30 09:52:29 +01:00
Andrey Antukh
b23e0c0642
Add tempfile storage bucket handler test case (#7839) 2025-11-27 10:27:57 +01:00
Alejandro Alonso
4f54469629
Merge pull request #7747 from penpot/niwinz-develop-storage-changes
 Make the binfile exportation process more reliable
2025-11-20 07:58:57 +01:00
Andrey Antukh
51e54a6bad
🐛 Fix incorrect project restoration on restoring file (#7778) 2025-11-19 18:24:24 +01:00
Andrey Antukh
94719eebf8 ♻️ Make storage and other objects deletion task vclock aware
This simplifes the mental model on how it works and simplifies testing
of the related code.

This also normalizes storage object deletion in the same way as the
rest of objects in penpot (now future deletion date on storage object
also means storage object to be deleted).
2025-11-19 17:28:55 +01:00
Andrey Antukh
363b4e3778
♻️ Make the SSO code more modular (#7575)
* 📎 Disable by default social auth on devenv

* 🎉 Add the ability to import profile picture from SSO provider

* 📎 Add srepl helper for insert custom sso config

* 🎉 Add custom SSO auth flow
2025-11-12 12:49:10 +01:00
Andrey Antukh
28cf67e7ff
🎉 Add management RPC API (#7700)
* 🎉 Add management RPC API

And refactor internal http auth flow

* 📎 Adjust final url namings

* 📚 Update changelog
2025-11-10 17:10:59 +01:00
Andrey Antukh
9d65d11c91 Merge remote-tracking branch 'origin/staging' into develop 2025-11-07 10:43:27 +01:00
Andrey Antukh
097897d8da Add better sse parser for backend tests 2025-11-06 15:54:50 +01:00
Andrey Antukh
83763b46ce Add RPC methods for manage deleted files
This includes: get already deletedf files, restore deleted files
and permanently delete files marked for deletion.
2025-10-31 16:07:23 +01:00
Andrey Antukh
1ddc196484 Make the get-projects return deleted projects
And adapt the frontend code to properly filter
deleted projects on appropriate pages
2025-10-31 16:07:23 +01:00
Andrey Antukh
76e610dd06 🔥 Remove duplicated functions from file tests namespace 2025-10-31 16:07:23 +01:00
Andrey Antukh
fbbee98c3d Add proper backend integration of for new feedback form 2025-10-17 09:40:27 +02:00
Andrey Antukh
62dffd30a4 ♻️ Refactor redis internal API
The main idea behind this refactor is make the
API less especialized for specific use of out internal
submidules and make it more general and usable
for more general purposes (per example cache)
2025-10-13 12:32:29 +02:00
Alejandro Alonso
2b7bd8fa5c 🐛 Fix deleted files are accesible 2025-10-13 12:24:05 +02:00
Andrey Antukh
5717708b56 ♻️ Refactor file storage
Make it more scallable and make it easily extensible
2025-10-13 12:24:05 +02:00
Andrey Antukh
2c1a8b59ba Add client header check middleware
As an additional csrf protection for API requests
2025-10-07 12:47:14 +02:00
Andrey Antukh
47d9c6f282 Add sec-fetch metadata middleware support 2025-10-07 12:47:14 +02:00
Andrey Antukh
61d9b57bc7 ♻️ Refactor internal tokens API
Mainly make it receive the whol cfg/system instead only props. This
makes the api more flexible for a future extending without the need
to change the api again.
2025-10-07 12:08:00 +02:00
Andrey Antukh
c1058c7fdb ♻️ Add minor refactor for internal concurrency model
Replace general usage of virtual threads with platform threads
and use virtual threads for lightweight procs such that websocket
connections. This decision is made mainly because virtual threads
does not appear on thread dumps in an easy way so debugging issues
becomes very difficult.

The threads requirement of penpot for serving http requests
is not very big so having so this decision does not really affects
the resource usage.
2025-09-26 14:35:06 +02:00
Andrey Antukh
45be4769d7 Merge remote-tracking branch 'origin/staging' into develop 2025-08-27 13:19:06 +02:00
Andrey Antukh
ad0ef82ffc 🎉 Add management http api 2025-08-25 10:53:12 +02:00