Commit graph

518 commits

Author SHA1 Message Date
Adam Brown
810ae23c0d Encrypt auth tokens at rest per platform (F-4)
Replace the plaintext FileAuthTokenStore binding with platform-specific
encrypted stores behind the same AuthTokenStore interface, wired via a new
expect/actual authTokenStoreModule.

Android: EncryptedSharedPrefsAuthTokenStore backed by EncryptedSharedPreferences
with a Keystore-backed AES256_GCM master key (androidx.security:security-crypto).

Desktop: EncryptedFileAuthTokenStore writes the token-map JSON as AES/GCM/NoPadding
to the config directory. The key is derived (PBKDF2WithHmacSHA256) from the OS user
name and home dir plus a static salt, with no key file on disk, so a copied token
file is useless on another machine or user. A random 12-byte IV is prepended per
write and owner-only POSIX perms are applied best-effort. Decryption failure is
treated as no tokens rather than crashing. This guards against casual disk
scraping and off-machine copies, not same-user local malware that can re-derive
the key.

iOS: still uses the plaintext file store pending a Keychain-backed implementation
(TODO marker in the iOS binding).

Migration: a legacy plaintext auth_tokens.json from an intermediate build is
imported into the encrypted store and deleted on first access; existing encrypted
tokens win on key collision so a stale plaintext entry cannot clobber a fresh
session.
2026-06-24 16:07:40 -07:00
Adam Brown
c5ee60feee Encode dynamic project-name path segments to stop URL segment injection
Every project-scoped client API built its request path by raw string
interpolation of projectName, e.g. "/api/project/$userId/$projectName/begin_sync".
That string reached the shared url() builder whose only path handling was
pathSegments = path.split("/"). Because the split ran on the already-interpolated
string, a projectName containing "/" was split into extra discrete path segments
and a ".." survived as a literal traversal dot-segment, so the outbound request
could target a different endpoint than the {userId}/{projectName}/{action}
template intended (e.g. a malicious sync server returning a project named
"p/../../../api/account/test_auth").

The shared ProjectNameValidator permits "/", "\" and "." (they are encoded to
disk-safe lookalikes only when used as a directory name), so a server-supplied
project name persists verbatim and then injects into every subsequent
project-scoped request under the same host with the bearer token attached.

Fix: each dynamic value is now percent-encoded into a single opaque path
segment via String.encodeUrlPathSegment() before interpolation, and the sink
sets encodedPath directly. Embedded "/" becomes %2F so it cannot create extra
segments, and an all-dots segment is encoded to %2E so a ".." name cannot act as
a traversal segment. The validator is intentionally left unchanged: tightening
it to reject "/" or "." would break syncing for already-valid existing project
names, so encoding is the backward-compatible fix and the on-disk
encodeForFilename behavior is untouched.

