Commit graph

29 commits

Author SHA1 Message Date
Andrew Pimenov
b285f546c2 stream-cap rates responses instead of buffering then checking size
resp.bytes() already pulls the whole body into memory before the 5MB
check ran, so a malicious server could still OOM the process during
download. read_body_capped aborts mid-stream once the cap is hit.

also fix goal-seek probe fallback: it could update lo/hi to a genuine
bracket without ever setting found=true, throwing "no solution" on
cases that do have one.
2026-08-19 04:11:27 +03:00
Андрей Пименов
509926bcef fix: address adversarial review findings
- Fix race condition in write_atomic_bytes by using unique temp file names
- Fix logic flaw in DataDirGate authorization on migration failures
- Reject invalid padding in base64_decode
- Set size limits on json fetches for rates
- Fix Date math around DST boundaries for tomorrow/yesterday
- Handle division by zero exceptions gracefully in goal seek
- Fix OOM vector for huge hexadecimal number rendering
2026-08-19 04:11:27 +03:00
Horizontal42
51ee3b3208 linux + macos release builds (unsigned)
split bundle config into tauri.{windows,linux,macos}.conf.json so each
platform only carries its own targets; gen-icon emits icon.icns; macos is
ad-hoc signed since arm64 refuses unsigned downloads
2026-08-14 13:39:08 +03:00
Horizontal42
c3bc67bd5b gate every dir-taking IPC command against a Rust-owned trust anchor
load_documents, save_documents, run_backups, backup_deleted_sheet,
open_backups_folder and data_dir_has_documents all took a `dir` param
straight from the frontend and used it unchecked — any IPC caller
(a buggy extension, compromised webview content) could point Rust at
an arbitrary path, and migrate_data_dir's old_dir was the worst of it:
combined with strategy="move" it deletes documents.json and everything
under backups/ at whatever path it's handed.

Add DataDirGate: a path only counts as authorized if it was proven
user-chosen, either just now via the native folder picker or because
it's the data-dir.txt this file itself wrote after a previous
successful commit. save_file/load_file refuse to touch that filename
so the frontend can't forge its own authorization. docs_dir() now
returns Result and every command above goes through it.

migrate_data_dir authorizes the target before copying but only writes
data-dir.txt once every file has actually landed, so a migration that
dies partway leaves the app still pointing at a folder that works.
2026-08-12 20:00:00 +03:00
Horizontal42
3bc946bd44 consistent size cap for OS-opened sheet files
read_text_file (drag&drop) capped sheets at 1MB with an extension
whitelist; get_launch_file and the single-instance file-open handler
only checked the extension. Route both through read_sheet_file so a
file association or second launch gets the same cap.
2026-08-12 19:59:12 +03:00
Horizontal42
dea7314842 move cache file I/O off the async runtime thread
rates.json, market.json and rates-<date>.json reads/writes ran
straight on the tokio worker calling the Tauri command, blocking the
shared async runtime for the duration. Wrap them in
tauri::async_runtime::spawn_blocking via read_file_async/write_atomic_async.
2026-08-12 19:57:55 +03:00
Horizontal42
2d682448c6 dedupe historical-rate map parsing
fetch_historical_rates and fetch_historical_rates_batch each built the
same USD-anchored, uppercased rate map inline. Extract parse_rate_map
and cover it with tests.
2026-08-12 19:56:11 +03:00
Horizontal42
a8121dbc90 share atomic-write bytes helper between write_atomic and image export
write_image_file hand-rolled the same temp+rename dance write_atomic
already did for text, just for bytes. Split write_atomic into a
write_atomic_bytes core and have both callers use it.
2026-08-12 19:54:37 +03:00
Horizontal42
d7b88cc9c9 atomic write for deleted-sheet backups
fs::write left the one safety-net copy of a deleted sheet exposed to
mid-write corruption; use the existing temp+rename helper like every
other user-data write.
2026-08-12 19:54:06 +03:00
Horizontal42
dad3de70a5
bound migrate_data_dir cleanup to known files, add dialog-verified new_dir 2026-08-09 16:27:08 +03:00
Horizontal42
354705cf15
scope read_text_file to files from real drop events 2026-08-09 16:23:33 +03:00
Horizontal42
55d8401a44
batch historical rates IPC calls with a pooled http client 2026-08-09 15:59:44 +03:00
Horizontal42
5c4f2db2d2 fix clippy collapsible_match warning in safe_name 2026-07-29 14:14:49 +03:00
Horizontal42
a6fc5b90f3 harden safe_name path validation 2026-07-29 14:14:49 +03:00
Horizontal42
c1a7254fdf fix arbitrary file write via write_text_file/write_image_file
Both Tauri commands took a raw path string straight from the frontend
and wrote to it with no validation — any code able to call invoke()
(a compromised or malicious extension script, which run with full page
privileges) could write to any path the OS user has access to, not just
one chosen through the save dialog. Move the save-file dialog into the
Rust command itself so the only path ever used is one the native dialog
returned; the frontend now only sends the content to save.
2026-07-08 15:50:13 +03:00
Horizontal42
f634b1858e fetch market data symbols concurrently instead of sequentially
fetch_market_data hit Yahoo's v8 chart endpoint once per symbol in a
sequential loop — with 9 symbols that's 9 round trips end to end.
join_all fires them together.
2026-07-08 15:47:31 +03:00
Horizontal42
8b4e6fc0fe market data: switch to Yahoo v8 chart, drop delisted tickers
v7/finance/quote returns 401 now — Yahoo stopped issuing anonymous
clients the cookie+crumb pair it requires. v8 chart still answers
without auth, one symbol per request instead of one bulk call.
Also dropped SBER/GAZP from the tracked symbols; Yahoo delisted
Russian tickers in 2022, so those two always missed anyway.
2026-07-03 11:51:40 +03:00
Horizontal42
d0d13ec1c0 historical rates: point at frankfurter.dev, fetch on cold start too
api.frankfurter.app 301-redirects to frankfurter.dev now, and the old
host is flaky over reqwest/rustls-tls — talk to the new one directly
(Rust backend, the vite-dev web fallback, and the CSP allowlist).

