Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ jobs:

steps:
- name: Check out repository
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Set up JDK 17
uses: actions/setup-java@v5
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: "17"

- name: Set up Gradle
uses: gradle/actions/setup-gradle@v6
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6

- name: Make Gradle wrapper executable
run: chmod +x gradlew
Expand Down Expand Up @@ -68,15 +68,15 @@ jobs:

mkdir -p ci-artifacts
cp "${apk}" \
ci-artifacts/mobileGF2logger-v2.1.0-unsigned-verification-only.apk
"ci-artifacts/mobileGF2logger-${GITHUB_SHA::12}-unsigned-verification-only.apk"
cat > ci-artifacts/DO_NOT_DISTRIBUTE.txt <<'EOF'
This unsigned APK exists only to verify compilation, lint, native
packaging, minification, and resource shrinking in CI. It cannot be
installed as a production update and must not be published.
EOF

- name: Upload unsigned verification artifact
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: unsigned-verification-only-do-not-distribute
path: ci-artifacts/
Expand Down
20 changes: 10 additions & 10 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ jobs:

steps:
- name: Check out repository
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Set up JDK 17
uses: actions/setup-java@v5
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: "17"

- name: Set up Gradle
uses: gradle/actions/setup-gradle@v6
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6

- name: Make Gradle wrapper executable
run: chmod +x gradlew
Expand All @@ -47,7 +47,7 @@ jobs:
"${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager" "cmake;3.22.1"

- name: Initialize CodeQL
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
with:
languages: c-cpp
build-mode: manual
Expand All @@ -62,7 +62,7 @@ jobs:
--stacktrace

- name: Analyze C/C++
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
with:
category: "/language:c-cpp"

Expand All @@ -77,22 +77,22 @@ jobs:

steps:
- name: Check out repository
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Set up JDK 17
uses: actions/setup-java@v5
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: "17"

- name: Set up Gradle
uses: gradle/actions/setup-gradle@v6
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6

- name: Make Gradle wrapper executable
run: chmod +x gradlew

- name: Initialize CodeQL
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
with:
languages: java-kotlin
build-mode: manual
Expand All @@ -107,6 +107,6 @@ jobs:
--stacktrace

- name: Analyze Kotlin
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
with:
category: "/language:java-kotlin"
10 changes: 5 additions & 5 deletions .github/workflows/deploy-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ jobs:

steps:
- name: Check out repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Configure GitHub Pages
id: pages
uses: actions/configure-pages@v5
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6

- name: Prepare Pages source
shell: bash
Expand Down Expand Up @@ -203,7 +203,7 @@ jobs:
'google-site-verification: google1d4c3f230e6af424.html'

- name: Build with Jekyll
uses: actions/jekyll-build-pages@v1
uses: actions/jekyll-build-pages@44a6e6beabd48582f863aeeb6cb2151cc1716697 # v1
with:
source: ./.pages-src
destination: ./_site
Expand Down Expand Up @@ -235,7 +235,7 @@ jobs:
'google-site-verification: google1d4c3f230e6af424.html'

- name: Upload GitHub Pages artifact
uses: actions/upload-pages-artifact@v4
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5
with:
path: ./_site

Expand All @@ -252,4 +252,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5
50 changes: 50 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,56 @@ All notable changes to mobileGF2logger are documented here.

## Unreleased

### Added

- Make every weekly metric cell explain its value, certainty, and supporting
facts when tapped, and add an Evidence Health panel summarizing observed,
exact, lower-bound, unknown, Login, Daily Patrol, and closing-boundary data.
- Add guided capture with a live Members, Activity, and Updates checklist that
stops automatically when all three management payloads have arrived.
- Preview the effects of one or more roster CSV files before mutation, create a
private automatic checkpoint before import, and provide one-level undo for
the most recent confirmed import.
- Export the displayed weekly table as a bounded PNG or share it through
Android, with independent controls for member names, UIDs, and private notes.
UIDs and private notes remain excluded by default.
- Send a parsed packet's validated original CSV body to a user-configured
Discord incoming webhook after explicit confirmation. The webhook is stored
with Android Keystore encryption and is never displayed after saving.
- Add a security policy with private-reporting and data-redaction guidance.