Adds a MockEngine test asserting a malicious projectName collapses to a single
encoded segment in the outbound URL across ProjectDataApi, ServerProjectApi and
WritingActivityApi.
2026-06-24 14:45:27 -07:00
renovate[bot]
9ad37ee315
Update logback monorepo (#637)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-23 16:35:51 -07:00
Adam Brown
3b23dc6cf0 Prepared for release: v3.4.2 2026-06-23 10:10:05 -07:00
Adam Brown
77f1eb1884 Prepared for release: v3.4.1 2026-06-23 00:45:34 -07:00
Adam Brown
080c403619 Prepared for release: v3.4.0 2026-06-22 22:02:40 -07:00
renovate[bot]
fe1f8162f9
Update aboutlibraries to v15 (#633)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-22 14:15:24 -07:00
renovate[bot]
68ffcc1eb1
Update kotlinx.collections.immutable to v0.5.0 (#630)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-22 11:43:14 -07:00
renovate[bot]
a9efa340d3
Update hikaricp to v7.1.0 (#629)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-22 01:41:53 -07:00
renovate[bot]
52dc757354
Update koin.bom to v4.2.2 (#622)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-21 21:11:14 -07:00
Adam Brown
c39f1b7854 Update spell check lib to fix crash on Android 2026-06-20 01:01:39 -07:00
Adam Brown
3318c1f284
Make SceneTree state Compose-stable with immutable collections (#621)
Mark the scene-tree state types @Immutable/@Stable and move them onto
kotlinx.collections.immutable so Compose can skip recomposition when the
tree is unchanged: TreeValue.children becomes ImmutableList, SceneSummary
.hasDirtyBuffer a PersistentSet (sourced as such from SceneContentRepository),
and SceneList.State.archivedScenes an ImmutableList. Also cache ImmutableTree
.nodeIndex/hashCode lazily and gate compose-compiler stability reports behind
the composeCompilerReports property.

* Harden onSceneBufferUpdate to reduce from oldState

Read the scene summary from the getAndUpdate lambda's oldState argument
instead of a snapshot captured before the CAS, so the reducer stays a pure
function of its input and composes correctly if buffer updates ever run off
the main dispatcher.
2026-06-19 23:29:41 -07:00
Adam Brown
c63b09f58f Use the HSTS plugin 2026-06-19 17:51:21 -07:00
Wavesonics
c6b049318d
Bump coreKtx 2026-06-18 15:32:06 -07:00
Adam Brown
491da055ef Replaced kotlinx.cli with Clikt 2026-06-18 00:35:55 -07:00
Adam Brown
49ba08b55a Prepared for release: v3.3.1 2026-06-16 00:34:56 -07:00
Adam Brown
091590943d Update text editor
Added shortcuts
2026-06-15 23:49:14 -07:00
renovate[bot]
c7e81d3ae9
Update coil to v3.5.0 (#602)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-14 01:33:19 -07:00
renovate[bot]
b31e7d1da8
Update filekit to v0.14.2 (#599)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-13 21:15:22 -07:00
Adam Brown
18bcc4652f Prepared for release: v3.3.0 2026-06-13 12:44:51 -07:00
Adam Brown
fde00d28f6 Fix compose edit stream 2026-06-13 11:50:43 -07:00
Adam Brown
b40358b4cb Upgrade logback_classic 2026-06-13 11:35:14 -07:00
Adam Brown
4b912129b4
Replace fluidsonic (#597) 2026-06-13 02:38:21 -07:00
Adam Brown
b0e16d6e63 Update text editor 2026-06-13 01:57:35 -07:00
Adam Brown
347baf82f0
Reworked PDF export (#585)
Better formatting now!
2026-06-11 00:44:47 -07:00
Adam Brown
0791954de0
Add docx export format 2026-06-11 00:18:00 -07:00
Adam Brown
6fd3fd15ae
Prepared for release: v3.2.1 2026-06-10 19:41:32 -07:00
Adam Brown
9c1ac1c7dc
Spell Checker dictionary is now selectable on Desktop and iOS 2026-06-09 00:01:20 -07:00
Adam Brown
60a61541e9
Harden release task against network failures 2026-06-08 21:45:29 -07:00
Adam Brown
93de0e7fd1
Prepared for release: v3.2.0 2026-06-08 00:08:51 -07:00
Adam Brown
b44c315431
Target Android API 37 (Android 17)
Bump compileSdk/targetSdk to 37 and AGP to 9.1.1 (9.0.x maxes out at
API 36.1 and can't resolve the minor-versioned android-37.0 platform).

Handle the two breaking behavior changes for API 37 targets:

- Cleartext traffic: usesCleartextTraffic is now ignored without a
  network security config. Self-hosted servers can be plain HTTP
  (ServerSettings.ssl = false), so add network_security_config.xml
  permitting cleartext and reference it from both manifests.

- Local network access: declare ACCESS_LOCAL_NETWORK and request it at
  runtime via a new expect/actual RequestLocalNetworkPermission,
  triggered when the server-setup dialog opens so the grant resolves
  before any LAN connection. No-op on desktop/iOS.
2026-06-07 23:57:01 -07:00
Adam Brown
27659be26c
Export to PDF support 2026-06-07 23:07:20 -07:00
Adam Brown
a2998adcba
Re-enable public-storage projects on F-Droid builds (#568)
Restores the "store projects in public storage" feature, gated to F-Droid builds (the required MANAGE_EXTERNAL_STORAGE permission is disallowed on Google Play).

- Expose the build channel at runtime via BuildConfig.FDROID in the common module.
- Declare the storage permissions only in src/fdroid/AndroidManifest.xml, swapped in for F-Droid builds.
- Restore the storage-location toggle + file-access UI, gated on BuildConfig.FDROID; reconcile the toggle with the real location on open.
- Build the GitHub release APK as the F-Droid flavor.
- Extract the directory move into a tested FileSystem.moveDirectory() helper (fixes the same-path data-loss crash; runs off the UI thread).
- Read the fdroid flag consistently across settings.gradle.kts and module scripts.
- Document the F-Droid build flag in DEVELOPMENT.md.
2026-06-07 19:16:42 -07:00
Adam Brown
846ed7fbc1
Upgrade libs 2026-06-06 23:59:58 -07:00
Adam Brown
db4343d8f1
Adds a full monitoring subsystem to the server admin panel
- Data foundation: SQLDelight tables for API metrics, error logs, and
login attempts with a v1→v2 schema migration
- Metrics pipeline: per-endpoint request counts, latency, and error
rates collected via a Ktor plugin; daily rollup job with configurable
retention windows
- Error tracking: fingerprinted deduplication, occurrence counts,
first/last seen timestamps, and email alerting on persistent errors
- Security page: login-attempt tracking, brute-force/spray detection
with cooldown alerts, optional IP storage
- Admin dashboard UI: performance charts (Frappe), error panel with
route filter and JSON export, live log viewer (10k ring buffer),
security event feed
- Alert deep-links from the dashboard into filtered error views
- Settings UI: all monitoring options converted to toggle switches;
master switch disables and grays out sub-options via JS; email field
conditionally required with htmx:before-request validation
2026-06-05 19:19:11 -07:00
Wavesonics
97bc5a1b1a Prepared for release: v3.1.3 2026-06-04 21:56:12 -07:00
Wavesonics
08ebef7098 Downgrade core-ktx to 1.16.0 to unblock release
1.19.0 requires compileSdk 37 and AGP 9.1.0 which we're not ready to bump yet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 21:51:48 -07:00
Wavesonics
4bb4c9501e Update compose-texteditor
Fix for markdown syntax sneaking through into rich text
2026-06-04 19:19:25 -07:00
Wavesonics
4e62f34acc Update compose-texteditor
Fix for markdown syntax sneaking through into rich text
2026-06-04 18:05:28 -07:00
Adam Brown
35ecc7b750
Prepared for release: v3.1.2 2026-06-03 00:37:43 -07:00
Adam Brown
6c705d11bb
Prepared for release: v3.1.1 2026-06-02 00:29:07 -07:00
Adam Brown
28d0d2bdf1
Prepared for release: v3.1.0 2026-06-01 23:10:53 -07:00
Adam Brown
ee279cd8e8
Fix spellcheck not being disabled when spellChecking is disabled 2026-06-01 23:07:35 -07:00
Wavesonics
569c9faaa5 Add a desktop splash screen 2026-05-31 01:46:30 -07:00
renovate[bot]
f6088d405f
Update aboutlibraries to v14.2.1 (#508)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-31 00:40:20 -07:00
renovate[bot]
8b2d3d3e30
Update kotlinx.atomicfu to v0.33.0 (#530)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-31 00:38:30 -07:00
renovate[bot]
3e47ead306
Update dependency io.zonky.test.postgres:embedded-postgres-binaries-bom to v18 (#522)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-31 00:37:40 -07:00
Adam Brown
4537909826
Add prose diff visualization to draft compare and conflict merge UIs (#525)
New ProseDiff module: word-level Myers diff (kotlin-multiplatform-diff)
over markdown text, with syntax stripped via the JetBrains parser and
offsets mapped back to source. Merges adjacent edits into single hunks,
emits anchors at each boundary for scroll sync, and includes a git-style
slider that aligns pure insert/delete blocks to line boundaries. Covers
plain-text diffing, prepared/reusable inputs, and an OffsetMap that maps
a position on one side to its counterpart.

Draft compare: highlights DELETED (red/strikethrough) and INSERTED
(green/underline) spans via non-destructive RichSpans in each pane's
rendered coordinate space, recomputed off-thread on a 500ms debounce.
Synchronized scrolling (compose-texteditor 2.0.7) drives either pane from
the other off raw scroll pixels with an echo guard. Both editor states are
hoisted so highlights and sync work in compact and expanded layouts and
survive theme changes. A DIFF toggle gates highlights and sync.
2026-05-30 09:49:33 -07:00
renovate[bot]
8b5323d01d
Update compose.texteditor to v2.0.7 (#520)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-29 22:48:24 -07:00
renovate[bot]
bb46814a0d
Update dependency io.mockk:mockk to v1.14.11 (#528)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-29 22:48:05 -07:00