Separately, a sheet reopened on boot with "on 2024-01-01" in it never
fetched historical rates at all: the fetch only ran from switchDoc()
and the editor's onChange, and the editor's initial text is seeded
directly, bypassing both.
2026-07-03 11:46:47 +03:00
Horizontal42
d28ab6d095 style: cargo fmt src-tauri
Whitespace only, no behavior change — makes the next couple of Rust
commits smaller and easier to read.
2026-07-03 11:44:36 +03:00
Horizontal42
fbeca06f2e historical rates: 1000 USD in EUR on 2024-01-01 via frankfurter.app 2026-07-01 22:23:35 +03:00
Horizontal42
bbbcc0497c export sheet as PNG — clipboard + file-save fallback 2026-07-01 20:44:04 +03:00
Horizontal42
661a4500ca live market data via Yahoo Finance: AAPL TSLA NVDA etc 2026-07-01 20:40:40 +03:00
Horizontal42
6efae0c706 add auto-update via tauri-plugin-updater
Signed by a new key (public half embedded in tauri.conf.json, private
half + password live in GitHub secrets). CI now signs release artifacts
and publishes latest.json; the app checks on boot and prompts to
install and restart.
2026-07-01 13:58:32 +03:00
Horizontal42
b0c46c390c RU math phrases, half/полтора constants, export button
- vocab: EN+RU aliases for abs/log/ln/round; RU already had sqrt/cbrt
- engine: "half"/"a half"/"one half"/"половина" → 0.5; "one and a half"/"полтора"/"полторы" → 1.5 as named constants; widen const union in parser/tokenizer/evaluator/registry
- export: ⤓ button in statusbar dropdown — copy sheet, save .sum, export .txt, print/PDF; write_text_file Tauri command; print media CSS hides chrome
2026-06-24 00:27:06 +03:00
Horizontal42
ece0ea1a14 fix white screen on autostart and hotkey toggle 2026-06-19 17:30:54 +03:00
Horizontal42
9fe8dd74f8 apply rustfmt 2026-06-18 22:08:09 +03:00
Horizontal42
165aa65bba add unit tests for safe_name and is_sheet_path 2026-06-18 22:00:44 +03:00
Horizontal42
f55266f70b v1.1.0: bug fixes, atomic writes, safe quit, .sum files, CI
Engine: fix BigInt crash on NaN, KM/KG case-insensitive units, space-grouped
and comma-decimal number parsing, variable-vs-unit shadowing, small value
display (1 mm in km), DST-safe date arithmetic, month-end clamp, log mustTouch,
avg counted, 50% of 50%, 100 USD + 20 after conversion, percent power.

Rust: atomic writes (temp+rename) for documents.json, safe quit (app-quit event
+ 2s watchdog so tray-quit doesn't lose edits), .sum file association + open,
migration safety (canonicalize + all_copied guard), opener API for backups and
extensions folders.

UI: decimal separator setting, hotkey rollback on failure, corrupted JSON guard,
ru welcome sheet, orange cursor visibility.

CI: windows-latest workflow (tsc + vitest + cargo clippy).
2026-06-11 12:57:39 +03:00
Horizontal42
0cef414e9a feat: Summarum — natural language calculator notebook for Windows
Write plain text, get live results per line. English + Russian, units,
live currency rates with crypto, percents, dates and timezones, bitwise
ops, variables and sheet totals. Tauri 2 + TypeScript engine +
CodeMirror 6; daily backups and a deleted-sheets bin.

Inspired by Numi for macOS (numi.app); built from scratch for Windows.
2026-06-10 22:19:24 +03:00