### Changed

- Move weekly navigation and stale-result validity into a lifecycle-independent
state holder, persist the selected week across recreation, and recycle heavy
weekly member rows in a bounded `RecyclerView` viewport.
- Extract standard-week counter inference from report assembly and extract
weekly snapshot projection SQL from the schema and transaction helper.
- Pin every GitHub Action to a verified commit SHA and make unsigned CI artifact
names commit-specific instead of carrying a stale release version.
- Add deterministic randomized invariants for standard-week inference and
malformed protocol streams alongside focused tests for evidence, sharing,
guided capture, import preview, checkpoint identity, and webhook policy.
- Clarify guided capture, stop, and Discord actions with accessible color,
Discord icons, aligned packet actions, and an explicit webhook-availability
indicator.

### Fixed

- Reject stale asynchronous weekly renders after navigation, pause, or screen
recreation and preserve the selected reporting date instead of allowing
overlapping week loads to replace each other.
- Keep newly selected CSV sources unretained until the user confirms the impact
preview, recover unfinished checkpoints before reading the preview baseline,
reconcile crash-left evidence before classification, cap multi-file imports,
preserve the preceding undo until a replacement import seals, and recover
database/quarantine state after a failed import, undo, or process death.
- Bound weekly PNG dimensions, pixel count, row count, and private-note length;
preserve pending save state across activity recreation, and share only through
a cache-scoped non-exported `FileProvider` grant.
- Restrict Discord destinations to canonical HTTPS `discord.com` incoming
webhook URLs, disallow redirects, and bound request/response sizes and timeouts.

## 2.1.2 - 2026-08-09

### Changed
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ capture to the selected game package, and raw traffic is never stored.
- Captures the mandatory Members (`21917`), Activity (`21935`), and Updates (`21960`) responses without a computer or root access.
- Tracks active and withdrawn members, repeat membership periods, exact Updates timestamps, editable nicknames, and private notes.
- Builds Sunday-to-Saturday Standard or Gunsmoke Frontline weekly tables around the 05:00 game reset, with cut-off points and manual correction for missing data.
- Offers guided capture that tracks the three useful Platoon payloads and stops automatically when the checklist is complete.
- Explains every weekly cell on tap and summarizes missing or uncertain evidence in an Evidence Health panel.
- Recovers interrupted imports before previewing roster CSV impact and keeps an automatic one-level checkpoint for undo.
- Saves or shares a weekly PNG with opt-in controls for names, UIDs, and private notes.
- Can send a validated original CSV to an optional user-owned Discord incoming webhook after confirmation.
- Stores the latest 100 parsed packets and up to 50 saved packets, with table and raw views, copy, export, selection, and deletion.
- Supports member sorting, persistent drag ordering, snapshot comparison, single-week and all-week CSV export, and complete `.gf2backup` export/restore.
- Supports English and Korean and uses the Android device timezone for display.
Expand All @@ -36,3 +41,9 @@ uid,name,level,weeklyMerit,totalMerit,highScore,totalScore,lastLogin,logTime
5. Return to GF2logger to review the captured packets and Platoon data.

The app keeps parsed history, management data, and generated CSV files in private on-device storage. It does not bypass TLS, certificate pinning, or anti-cheat systems, and it does not modify game traffic. Server responses may contain only recent incremental history, so older missing membership records can be entered manually.

## Reference

