Security
- Zip extraction in
BackupService.restore()andUpdateServicenow validates
member paths before extracting, preventing zip-slip path traversal attacks. - TSM API endpoints probed: only
id.tradeskillmaster.com(OIDC) has a valid cert.
All other*.tradeskillmaster.comAPI hosts have a certificate hostname mismatch
and must use plain HTTP.scripts/check_ssl.pyadded to re-verify this during development.
Fixed
- Login dialog is now fixed size (480x280 px) and cannot be resized; redundant
"TradeSkillMaster" title label removed. - Logging out via Settings now closes the Settings dialog before showing the login
window instead of leaving it open in the background. - Status bar no longer shows "⚠ TradeSkillMaster_AppHelper addon not found" on WoW
installs whereWoW.exeis absent from the game-version directory (common on some
Lutris setups). The AppData.lua reader now only requires the game-version directory
to exist rather than a WoW executable, matching the writer's behavior. - WoW account directory scan now accepts account names containing hyphens and dots,
which are valid in some localized WoW installs. ItemCache.get(),get_name(), andensure_fetched()now hold the internal lock
while reading_data, preventing data races with the background fetch thread.cfg.wow_installs = foundin the scheduler replaced with immutable
model_copy(update=...)- Pydantic models must not be mutated in place.subprocess.Popenin the Settings backup-folder button replaced with
subprocess.run(check=False)with return-code logging.
Changed
- API client retries on HTTP 429 (rate-limited) responses, honouring the
Retry-Afterheader when present, instead of raising immediately. asyncio.ensure_future()replaced withasyncio.create_task()in the scheduler
(the former is deprecated in Python 3.10+).
Chore
_GAME_VERSIONSconstant deduplicated:accounts.pynow imports it from
utils.pyinstead of redefining it.- Scheduled job functions are now typed with
ServiceContainerand the defensive
getattr()/callable()guards are replaced with directis not Nonechecks. - Hover icon button logic consolidated into
HoverIconButtonin
tsm/ui/components/hover_button.py; four duplicate inner classes removed. populate_combo()helper added totsm/ui/views/_utils.py;blockSignals
boilerplate replaced acrossrealm_data.pyandaccounting_export.py.BackupsView._refresh()andRealmViewModel._on_data_received()renamed to
public slots;app_window.pyno longer calls private methods on child objects.backup.py run()split into_purge_old_backups(),_should_skip_backup(),
and_prune_auto_backups()helpers; the loop body is now a readable outline.- Protocol
Anytypes replaced with concrete model types (AuctionData,
RealmStatus,AddonVersionInfo,WoWInstall,AppConfig,Path) in
scheduler.py;Anyimport removed entirely. RealmViewModel.summaries.pop(row)inrealm_data.pyreplaced with a new
remove_local(row)method - views should not mutate ViewModel internals directly.- Pure CSV/data functions extracted from
accounting_export.pyinto
tsm/ui/views/_accounting_utils.pyfor testability;_setup_ui()split into
_build_*helper methods; strayimport contextlibmoved to module top. - Unit tests added:
test_saved_variables.py,test_wow_tooltip.py,
test_item_cache.py(34 new tests, 70 total).