diff --git a/CHANGELOG.md b/CHANGELOG.md index 87ef429..27ef78d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,94 @@ All notable changes to mobileGF2logger are documented here. +## 2.7.2 - 2026-11-07 + +### Security + +- Pin each supported game client's signing certificate the first time it is + seen and refuse to route or record traffic from a client whose signer + changed. Home's client rows show the trust state, and Settings lists the + pinned signers. After upgrading, a scheduled or standby run records "client + not trusted" until Home has been opened once. +- Bound every decoded payload to 32,768 elements, and every held pre-identity + payload and admission to 65,536 elements in total, so a small packet can no + longer expand into an outsized decode. +- Rebuild every restored `.gf2backup` into the app's own table definitions + instead of installing the archive's DDL. Refuse rows the app could never read + back (out-of-range counters and IDs, unknown enum values, oversized text, + BLOBs), and drop maintenance keys the app never writes. A live database that + still carries DDL from a restore made before 2.7.2 is rebuilt on its first + access. +- Keep Discord webhook tokens out of failure messages and logcat. +- Native forwarding: forward a client FIN only after the bytes before it, close + TCP and ICMP flows whose socket cannot be opened, purge datagram and web + flows before inspected TCP at the socket cap, and read the DNS QR bit in host + byte order. Host regression tests cover each fix. +- Never delete a picked export document on a provider the app refuses, or when + opening it fails. + +### Fixed + +- Quarantine a Platoon database found corrupt, whether while opening or while + hashing for a CSV undo, instead of letting it be recreated empty. Platoon + screens and capture notices report a damaged database and offer a rebuild, + including after the Settings screen that ran the backup is gone. +- Wait out a running CSV import on Platoon screens and in capture, and refuse + capture while an import recovery is incomplete. +- Roll back an interrupted import from a checkpoint written by the older schema. +- Re-check that capture is stopped wherever Platoon maintenance runs. +- Membership: store activity-dated joins and withdrawals as their own evidence + source and let Updates replace them. On upgrade, repair stale active flags, + duplicate open periods and the shadow periods older versions created, keeping + departed members inactive. Remove stored members without a real UID, and + never store a roster member with UID 0. +- Set aside rosters captured with the phone clock set ahead, rather than letting + them become the latest roster. +- Rebuild restored weekly history recorded under another reset zone, ignore + stored weekly overrides outside one day's domain, skip a weekly revision that + names a member deleted since it was built, and fall back to the live weekly + table when the active revision cannot be read. +- Gunsmoke Frontline: stop treating a near-reset capture as a closed opening + anchor, keep a near-reset Standard day exact only when one split remains, and + compare Updates correlation instants as integers. The 48-hour correlation + window now applies as intended, which can change a correlated join that older + versions placed outside it. +- Deliver every flow close, date held payloads by their arrival, rotate recent + history by a persisted recording sequence, and fsync history and roster files + before renaming them into place. +- CSV: keep quoted text exact, make the roster export importable without + changing names (a reversible prefix protects formula-like names in + spreadsheets), recognize re-imported rosters, and export Home's roster CSV + from the latest stored roster. +- Input: reject future manual membership dates and out-of-range UIDs and + Platoon IDs, validate manual weekly edits against the day's range and + evidence, compare a typed Platoon name in its typeable form before deleting, + and truncate Platoon text on a code point boundary. +- Standby: stop taps at any notice that follows a login, keep scheduled + recording matched to the saved Platoons, warn that a phone with a screen lock + stays unlocked, and mark results seen only when the user closes them. +- Keep open drafts, including the weekly cell editor's typed values, when the + Platoon changes or a screen is recreated, with each draft bound to its own + Platoon. +- Accessibility: announce state changes and capture stop reasons, add + tooltips, keep large-font values and every weekly cutline warning visible, and + let Home's capture notice wrap in full. +- Open the app and offer Stop from the capture notification, word English + capture counts correctly for one, and fit long cells in the weekly PNG. +- Commit the legacy Platoon's member order and cutlines like a scoped + Platoon's, and save member order only on real changes. + +### Changed + +- Platoon database schema 14 adds a set-aside flag for clock-suspect rosters. +- The CSV undo check is now a digest of primary evidence only, so a checkpoint + sealed by 2.7.1 is refused once. +- Report roster comparison deltas with honest certainty, and label game-zone + times when the phone clock reads differently. +- Consolidate the game ID range, SQLite identifier quoting, roster file naming, + export failure messages, screen-lock checks and the latest-roster read into + one place each. + ## 2.7.1 - 2026-10-25 ### Fixed diff --git a/DESIGN.md b/DESIGN.md index e945d7c..b7503e4 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -159,7 +159,7 @@ Home, Platoon, and Weekly share a 64dp bottom bar. Each destination has a 24dp i ### Capture Status Panel -Capture state, its localized latest notice, the one-time capture checklist, the two supported clients with their package IDs and install state, and the capture actions form one operational group. While stopped the panel offers One-time capture (primary) and Continuous capture; while preparing or capturing those are replaced by a single Stop action. +Capture state, its localized latest notice, the one-time capture checklist, the two supported clients with their package IDs and install or signer-trust state, and the capture actions form one operational group. While stopped the panel offers One-time capture (primary) and Continuous capture; while preparing or capturing those are replaced by a single Stop action. ### Weekly Table diff --git a/README.md b/README.md index 7da7c9d..5ca2d09 100644 --- a/README.md +++ b/README.md @@ -40,13 +40,18 @@ never stored. - Provides profile management for correcting server metadata without moving data and for deleting one isolated Platoon behind two confirmations and an exact-name check. - Guides first-time users through Main, Settings, Platoon management, weekly controls, and parsed-packet pages, with a persistent English/Korean selector and Skip action; the guide can be replayed from Settings. - Offers an overnight standby mode from Home's moon button: an all-black, - minimum-brightness screen that keeps the phone awake. With the optional - GF2logger accessibility service turned on, standby records members by itself - five minutes before each chosen server's daily reset: it starts capture, opens - the game, taps Start on the title screen, waits for the roster, closes the game - from Recents, and locks the phone after the last server. The service only taps - while the game is in front and reads nothing on screen except the foreground - app and the app names on Recents cards. + minimum-brightness screen that keeps the phone awake and unlocked until + standby ends; on a phone with a PIN, pattern, or password it says so and asks + once before the first use. With the optional GF2logger accessibility service + turned on, standby records members by itself five minutes before each chosen + server's daily reset: it starts capture, opens the game, taps where Start sits + on the title screen (every few seconds, until the game reports a login, and + for two minutes at most), waits for the roster, closes the game from Recents, + and locks the phone after the last server. Android 8 offers no lock action, so + there the phone is left to its own screen timeout. Tapping the standby screen + or switching to another app leaves standby without locking the phone. The + service only taps while the game is in front and reads nothing on screen + except the foreground app and the app names on Recents cards. - On a phone without a PIN, pattern, or password, can instead record every day on a schedule from Settings: an alarm wakes the phone before each chosen server's reset, records members the same way, and turns the screen off again. @@ -56,6 +61,9 @@ never stored. Selecting a detected Platoon automatically follows that profile's saved region. - Registers the HaoPlay (`com.haoplay.game.and.exilium`) and Darkwinter (`com.Sunborn.SnqxExilium.Glo`) Android clients as separate VPN targets. + The signing certificate first seen for each client is trusted; a client + reinstalled under another signer is neither captured nor opened until you + trust it again in Settings. - Creates UTF-8 Platoon-member CSV files with this column order: ```text diff --git a/README_KR.md b/README_KR.md index 4d3891a..24cab32 100644 --- a/README_KR.md +++ b/README_KR.md @@ -33,11 +33,11 @@ mobileGF2logger는 서클장을 위한 가벼운 비루팅 앱입니다. Android - 새 서클은 확인된 클라이언트에 맞는 서버를 사용자가 선택할 때까지 패킷을 제한된 메모리에만 보관하며, 강제 종료 또는 프로세스 종료 시 확인되지 않은 데이터를 버립니다. - 서버 정보는 데이터를 이동하지 않고 수정할 수 있으며, 서클 삭제는 두 번의 확인과 정확한 서클 이름 입력을 거쳐 해당 격리 데이터만 제거합니다. - 첫 사용 시 메인, 설정, 서클 관리, 주간 기능, 파싱 패킷 화면을 안내하며, 한국어/English 전환과 건너뛰기를 지원합니다. 안내는 설정에서 다시 볼 수 있습니다. -- 홈의 달 버튼으로 밤샘 대기 모드를 켤 수 있습니다. 화면을 완전히 검게, 밝기를 최소로 두고 휴대전화를 깨어 있게 유지합니다. 선택 사항인 GF2logger 접근성 서비스를 켜면, 선택한 서버마다 일일 초기화 5분 전에 캡처를 시작하고 게임을 열어 타이틀 화면의 시작을 누른 뒤 멤버 명단을 기다렸다가, 최근 앱 화면에서 게임을 닫고 마지막 서버가 끝나면 휴대전화를 잠급니다. 이 서비스는 게임이 앞에 있을 때만 누르며, 앞에 있는 앱과 최근 앱 카드의 앱 이름 외에는 화면 내용을 읽지 않습니다. +- 홈의 달 버튼으로 밤샘 대기 모드를 켤 수 있습니다. 화면을 완전히 검게, 밝기를 최소로 두고 대기 모드가 끝날 때까지 휴대전화를 잠그지 않은 채 깨어 있게 유지합니다. PIN·패턴·비밀번호가 있는 휴대전화에서는 처음 사용할 때 이 점을 알리고 한 번 확인받습니다. 선택 사항인 GF2logger 접근성 서비스를 켜면, 선택한 서버마다 일일 초기화 5분 전에 캡처를 시작하고 게임을 열어 타이틀 화면의 시작 위치를 누른 뒤(게임이 로그인을 알릴 때까지 몇 초마다, 최대 2분) 멤버 명단을 기다렸다가, 최근 앱 화면에서 게임을 닫고 마지막 서버가 끝나면 휴대전화를 잠급니다. Android 8에는 잠금 동작이 없어 화면 자동 꺼짐에 맡깁니다. 대기 화면을 누르거나 다른 앱으로 전환하면 휴대전화를 잠그지 않은 채 대기 모드가 끝납니다. 이 서비스는 게임이 앞에 있을 때만 누르며, 앞에 있는 앱과 최근 앱 카드의 앱 이름 외에는 화면 내용을 읽지 않습니다. - PIN·패턴·비밀번호가 없는 휴대전화에서는 설정의 예약 자동 기록으로 매일 기록할 수도 있습니다. 선택한 서버마다 초기화 전에 알람이 휴대전화를 깨워 같은 방식으로 멤버를 기록하고 화면을 다시 끕니다. - 화면을 가장자리까지 그리며, 회전·테마·언어 변경이나 프로세스 재생성 후에도 작성 중인 내용과 선택, 대기 중인 내보내기를 유지합니다. - 영어와 한국어, 시스템/라이트/다크 테마를 지원합니다. 알려진 Darkwinter/HaoPlay 6개 서버 지역의 초기화 시각을 기기 시간대로 환산하며, 감지된 서클을 선택하면 해당 프로필에 저장된 지역을 자동으로 따릅니다. -- HaoPlay(`com.haoplay.game.and.exilium`)와 Darkwinter(`com.Sunborn.SnqxExilium.Glo`) Android 클라이언트를 별도의 VPN 대상으로 등록합니다. +- HaoPlay(`com.haoplay.game.and.exilium`)와 Darkwinter(`com.Sunborn.SnqxExilium.Glo`) Android 클라이언트를 별도의 VPN 대상으로 등록합니다. 클라이언트마다 처음 확인한 서명 인증서를 신뢰하며, 다른 서명으로 다시 설치된 클라이언트는 설정에서 다시 신뢰하기 전까지 캡처하거나 실행하지 않습니다. - 다음 열 순서의 UTF-8 서클 멤버 CSV 파일을 만듭니다. ```text diff --git a/SECURITY.md b/SECURITY.md index 8616586..c5edc4f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,8 +7,10 @@ Security fixes are made on the latest published release and the current | Version | Supported | | --- | --- | -| 2.4.x | Yes | -| 2.3.x and earlier | No | +| 2.7.x | Yes | +| 2.6.x and earlier | No | + +Update this table with every minor release. ## Reporting a vulnerability @@ -28,7 +30,9 @@ Include: - the expected and observed behavior; - the impact and any user interaction required; and - whether the issue affects capture, parsing, CSV import/export, backup/restore, - Discord sharing, local persistence, or release signing. + Discord sharing, local persistence, standby automation (the accessibility + service), scheduled recording (exact alarms and the boot receiver), or + release signing. Do not test against another person's device, game account, Discord webhook, or network traffic. Remove UIDs, names, notes, webhook secrets, signing material, @@ -44,11 +48,30 @@ plaintext protocol. Parsed data and backups therefore provide local integrity and management convenience, not cryptographic proof that a remote payload is genuine. +A package name alone does not make an app a supported client. The publishers' +signing certificates are not known in advance, so GF2logger pins, per supported +package, the SHA-256 digests of the signing certificates it first sees installed +while the user is using the app: when Home is shown, or when capture, standby, +or scheduled recording is started from the app. Capture routes, attributes, and +standby or scheduled recording opens a client only while every pinned +certificate still signs it (Android 9 and newer ask `hasSigningCertificate`, +which honours APK Signature Scheme v3 key rotation; Android 8 compares the +current signatures). Background work never pins. Uninstalling a client keeps its +pin, so the same publisher's reinstall matches and an app installed under that +package name by anyone else is left outside the VPN, never attributed, and never +launched, with a capture notice or standby result saying why, until the user +reviews the new certificate's fingerprint in Settings and trusts it explicitly. +The limit is that of any trust on first use: whatever is installed under a +supported package name the first time GF2logger sees it is trusted. Pins are +kept in app-private preferences, which Android backup excludes and `.gf2backup` +archives never contain. + On Android 10 and newer, the active VPN asks Android for the UID owning an original connection tuple and maps that UID only to the fixed supported package -IDs. Remote IP addresses and DNS/SNI labels are diagnostic hints, not trusted -client or server identities. Android 8–9 falls back only when exactly one -supported client is installed; ambiguous flows remain quarantined. Payload +IDs whose signer is verified. Remote IP addresses and DNS/SNI labels are +diagnostic hints, not trusted client or server identities. Android 8–9 falls +back only when exactly one verified supported client is installed; ambiguous +flows remain quarantined. Payload `21905` supplies a bounded Platoon identity for its own decoded flow. Its banner frame and mark are accepted only as scalar IDs in the closed game-defined range `1..6`; unknown values remain undisplayed rather than selecting arbitrary local @@ -86,24 +109,81 @@ scoped settings, and retained CSV retirement share one durable restore journal. A process death before the commit marker restores the previous values together. Destructive profile deletion requires two confirmations including an exact-name match, then uses a durable deletion queue so interrupted scoped cleanup resumes -before profiles are listed again. +before profiles are listed again. Deletion is refused while that Platoon's CSV +import or undo runs, and work that was already running cannot recreate the +deleted database. It also removes the restore rollback and staging copies, +quarantined corrupt copies, the weekly PNG share cache, and a capture +diagnostics status that names the Platoon. Exports and Discord sends are explicit user actions that move selected data out of Android private storage. Backups are checksummed and strictly validated but are not encrypted or signed. Treat exported files and webhook destinations as -sensitive. +sensitive. A restore never installs the selected file's schema: after +validation its rows are copied, column by column, into a database that the +current schema code creates, so table constraints an archive declares (CHECK, +ON CONFLICT, COLLATE, STRICT, WITHOUT ROWID) are discarded and the installed +DDL must equal the app's own text exactly. The copied rows are refused, and the +restore fails as an invalid backup, when an enum column holds a name the app +does not define, a text value is oversized, or a row id or AUTOINCREMENT +counter is out of range; maintenance keys the app never writes are dropped. A +Platoon restored before 2.7.2, which installed the selected file as it was, is +checked once per launch before its first use: table DDL the app never wrote is +rebuilt into the app's own schema the same way, keeping every row. +While a Platoon's CSV import or +undo holds its checkpoint claim, captures, edits, and backup restores of that +Platoon are refused instead of being sealed into, or later erased by, the +import's undo. + +A database that fails SQLite's integrity check is never exported or used for a +CSV checkpoint. A database that SQLite reports as corrupt is moved aside under a +`.corrupt-