mobileGF2logger was inspired by [blead/gfl2logger](https://github.com/blead/gfl2logger),
a GF2 logger for the Windows client. This project is an independent Android
implementation tailored to on-device Platoon management.
9 changes: 9 additions & 0 deletions README_KR.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ mobileGF2logger는 서클장을 위한 가벼운 비루팅 앱입니다. Android
- 컴퓨터나 루트 권한 없이 필수 멤버(`21917`), 활동(`21935`), 동향(`21960`) 응답을 캡처합니다.
- 가입 및 탈퇴 멤버, 반복 가입 이력, 동향의 정확한 시각, 수정 가능한 닉네임과 개인 비고를 관리합니다.
- 05:00 게임 초기화 시각을 기준으로 일요일부터 토요일까지의 일반 주간 또는 흙먼지 주간 표를 만들며, 커트라인과 누락 데이터 수동 수정을 지원합니다.
- 안내형 캡처는 세 가지 유용한 서클 페이로드의 수집 상태를 표시하고 체크리스트가 완료되면 자동으로 중지합니다.
- 모든 주간 셀을 누르면 근거를 설명하고, 근거 상태 패널에서 누락되거나 불확실한 데이터를 요약합니다.
- 중단된 가져오기를 먼저 복구한 뒤 명단 CSV의 영향을 미리 보여 주고, 실행 취소용 1단계 자동 체크포인트를 보관합니다.
- 이름, UID, 비공개 메모의 포함 여부를 선택해 주간 PNG를 저장하거나 공유할 수 있습니다.
- 확인 후 검증된 원본 CSV를 사용자가 소유한 선택적 Discord 수신 웹훅으로 전송할 수 있습니다.
- 최근 파싱 패킷 100개와 저장 패킷 50개를 보관하며, 표 및 원본 보기, 복사, 내보내기, 선택, 삭제를 지원합니다.
- 멤버 정렬, 드래그 순서 유지, 최근 스냅샷 비교, 주간 CSV 내보내기, 서클 관리 데이터 백업 및 복원을 지원합니다.
- 영어와 한국어를 지원하며 화면에 표시하는 시각에는 Android 기기의 시간대를 사용합니다.
Expand All @@ -31,3 +36,7 @@ uid,name,level,weeklyMerit,totalMerit,highScore,totalScore,lastLogin,logTime
5. GF2logger로 돌아와 캡처한 패킷과 서클 데이터를 확인합니다.

앱은 파싱 내역, 관리 데이터, 생성한 CSV 파일을 기기의 비공개 저장소에 보관합니다. TLS, 인증서 고정 또는 안티치트 체계를 우회하지 않으며 게임 트래픽을 변경하지 않습니다. 서버 응답에는 최근의 일부 이력만 포함될 수 있으므로, 누락된 과거 가입 이력은 직접 추가할 수 있습니다.

## 참고

mobileGF2logger는 Windows 클라이언트용 GF2 로거인 [blead/gfl2logger](https://github.com/blead/gfl2logger)에서 영감을 받은, Android 기기 내 서클 관리에 맞춘 독립적인 구현입니다.
50 changes: 50 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Security policy

## Supported versions

Security fixes are made on the latest published release and the current
`main` branch. Older releases should be upgraded before a report is evaluated.

## Reporting a vulnerability

Please do not publish exploit details, captured player data, backup archives,
or packet payloads in a public issue.

Use the repository's **Security** tab to submit a private vulnerability report
when that option is available. If private reporting is unavailable, contact the
maintainer through the GitHub profile linked from the repository and request a
private channel without including sensitive details in the first message.

Include:

- the affected version or commit;
- the Android version and device architecture;
- the smallest reproducible input using synthetic data;
- 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.

Do not test against another person's device, game account, Discord webhook, or
network traffic. Remove UIDs, names, notes, webhook secrets, signing material,
and real packet contents from reproductions.

## Security boundaries

mobileGF2logger observes traffic only after Android grants `VpnService` consent
for a user-selected package. It does not decrypt TLS or authenticate the game's
plaintext protocol. Parsed data and backups therefore provide local integrity
and management convenience, not cryptographic proof that a remote payload is
genuine.

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.

## Response expectations

The maintainer will acknowledge a reproducible report, assess severity, and
coordinate a fix and disclosure timeline. A report may be closed when it is a
duplicate, requires a rooted/compromised Android system outside this project's
control, or does not cross a documented security boundary.
10 changes: 6 additions & 4 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ android {
applicationId = 'dev.gf2log'
minSdk = 26
targetSdk = 36
versionCode = 20102
versionName = '2.1.2'
versionCode = 20200
versionName = '2.2.0'
testInstrumentationRunner = 'androidx.test.runner.AndroidJUnitRunner'

ndk {
Expand Down Expand Up @@ -223,7 +223,9 @@ android {

dependencies {
implementation project(':protocol')
implementation 'androidx.core:core:1.17.0'
implementation 'androidx.recyclerview:recyclerview:1.4.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.6.2'
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test:runner:1.7.0'
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
}
Loading
Loading