Skip to content

Commit 4407e20

Browse files
authored
Merge pull request #60 from xLieferant/VTC-BIG-Change
New assignments for VTC and UI Update 0.7.5
2 parents b7e1b65 + 0a138b6 commit 4407e20

278 files changed

Lines changed: 1011236 additions & 2125 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ets2-tool/README.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,158 @@ GDK_BACKEND=x11 WEBKIT_DISABLE_DMABUF_RENDERER=1 cargo tauri dev
2828
```
2929

3030
You can prefix the same environment variables to the app launch command outside of dev as well.
31+
32+
## Local Authentication (Career Mode)
33+
34+
This project includes a local/offline authentication system for the Career panel (SQLite + Argon2 password hashing).
35+
36+
### Test user (dev)
37+
38+
- Email: `admin@admin.de`
39+
- Password: `admin123`
40+
- Role: `admin`
41+
42+
The admin user is created/seeded automatically on first auth DB access and the password is stored only as a hash (never plaintext).
43+
44+
### Where login data is stored
45+
46+
**Database file**
47+
- Path: `%LOCALAPPDATA%\\SimNexusHub\\logbook.sqlite` (Windows)
48+
- Created automatically if missing.
49+
- Fallback: if `dirs::data_local_dir()` is unavailable, the current working directory is used.
50+
51+
**Session file (remember-me token)**
52+
- Path: `%LOCALAPPDATA%\\SimNexusHub\\auth_session.json`
53+
- Contains only a persisted session token for “remember me” (no password, no email).
54+
55+
Source of truth for paths:
56+
- `src-tauri/src/features/auth/db.rs`
57+
58+
### SQLite schema (auth-related)
59+
60+
Tables are created/updated automatically via “ensure tables/columns” (lightweight migrations):
61+
- `src-tauri/src/features/auth/db.rs`
62+
63+
```sql
64+
-- users
65+
CREATE TABLE IF NOT EXISTS users (
66+
id INTEGER PRIMARY KEY AUTOINCREMENT,
67+
username TEXT NOT NULL,
68+
email TEXT NOT NULL,
69+
password_hash TEXT NOT NULL,
70+
role TEXT NOT NULL DEFAULT 'user',
71+
company_id INTEGER,
72+
created_at TEXT NOT NULL,
73+
updated_at TEXT NOT NULL,
74+
last_login_at TEXT,
75+
consent_at TEXT NOT NULL,
76+
is_active INTEGER NOT NULL DEFAULT 1,
77+
is_seed INTEGER NOT NULL DEFAULT 0
78+
);
79+
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_username ON users(username);
80+
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_email ON users(email);
81+
82+
-- sessions (remember-me)
83+
CREATE TABLE IF NOT EXISTS sessions (
84+
id INTEGER PRIMARY KEY AUTOINCREMENT,
85+
user_id INTEGER NOT NULL,
86+
token TEXT,
87+
created_at TEXT NOT NULL,
88+
expires_at TEXT,
89+
last_used_at TEXT,
90+
revoked_at TEXT
91+
);
92+
CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id);
93+
CREATE INDEX IF NOT EXISTS idx_sessions_token ON sessions(token);
94+
95+
-- recovery codes (hashed, one-time)
96+
CREATE TABLE IF NOT EXISTS recovery_codes (
97+
id INTEGER PRIMARY KEY AUTOINCREMENT,
98+
user_id INTEGER NOT NULL,
99+
code_hash TEXT NOT NULL,
100+
created_at TEXT NOT NULL,
101+
used_at TEXT
102+
);
103+
CREATE INDEX IF NOT EXISTS idx_recovery_codes_user_id ON recovery_codes(user_id);
104+
105+
-- login events (privacy-friendly local MAU per installation)
106+
CREATE TABLE IF NOT EXISTS login_events (
107+
id INTEGER PRIMARY KEY AUTOINCREMENT,
108+
user_id INTEGER,
109+
at_utc TEXT NOT NULL,
110+
year_month TEXT NOT NULL
111+
);
112+
CREATE INDEX IF NOT EXISTS idx_login_events_year_month ON login_events(year_month);
113+
CREATE INDEX IF NOT EXISTS idx_login_events_user_month ON login_events(user_id, year_month);
114+
```
115+
116+
### What is stored / what is NOT stored (privacy)
117+
118+
Stored (minimum needed for local auth):
119+
- Email + username (for login + display)
120+
- Role (admin/user)
121+
- Password hash (Argon2, salted) in `users.password_hash`
122+
- Session token for “remember me” in `sessions.token` and `auth_session.json`
123+
- Timestamps: `created_at`, `updated_at`, `last_login_at`, session timestamps
124+
125+
Not stored:
126+
- No plaintext passwords
127+
- No IP address, device fingerprint, geo location, or tracking identifiers
128+
- No telemetry / online user tracking (local-only)
129+
130+
This is a technical, data-minimizing structure and **not legal advice**. For production, you likely want to add:
131+
- Server-side auth (if you need global MAU), email delivery, and secure token flows
132+
- Proper audit/event model, rate limiting, lockouts, and encrypted backups
133+
- Optional database encryption at rest (depending on threat model)
134+
135+
### How login/logout works (technical)
136+
137+
Backend:
138+
- Login/register: `src-tauri/src/features/auth/service.rs` (`login_local`, `register_local`)
139+
- Password hashing: Argon2 in `src-tauri/src/features/auth/service.rs` (`hash_password`, `verify_password`)
140+
- Session persistence: remember-me token written to `auth_session.json` and stored in `sessions`
141+
- Logout: clears in-memory state + removes `auth_session.json` + revokes the session row (sets `revoked_at`)
142+
143+
Frontend:
144+
- Header user menu + login/logout: `src/main.js`
145+
- Career auth gate modal: `src/index.html` + `src/styles.css`
146+
- State refresh: on startup `auth_restore_session` is called, then UI fetches `auth_get_current_user`
147+
148+
### Admin / Database view (local)
149+
150+
If you are logged in as `admin`, the header user menu shows **Admin / DB**.
151+
- It displays: user id, email, role, created-at, last login, and whether an active session exists.
152+
- It does **not** display any password or password hash.
153+
154+
## ETS2 Dispatcher Post-Write Validation
155+
156+
The ETS2 dispatcher write flow validates the written `game.sii` immediately after the file is updated.
157+
158+
- Validator source: `src-tauri/src/features/ets2save/post_write_validator.rs`
159+
- Trigger point: `src-tauri/src/features/ets2save/injector.rs`
160+
- UI output: Career Mode dispatcher detail panel, `Last Write Output`
161+
162+
The validator checks the full pointer chain:
163+
164+
1. `company.volatile.<company>.<city>` block exists
165+
2. expected `job_offer[i]` pointer still exists in that company block
166+
3. matching `job_offer_data : _nameless.*` block exists
167+
4. written fields match the expected dispatcher payload:
168+
`cargo`, `target`, `shortest_distance_km`, `expiration_time`
169+
170+
Result interpretation:
171+
172+
- `post_write_valid = true`
173+
The write is structurally valid. If ETS2 still does not show the job, the remaining cause is ETS2 load/cache state. Load the exact quicksave that was written.
174+
- `post_write_valid = false`
175+
The write is not valid for the expected depot/job chain. Use `validation.rootCause` and `validation.validationErrorCode` from the write output.
176+
177+
Root-cause mapping:
178+
179+
- `wrong_depot`: expected company block was not found after write
180+
- `wrong_slot`: expected `job_offer` pointer is missing from the company block
181+
- `write_corrupt`: `job_offer_data` block is missing for the selected pointer
182+
- `cargo_mismatch`: written cargo token does not match the expected token
183+
- `target_mismatch`: written target company does not match the expected target
184+
185+
The write output also includes an offer-slot scan so the selected `job_offer[i]` can be inspected when a depot contains multiple offer pointers.

ets2-tool/data/app.sqlite

2.67 MB
Binary file not shown.

ets2-tool/data/app.sqlite-shm

32 KB
Binary file not shown.

ets2-tool/data/app.sqlite-wal

3.41 MB
Binary file not shown.

0 commit comments

Comments
 (0)