fancymax/12306ForMac
An unofficial 12306 Client for Mac
Stale — last commit 7y ago
worst of 4 axeslast commit was 7y ago; top contributor handles 98% of recent commits…
no tests detected; no CI workflows detected…
Documented and popular — useful reference codebase to read through.
last commit was 7y ago; no CI workflows detected
- ✓2 active contributors
- ✓MIT licensed
- ⚠Stale — last commit 7y ago
Show 4 more →Show less
- ⚠Small team — 2 contributors active in recent commits
- ⚠Single-maintainer risk — top contributor 98% of recent commits
- ⚠No CI workflows detected
- ⚠No test directory detected
What would change the summary?
- →Use as dependency Concerns → Mixed if: 1 commit in the last 365 days
- →Fork & modify Mixed → Healthy if: add a test suite
- →Deploy as-is Mixed → Healthy if: 1 commit in the last 180 days
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Great to learn from" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/fancymax/12306formac)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/fancymax/12306formac on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: fancymax/12306ForMac
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/fancymax/12306ForMac shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Stale — last commit 7y ago
- 2 active contributors
- MIT licensed
- ⚠ Stale — last commit 7y ago
- ⚠ Small team — 2 contributors active in recent commits
- ⚠ Single-maintainer risk — top contributor 98% of recent commits
- ⚠ No CI workflows detected
- ⚠ No test directory detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live fancymax/12306ForMac
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/fancymax/12306ForMac.
What it runs against: a local clone of fancymax/12306ForMac — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in fancymax/12306ForMac | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 2698 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of fancymax/12306ForMac. If you don't
# have one yet, run these first:
#
# git clone https://github.com/fancymax/12306ForMac.git
# cd 12306ForMac
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of fancymax/12306ForMac and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "fancymax/12306ForMac(\\.git)?\\b" \\
&& ok "origin remote is fancymax/12306ForMac" \\
|| miss "origin remote is not fancymax/12306ForMac (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "12306ForMac/Service/Service.swift" \\
&& ok "12306ForMac/Service/Service.swift" \\
|| miss "missing critical file: 12306ForMac/Service/Service.swift"
test -f "12306ForMac/AppDelegate.swift" \\
&& ok "12306ForMac/AppDelegate.swift" \\
|| miss "missing critical file: 12306ForMac/AppDelegate.swift"
test -f "12306ForMac/MainWindowController.swift" \\
&& ok "12306ForMac/MainWindowController.swift" \\
|| miss "missing critical file: 12306ForMac/MainWindowController.swift"
test -f "12306ForMac/RealmModel/DataManager.swift" \\
&& ok "12306ForMac/RealmModel/DataManager.swift" \\
|| miss "missing critical file: 12306ForMac/RealmModel/DataManager.swift"
test -f "12306ForMac/Model/MainModel.swift" \\
&& ok "12306ForMac/Model/MainModel.swift" \\
|| miss "missing critical file: 12306ForMac/Model/MainModel.swift"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 2698 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~2668d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/fancymax/12306ForMac"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
12306ForMac is an unofficial macOS client for China Railways' 12306 ticketing system that enables automated ticket booking and monitoring without needing Windows VMs or the official web interface. Built in Swift with Alamofire networking, PromiseKit async/await patterns, and FMDB SQLite persistence, it provides a native macOS app for ticket queries, purchasing automation, and seat availability alerts. Monolithic Xcode project: 12306ForMac/ contains all source (AppDelegate.swift, BaseWindowController.swift as entry points), 12306ForMac.xcodeproj/ holds build config and Carthage dependencies, Images.xcassets/ holds UI resources (AppIcon, Filter, Reminder, Direction icons). Bridging header 12306ForMac-Bridging-Header.h mixes Swift/Objective-C. No visible src/ subdirectories or modular structure.
👥Who it's for
Mac users in China who need to book train tickets on the 12306 system and want a native desktop experience instead of opening the official web portal or running Windows virtualization. Primarily appeals to frequent travelers and those who want automation features the official clients lack.
🌱Maturity & risk
This is an experimental/maintenance-mode project: it's a single-maintainer (fancymax) repository built for Swift 3.2 on OS X 10.13–Xcode 9.0 (notably outdated toolchain). No visible CI/CD, no test suite in the file structure, and likely broken against current 12306 API versions (the README explicitly warns 'may not work normally as 12306 interfaces change'). Not production-ready for critical bookings.
High risk: (1) Reverse-engineered 12306 API calls are fragile—any backend changes break the app silently; (2) Swift 3.2 and Xcode 9 are ancient (2017), making it unmaintainable on modern Macs (Xcode 15+); (3) Dependency chain includes Carthage-managed Alamofire, PromiseKit, FMDB with no version pinning visible; (4) Single maintainer with no recent activity suggested; (5) No test coverage means regressions hide until users report failures. Do not use for production train booking.
Active areas of work
No active development visible from file structure alone. The repo appears dormant—Swift 3.2 syntax, no recent commits indicated, Xcode 9 project files unchanged. This is a 'historical snapshot' rather than an actively maintained project.
🚀Get running
git clone --recursive https://github.com/fancymax/12306ForMac.git
cd 12306ForMac
brew install carthage
carthage update --platform macOS
open 12306ForMac.xcodeproj
Then build with Xcode 9 (or attempt migration to modern Swift). The --recursive flag fetches Carthage dependencies as git submodules.
Daily commands:
Open 12306ForMac.xcodeproj in Xcode 9 (or newer, if you manually fix Swift 3→5 migration), ensure Carthage dependencies are built (carthage update --platform macOS), then run the Scheme 12306ForMac (Cmd+R). This will launch the macOS app. Warning: Will likely fail to connect to 12306 API if servers have changed.
🗺️Map of the codebase
12306ForMac/Service/Service.swift— Core HTTP client and API gateway that all ticket queries, login, and order operations depend on; handles session management and request routing12306ForMac/AppDelegate.swift— macOS application entry point; initializes main window, database, and lifecycle hooks that all features depend on12306ForMac/MainWindowController.swift— Primary UI controller for ticket search and filtering; orchestrates communication between service layer and UI components12306ForMac/RealmModel/DataManager.swift— Data persistence abstraction layer using Realm; manages user profiles, saved searches, and cached ticket data12306ForMac/Model/MainModel.swift— Central data model holding session state, query results, and UI state; bridges service responses and view controllers12306ForMac/Service/Service+Login.swift— Authentication flow including captcha solving and credential validation; prerequisite for all protected API calls12306ForMac/Service/Service+Order.swift— Order submission and payment initiation logic; implements the critical booking workflow with queue management
🛠️How to make changes
Add a new API endpoint (e.g., query new route info)
- Create a new Swift struct conforming to Codable for request/response in Model/ folder (
12306ForMac/Model/MyNewParam.swift) - Add a new extension method in Service layer (e.g., Service+NewFeature.swift) that calls Service.request() with the endpoint URL and parameters (
12306ForMac/Service/Service+NewFeature.swift) - Call the new service method from MainWindowController or relevant view controller, passing a completion handler that updates MainModel state (
12306ForMac/MainWindowController.swift) - Bind UI updates via KVO or property observers on MainModel properties to reflect API results in the window (
12306ForMac/Model/MainModel.swift)
Add a new preference panel (e.g., Notification settings)
- Create a new XIB file with UI controls (checkboxes, dropdowns) in Preferences/ folder (
12306ForMac/Preferences/NotificationPreferenceViewController.xib) - Create corresponding Swift view controller class with @IBOutlet bindings and a PreferenceManager subclass for UserDefaults persistence (
12306ForMac/Preferences/NotificationPreferenceViewController.swift) - Register the new preference pane in the main preferences window (typically in AppDelegate or a preferences coordinator) (
12306ForMac/AppDelegate.swift) - Consume saved preferences in MainWindowController or Service layer when needed (e.g., check notification flag before displaying alerts) (
12306ForMac/MainWindowController.swift)
Add a new filter option (e.g., filter by station)
- Add a new filter property to FilterPreferenceManager to persist the user's selection (
12306ForMac/Preferences/AdvancedPreferenceManager.swift) - Update FilterPreferenceViewController.xib with a new UI control (checkbox, dropdown) for the filter criterion (
12306ForMac/Preferences/FilterPreferenceViewController.xib) - Add an @IBAction in FilterPreferenceViewController to read the UI control and save to AdvancedPreferenceManager (
12306ForMac/Preferences/FilterPreferenceViewController.swift) - Implement filtering logic in MainWindowController when displaying results, checking the filter setting from AdvancedPreferenceManager (
12306ForMac/MainWindowController.swift)
Enhance CAPTCHA solving (e.g., switch captcha provider)
- Create a new protocol in Service/Dama.swift or a new file defining the CAPTCHA service interface (
12306ForMac/Service/Dama.swift) - Implement a new adapter class conforming to that protocol (e.g., CaptchaProvider2, CaptchaProviderOCR) with actual solving logic (
12306ForMac/Service/Service+Login.swift) - Refactor Service+Login.swift to inject the captcha provider as a dependency (or use a factory) so it can be swapped at runtime (
12306ForMac/Service/Service+Login.swift) - Add a preference in AdvancedPreferenceViewController to allow users to select which captcha provider to use (
12306ForMac/Preferences/AdvancedPreferenceViewController.swift)
🔧Why these technologies
- Swift + Cocoa/AppKit — Native macOS
🪤Traps & gotchas
Major trap 1: Carthage bootstrap required—carthage update --platform macOS must complete before Xcode build succeeds; if skipped, linker errors on Alamofire/PromiseKit. Trap 2: Swift 3.2 syntax is archaic; modern Xcode (14+) will reject this without full migration (2-3 days of refactoring for Swift 5.x). Trap 3: 12306 API calls are reverse-engineered and undocumented—no mock server, no integration tests; you must run against live API to debug. Trap 4: The entitlements file suggests network requests may need special sandbox capabilities (check for NSLocalNetworkUsageDescription in Info.plist if modern Xcode enforces it). Trap 5: Session/auth cookies likely stored in Keychain via some (unlisted) auth wrapper—missing knowledge of credential handling will break login.
🏗️Architecture
💡Concepts to learn
- Reverse-Engineered API & Session Management — 12306ForMac calls undocumented 12306 backend endpoints (no official API contract); understanding HTTP session cookies, CSRF tokens, and stateful login flows is essential to debug breakage and add new features
- Promise-Based Async Patterns (PromiseKit) — The entire 12306 API call chain is built on Promise chaining (Alamofire.request().then().catch()); this is pre-async/await Swift, so understanding Promise composition is key to reading the network layer
- Carthage Dependency Management — Project uses Carthage (not CocoaPods or SPM); understanding Cartfile resolution, binary framework linking, and platform-specific builds is required to troubleshoot dependency issues
- Swift-Objective-C Bridging — The bridging header (12306ForMac-Bridging-Header.h) indicates legacy Objective-C code interop; understanding how bridging headers expose C/ObjC APIs to Swift is needed to modify mixed-language code
- macOS Sandbox Entitlements & Capabilities — The .entitlements file gates network access and system resources on macOS; understanding App Sandbox rules is critical for debugging permission denials on modern macOS versions
- SQLite via FMDB — Local ticket data, user profiles, and booking history are stored in SQLite (via FMDB wrapper); understanding schema design and query patterns is needed to add new data features
- Cocoa AppKit MVC & Window Controllers — UI is built with legacy Cocoa (not SwiftUI); BaseWindowController and AppDelegate use NSWindowController/NSViewController delegates—understanding Cocoa lifecycle is required for UI work
🔗Related repos
testerSunny/12306— Python-based 12306 ticketing bot; demonstrates the same reverse-engineered 12306 API in a different ecosystem, useful for understanding API contract detailszhaojiedi1992/hello_world_python_12306— Another Python 12306 automation library; provides alternative implementation patterns for login, query, and booking flows that could inform Swift refactoringAlamofire/Alamofire— The HTTP networking library powering 12306ForMac—understanding its 4.x/5.x API evolution is critical for modernizing this project's network codemxcl/PromiseKit— The Promise/async library used throughout 12306ForMac for chaining API calls; understanding its patterns is essential for understanding async flow in this codebaseccgus/fmdb— SQLite wrapper used for local ticket/user data persistence; the reference for understanding how database queries are structured in 12306ForMac
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Remove xcuserdata and build artifacts from version control
The repo contains multiple xcuserdata directories (dream.xcuserdatad, lindahai.xcuserdatad) and UserInterfaceState.xcuserstate files which are personal Xcode workspace settings that should never be committed. This pollutes the repo, causes merge conflicts, and violates .gitignore best practices. Adding proper Xcode exclusions to .gitignore will clean up the repo and prevent future contributor conflicts.
- [ ] Update .gitignore to include '/*.xcuserdata', '/.xcworkspace/xcuserdata', and '**/.xcworkspace/xcuserstate'
- [ ] Remove all xcuserdata directories and nested UserInterfaceState.xcuserstate files from git history using git rm --cached
- [ ] Remove Breakpoints_v2.xcbkptlist files that are personal debugger settings
- [ ] Test by cloning fresh copy and verifying no xcuserdata appears on git status
Add Swift unit tests for Model layer (AutoSubmitParams, OrderDTO, PassengerDTO)
The Model directory contains 16+ data model files (AutoSubmitParams.swift, OrderDTO.swift, PassengerDTO.swift, QueryLeftNewDTO.swift, etc.) with no corresponding test files. These models handle critical 12306 API responses and parameter construction. Unit tests would catch serialization/deserialization bugs, improve maintainability as the 12306 API evolves, and provide examples for contributors.
- [ ] Create 12306ForMacTests directory structure mirroring Model/ layout
- [ ] Add XCTest file for OrderDTO.swift testing JSON decoding with sample 12306 API responses
- [ ] Add XCTest file for PassengerDTO.swift testing passenger data validation and encoding
- [ ] Add XCTest file for AutoSubmitParams.swift testing parameter construction for ticket submission
- [ ] Add test targets to 12306ForMac.xcodeproj/project.pbxproj and verify tests run via carthage setup
Add GitHub Actions CI workflow for building and testing on macOS
The repo lacks any CI/CD pipeline. With Swift/Xcode projects, this means PRs aren't automatically validated for build failures or regressions. Adding a GitHub Actions workflow to build the project (carthage update, xcodebuild) and run tests on each push/PR will catch integration issues early and increase contributor confidence.
- [ ] Create .github/workflows/build.yml that triggers on push and pull_request
- [ ] Add steps to checkout repo with submodules (--recursive as noted in README)
- [ ] Add step to install carthage via brew and run 'carthage update --platform macOS'
- [ ] Add step to build project with xcodebuild -workspace 12306ForMac.xcodeproj/project.xcworkspace -scheme 12306ForMac -configuration Release
- [ ] Add step to run unit tests (from PR #2) via xcodebuild test
- [ ] Add badge to README showing build status
🌿Good first issues
- Add unit test scaffold: Create
12306ForMacTests/bundle and write tests for PromiseKit-based Alamofire API call chains in the (hidden) network layer—repo has zero test coverage and is vulnerable to silent API breakage. Start with a mock URLSession + PromiseKit test for a simple 12306 endpoint. - Modernize Swift 3.2 → 5.9: File-by-file migration of Swift syntax (replace
as!with safe unwrapping, migrate@noescapeclosures to modern async/await, update Alamofire 4.x calls to 5.x API). This unblocks building on Xcode 15+ and macOS Sonoma/Sequoia. - Document 12306 API surface: Create
docs/API.mdreverse-engineering the 12306 endpoint calls (login, query trains, book tickets) visible in the (hidden) networking code; include request/response schemas, auth flow, and cookie handling. Will help future maintainers debug API changes.
📝Recent commits
Click to expand
Recent commits
ff69af8— update README (fancymax)972c002— Merge pull request #210 from qyf404/master (fancymax)4915451— update SwiftyJSON version (QiYifei)5e37cc0— 开发前需要先安装Carthage命令 (QiYifei)f1693fb— 1.68 (fancymax)cd083fd— fix: 临时处理DeviceID (fancymax)bccd127— improve: prevent system sleep when in auto query tickets (fancymax)d847dfc— 1.67 (fancymax)1466c21— 1.66 (fancymax)2aef916— fix: 临时处理 频繁登陆失败的问题。 (fancymax)
🔒Security observations
- High · Use of Unofficial/Third-party 12306 API —
Project-wide (AppDelegate.swift, network layer). This is an unofficial client for the Chinese 12306 railway booking system. Using unofficial APIs violates terms of service and may expose users to man-in-the-middle attacks, data interception, or account compromise. The application directly interfaces with 12306 endpoints which may change or implement blocking mechanisms. Fix: Obtain official API access from 12306 or use only officially documented interfaces. Implement certificate pinning for HTTPS connections to prevent MITM attacks. - High · Credential Storage Risk —
12306ForMac/Model/MainModel.swift, 12306ForMac/Preferences/*.swift. The application handles user credentials (usernames, passwords) for 12306 authentication. File structure shows Model files like 'MainModel.swift' and preference files that likely store sensitive authentication data. No evidence of proper encryption using macOS Keychain API in the provided file structure. Fix: Store all credentials in macOS Keychain instead of UserDefaults or plaintext files. Never cache plaintext passwords. Implement proper credential lifecycle management. - High · Outdated Dependency Framework —
12306ForMac/12306ForMac-Bridging-Header.h, Carthage dependencies. The README indicates the project uses Carthage with dependencies like Alamofire, PromiseKit, FMDB, and MASPreferences. The project appears to be written in Swift 3.2 (iOS/macOS 10.11+), which are extremely outdated. These older versions likely contain known security vulnerabilities. Fix: Update to Swift 5.x or later and modern versions of all dependencies. Run security audit: 'carthage outdated' and update all packages to latest versions. Review CVE databases for Alamofire, FMDB versions in use. - Medium · SQL Injection Risk via FMDB —
12306ForMac/Model/ (likely database access layer not fully visible). FMDB is a SQLite wrapper used in the project (referenced in thankyou section). Without seeing actual SQL query code, there's risk of SQL injection if user input is directly concatenated into queries rather than using parameterized statements. Fix: Ensure all SQL queries use parameterized statements with placeholders (?). Never concatenate user input directly into SQL queries. Audit all database access code for injection vulnerabilities. - Medium · Missing HTTPS Certificate Validation —
12306ForMac/12306ForMac-Bridging-Header.h, network layer (not fully visible). No visible evidence of certificate pinning or enhanced TLS validation in the codebase. Alamofire by default validates certificates but may not implement pinning for sensitive financial/booking transactions. Fix: Implement certificate pinning using TrustKit or Alamofire's ServerTrustPolicy. Pin the 12306 server certificate and intermediate CAs. Validate certificate chains explicitly. - Medium · Bridging Header Potential Security Gap —
12306ForMac/12306ForMac-Bridging-Header.h. The project uses an Objective-C bridging header (12306ForMac-Bridging-Header.h). Bridging headers can expose C/Objective-C code that may have memory safety issues or unvalidated input handling. Fix: Review the bridging header content for any unsafe C functions. Minimize bridging header scope. Prefer Swift-native implementations. Use -Weverything compiler flag to catch warnings. - Medium · No Visible Input Validation —
12306ForMac/Model/*.swift (parameter classes). The file structure doesn't show explicit input validation layers. Parameters like 'LeftTicketParam', 'SubmitOrderParams', 'QueryTrainPriceParam' lack visible validation before being sent to the 12306 API. Fix: Implement comprehensive input validation for all user inputs. Validate date formats, numeric ranges, string lengths. Use types (e.g., typed wrappers) to enforce constraints at compile time where possible. - Low · Xcode User Data Files in Repository —
undefined. Multiple xcuserdata directories and scheme files are tracked in the repository. These files may contain breakpoint locations, debug sessions, Fix: undefined
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.