location-tracker 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- location_tracker-1.0.0/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
- location_tracker-1.0.0/.github/ISSUE_TEMPLATE/feature_request.md +16 -0
- location_tracker-1.0.0/.github/PULL_REQUEST_TEMPLATE.md +17 -0
- location_tracker-1.0.0/.github/workflows/ci.yml +129 -0
- location_tracker-1.0.0/.github/workflows/publish.yml +34 -0
- location_tracker-1.0.0/.gitignore +20 -0
- location_tracker-1.0.0/.python-version +1 -0
- location_tracker-1.0.0/CONTRIBUTING.md +86 -0
- location_tracker-1.0.0/LICENSE +21 -0
- location_tracker-1.0.0/PKG-INFO +182 -0
- location_tracker-1.0.0/README.md +144 -0
- location_tracker-1.0.0/build.sh +32 -0
- location_tracker-1.0.0/cookie_store.py +100 -0
- location_tracker-1.0.0/dashboard.py +242 -0
- location_tracker-1.0.0/db.py +144 -0
- location_tracker-1.0.0/get_cookies.py +213 -0
- location_tracker-1.0.0/main.py +502 -0
- location_tracker-1.0.0/pyproject.toml +79 -0
- location_tracker-1.0.0/setup.sh +59 -0
- location_tracker-1.0.0/static/app.js +647 -0
- location_tracker-1.0.0/static/style.css +229 -0
- location_tracker-1.0.0/templates/index.html +111 -0
- location_tracker-1.0.0/tests/__init__.py +0 -0
- location_tracker-1.0.0/tests/test_dashboard.py +81 -0
- location_tracker-1.0.0/tests/test_db.py +117 -0
- location_tracker-1.0.0/tests/test_tracker.py +84 -0
- location_tracker-1.0.0/tracker.py +376 -0
- location_tracker-1.0.0/uv.lock +1385 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug Report
|
|
3
|
+
about: Something isn't working as expected
|
|
4
|
+
title: ''
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: ''
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**Describe the bug**
|
|
10
|
+
A clear description of what's wrong.
|
|
11
|
+
|
|
12
|
+
**To reproduce**
|
|
13
|
+
1. Run `location-tracker ...`
|
|
14
|
+
2. Open dashboard at ...
|
|
15
|
+
3. Click on ...
|
|
16
|
+
4. See error
|
|
17
|
+
|
|
18
|
+
**Expected behavior**
|
|
19
|
+
What should happen instead.
|
|
20
|
+
|
|
21
|
+
**Environment**
|
|
22
|
+
- OS: [e.g. macOS 15.1]
|
|
23
|
+
- Python: [e.g. 3.13]
|
|
24
|
+
- Browser: [e.g. Chrome 130]
|
|
25
|
+
|
|
26
|
+
**Logs**
|
|
27
|
+
```
|
|
28
|
+
Paste relevant output from .tracker.log here
|
|
29
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature Request
|
|
3
|
+
about: Suggest a new feature or improvement
|
|
4
|
+
title: ''
|
|
5
|
+
labels: enhancement
|
|
6
|
+
assignees: ''
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**Problem**
|
|
10
|
+
What are you trying to do that you can't do today?
|
|
11
|
+
|
|
12
|
+
**Proposed solution**
|
|
13
|
+
How would you like it to work?
|
|
14
|
+
|
|
15
|
+
**Alternatives considered**
|
|
16
|
+
Any other approaches you thought about.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
## What
|
|
2
|
+
|
|
3
|
+
Brief description of the change.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
What problem does this solve?
|
|
8
|
+
|
|
9
|
+
## How
|
|
10
|
+
|
|
11
|
+
Key implementation details (if non-obvious).
|
|
12
|
+
|
|
13
|
+
## Testing
|
|
14
|
+
|
|
15
|
+
- [ ] Imports clean: `uv run python -c "import main, tracker, dashboard, db"`
|
|
16
|
+
- [ ] Dashboard tested manually
|
|
17
|
+
- [ ] No personal data in committed files
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
lint:
|
|
14
|
+
name: Lint & Format
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: astral-sh/setup-uv@v6
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.13"
|
|
22
|
+
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: uv sync --extra dev
|
|
25
|
+
|
|
26
|
+
- name: Ruff check
|
|
27
|
+
run: uv run ruff check .
|
|
28
|
+
|
|
29
|
+
- name: Ruff format check
|
|
30
|
+
run: uv run ruff format --check .
|
|
31
|
+
|
|
32
|
+
typecheck:
|
|
33
|
+
name: Import & Syntax Check
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
strategy:
|
|
36
|
+
matrix:
|
|
37
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
- uses: astral-sh/setup-uv@v6
|
|
41
|
+
- uses: actions/setup-python@v5
|
|
42
|
+
with:
|
|
43
|
+
python-version: ${{ matrix.python-version }}
|
|
44
|
+
|
|
45
|
+
- name: Install dependencies
|
|
46
|
+
run: uv sync --extra dev
|
|
47
|
+
|
|
48
|
+
- name: Verify all modules import
|
|
49
|
+
run: uv run python -c "import main, tracker, dashboard, db, cookie_store, get_cookies; print('All imports OK')"
|
|
50
|
+
|
|
51
|
+
- name: Check for syntax errors
|
|
52
|
+
run: uv run python -m py_compile main.py && uv run python -m py_compile tracker.py && uv run python -m py_compile dashboard.py && uv run python -m py_compile db.py && uv run python -m py_compile cookie_store.py && uv run python -m py_compile get_cookies.py
|
|
53
|
+
|
|
54
|
+
test:
|
|
55
|
+
name: Tests
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
strategy:
|
|
58
|
+
matrix:
|
|
59
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v4
|
|
62
|
+
- uses: astral-sh/setup-uv@v6
|
|
63
|
+
- uses: actions/setup-python@v5
|
|
64
|
+
with:
|
|
65
|
+
python-version: ${{ matrix.python-version }}
|
|
66
|
+
|
|
67
|
+
- name: Install dependencies
|
|
68
|
+
run: uv sync --extra dev
|
|
69
|
+
|
|
70
|
+
- name: Run tests
|
|
71
|
+
run: uv run pytest tests/ -v --tb=short || echo "No tests found yet"
|
|
72
|
+
|
|
73
|
+
security:
|
|
74
|
+
name: Security Scan
|
|
75
|
+
runs-on: ubuntu-latest
|
|
76
|
+
steps:
|
|
77
|
+
- uses: actions/checkout@v4
|
|
78
|
+
- uses: astral-sh/setup-uv@v6
|
|
79
|
+
- uses: actions/setup-python@v5
|
|
80
|
+
with:
|
|
81
|
+
python-version: "3.13"
|
|
82
|
+
|
|
83
|
+
- name: Install dependencies
|
|
84
|
+
run: uv sync --extra dev
|
|
85
|
+
|
|
86
|
+
- name: Check for hardcoded secrets
|
|
87
|
+
run: |
|
|
88
|
+
echo "Scanning for potential secrets..."
|
|
89
|
+
FOUND=0
|
|
90
|
+
# Check for hardcoded emails (not in example/help text)
|
|
91
|
+
if grep -rn '@gmail.com' --include='*.py' | grep -v 'you@gmail.com' | grep -v 'test@test.com' | grep -v '#' | grep -v 'example'; then
|
|
92
|
+
echo "::warning::Possible hardcoded email found"
|
|
93
|
+
FOUND=1
|
|
94
|
+
fi
|
|
95
|
+
# Check for API keys or tokens
|
|
96
|
+
if grep -rniE '(api_key|api_secret|token|password)\s*=' --include='*.py' | grep -v '#' | grep -v 'def ' | grep -v 'request' | grep -v 'csrf'; then
|
|
97
|
+
echo "::warning::Possible hardcoded credential found"
|
|
98
|
+
FOUND=1
|
|
99
|
+
fi
|
|
100
|
+
# Verify sensitive files are gitignored
|
|
101
|
+
for f in cookies.txt cookies.enc location_history.json location_history.db .tracker.log browser_profile; do
|
|
102
|
+
if ! grep -q "$f" .gitignore; then
|
|
103
|
+
echo "::error::$f is NOT in .gitignore"
|
|
104
|
+
FOUND=1
|
|
105
|
+
fi
|
|
106
|
+
done
|
|
107
|
+
if [ "$FOUND" -eq 0 ]; then echo "No secrets found."; fi
|
|
108
|
+
|
|
109
|
+
- name: Dependency audit
|
|
110
|
+
run: uv run pip audit --desc || echo "pip-audit not available, skipping"
|
|
111
|
+
|
|
112
|
+
build:
|
|
113
|
+
name: Package Build
|
|
114
|
+
runs-on: ubuntu-latest
|
|
115
|
+
needs: [lint, typecheck]
|
|
116
|
+
steps:
|
|
117
|
+
- uses: actions/checkout@v4
|
|
118
|
+
- uses: astral-sh/setup-uv@v6
|
|
119
|
+
- uses: actions/setup-python@v5
|
|
120
|
+
with:
|
|
121
|
+
python-version: "3.13"
|
|
122
|
+
|
|
123
|
+
- name: Build wheel
|
|
124
|
+
run: uv build
|
|
125
|
+
|
|
126
|
+
- name: Verify wheel contents
|
|
127
|
+
run: |
|
|
128
|
+
ls -la dist/
|
|
129
|
+
uv run python -m zipfile -l dist/*.whl | head -30
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
publish:
|
|
12
|
+
name: Build & Publish
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
environment: pypi
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: astral-sh/setup-uv@v6
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.13"
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: uv sync --extra dev
|
|
24
|
+
|
|
25
|
+
- name: Run tests
|
|
26
|
+
run: uv run pytest tests/ -v --tb=short
|
|
27
|
+
|
|
28
|
+
- name: Build package
|
|
29
|
+
run: uv build
|
|
30
|
+
|
|
31
|
+
- name: Publish to PyPI
|
|
32
|
+
env:
|
|
33
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
34
|
+
run: uv publish
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv
|
|
11
|
+
|
|
12
|
+
# Sensitive data - NEVER commit
|
|
13
|
+
cookies.txt
|
|
14
|
+
cookies.enc
|
|
15
|
+
location_history.json
|
|
16
|
+
location_history.db
|
|
17
|
+
browser_profile/
|
|
18
|
+
.tracker.log*
|
|
19
|
+
.tracker.pid
|
|
20
|
+
todo.md
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Contributing to Location Tracker
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing! This project is open to contributions of all kinds: bug reports, feature requests, documentation improvements, and code changes.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Fork the repo and clone your fork
|
|
8
|
+
2. Run `./setup.sh` or manually: `uv sync && uv run location-tracker setup`
|
|
9
|
+
3. Configure: `uv run location-tracker config --email you@gmail.com`
|
|
10
|
+
4. Authenticate: `uv run location-tracker cookies`
|
|
11
|
+
5. Start developing: `uv run location-tracker on`
|
|
12
|
+
|
|
13
|
+
## Development Setup
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Install dependencies
|
|
17
|
+
uv sync
|
|
18
|
+
|
|
19
|
+
# Run the dashboard in foreground (for development)
|
|
20
|
+
uv run python main.py _serve
|
|
21
|
+
|
|
22
|
+
# Run import check
|
|
23
|
+
uv run python -c "import main, tracker, dashboard, db, cookie_store"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Project Structure
|
|
27
|
+
|
|
28
|
+
| File | Purpose |
|
|
29
|
+
|------|---------|
|
|
30
|
+
| `main.py` | CLI entry point, daemon management, setup commands |
|
|
31
|
+
| `tracker.py` | Location polling, statistics, static map generation |
|
|
32
|
+
| `dashboard.py` | Flask server, API endpoints |
|
|
33
|
+
| `db.py` | SQLite database layer |
|
|
34
|
+
| `cookie_store.py` | Encrypted cookie storage (Fernet + macOS Keychain) |
|
|
35
|
+
| `get_cookies.py` | Browser-based Google authentication |
|
|
36
|
+
| `templates/index.html` | Dashboard HTML |
|
|
37
|
+
| `static/style.css` | Dashboard styles |
|
|
38
|
+
| `static/app.js` | Dashboard JavaScript (Leaflet map, UI logic) |
|
|
39
|
+
|
|
40
|
+
## How to Contribute
|
|
41
|
+
|
|
42
|
+
### Bug Reports
|
|
43
|
+
|
|
44
|
+
Open an issue with:
|
|
45
|
+
- What you expected to happen
|
|
46
|
+
- What actually happened
|
|
47
|
+
- Steps to reproduce
|
|
48
|
+
- Your OS and Python version
|
|
49
|
+
|
|
50
|
+
### Feature Requests
|
|
51
|
+
|
|
52
|
+
Open an issue describing:
|
|
53
|
+
- The problem you're trying to solve
|
|
54
|
+
- Your proposed solution
|
|
55
|
+
- Any alternatives you considered
|
|
56
|
+
|
|
57
|
+
### Pull Requests
|
|
58
|
+
|
|
59
|
+
1. Create a branch from `main`
|
|
60
|
+
2. Make your changes
|
|
61
|
+
3. Verify imports: `uv run python -c "import main, tracker, dashboard, db"`
|
|
62
|
+
4. Test the dashboard manually: `uv run python main.py _serve`
|
|
63
|
+
5. Open a PR with a clear description of what changed and why
|
|
64
|
+
|
|
65
|
+
### Code Style
|
|
66
|
+
|
|
67
|
+
- Follow existing patterns in each file
|
|
68
|
+
- Use `log.info/warning/error` for logging, not `print()`
|
|
69
|
+
- Add input validation at system boundaries (API endpoints, CLI args)
|
|
70
|
+
- Use `datetime.now(timezone.utc)` for all timestamps
|
|
71
|
+
- Escape user-controlled data before rendering in HTML (`esc()` in app.js)
|
|
72
|
+
|
|
73
|
+
### Areas Where Help is Wanted
|
|
74
|
+
|
|
75
|
+
Check the [issues labeled `help wanted`](https://github.com/dcondrey/location-tracker/labels/help%20wanted) for specific tasks. Some general areas:
|
|
76
|
+
|
|
77
|
+
- **Cross-platform support** -- Linux (Secret Service for keychain), Windows
|
|
78
|
+
- **Test suite** -- Unit tests for db.py, tracker.py, cookie_store.py
|
|
79
|
+
- **Notifications** -- Push notifications when someone arrives/leaves a geofence
|
|
80
|
+
- **Data visualization** -- Speed graphs, time-at-location charts, weekly summaries
|
|
81
|
+
- **Multi-provider support** -- Apple Find My, Samsung SmartThings, Life360
|
|
82
|
+
- **Performance** -- WebSocket push updates instead of 30s polling on the frontend
|
|
83
|
+
|
|
84
|
+
## Code of Conduct
|
|
85
|
+
|
|
86
|
+
Be respectful. This is a personal project shared with the community. Treat others the way you'd want to be treated.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 David Condrey
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: location-tracker
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Self-hosted location tracking dashboard with encrypted cookies, SQLite storage, and adaptive polling
|
|
5
|
+
Project-URL: Homepage, https://github.com/dcondrey/location-tracker
|
|
6
|
+
Project-URL: Repository, https://github.com/dcondrey/location-tracker
|
|
7
|
+
Project-URL: Issues, https://github.com/dcondrey/location-tracker/issues
|
|
8
|
+
Author-email: David Condrey <davidcondrey@me.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: dashboard,geolocation,google-maps,location,self-hosted,tracking
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: MacOS
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: System :: Monitoring
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: cryptography>=44.0
|
|
24
|
+
Requires-Dist: flask>=3.1.0
|
|
25
|
+
Requires-Dist: folium>=0.20.0
|
|
26
|
+
Requires-Dist: locationsharinglib>=5.0.3
|
|
27
|
+
Requires-Dist: pandas>=3.0.3
|
|
28
|
+
Requires-Dist: playwright-stealth>=2.0.3
|
|
29
|
+
Requires-Dist: playwright>=1.60.0
|
|
30
|
+
Requires-Dist: schedule>=1.2.2
|
|
31
|
+
Provides-Extra: build
|
|
32
|
+
Requires-Dist: pyinstaller>=6.0; extra == 'build'
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pip-audit>=2.7; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: ruff>=0.11; extra == 'dev'
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# Location Tracker
|
|
40
|
+
|
|
41
|
+
A self-hosted location tracking dashboard that polls Google Maps location sharing and visualizes movement history on an interactive map. Runs as a background daemon with a real-time web interface.
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- **Real-time tracking** -- Polls Google Maps shared locations with adaptive intervals (15s when driving, 10min when stationary)
|
|
46
|
+
- **Interactive dashboard** -- Dark-themed Leaflet map with path visualization, heatmaps, stop detection, and timeline scrubbing
|
|
47
|
+
- **Self-tracking** -- Track your own position via browser geolocation
|
|
48
|
+
- **Encrypted cookie storage** -- Google auth tokens encrypted at rest with Fernet; key stored in macOS Keychain
|
|
49
|
+
- **Auto cookie refresh** -- Headless browser automatically re-authenticates when cookies expire
|
|
50
|
+
- **SQLite storage** -- Location history stored in an indexed SQLite database with WAL mode
|
|
51
|
+
- **Mobile responsive** -- Bottom-sheet sidebar on phones, touch-friendly controls
|
|
52
|
+
- **Multiple export formats** -- JSON, CSV, and GeoJSON
|
|
53
|
+
- **Persistent daemon** -- Optional launchd integration to survive reboots
|
|
54
|
+
- **CLI query tools** -- Look up anyone's latest location or history from the terminal
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Clone and set up
|
|
60
|
+
git clone https://github.com/dcondrey/location-tracker.git
|
|
61
|
+
cd location-tracker
|
|
62
|
+
./setup.sh
|
|
63
|
+
|
|
64
|
+
# Or manually:
|
|
65
|
+
uv sync
|
|
66
|
+
uv run location-tracker setup
|
|
67
|
+
|
|
68
|
+
# Configure your Google account
|
|
69
|
+
uv run location-tracker config --email you@gmail.com
|
|
70
|
+
|
|
71
|
+
# Authenticate with Google (opens browser)
|
|
72
|
+
uv run location-tracker cookies
|
|
73
|
+
|
|
74
|
+
# Start tracking
|
|
75
|
+
uv run location-tracker on
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The dashboard will be available at **http://tracker** (or `http://localhost:7070` if DNS isn't configured).
|
|
79
|
+
|
|
80
|
+
## Prerequisites
|
|
81
|
+
|
|
82
|
+
- **Python 3.11+**
|
|
83
|
+
- **macOS** (uses Keychain for cookie encryption, launchd for persistence)
|
|
84
|
+
- **uv** package manager ([install](https://docs.astral.sh/uv/getting-started/installation/))
|
|
85
|
+
- A Google account with [location sharing](https://support.google.com/maps/answer/7326816) enabled
|
|
86
|
+
|
|
87
|
+
## Commands
|
|
88
|
+
|
|
89
|
+
### Core
|
|
90
|
+
|
|
91
|
+
| Command | Description |
|
|
92
|
+
|---------|-------------|
|
|
93
|
+
| `on` | Start the tracker daemon and web dashboard |
|
|
94
|
+
| `off` | Stop the tracker |
|
|
95
|
+
| `status` | Check if the tracker is running |
|
|
96
|
+
| `cookies` | Open browser to authenticate with Google |
|
|
97
|
+
| `test` | Verify cookies are valid and list shared contacts |
|
|
98
|
+
|
|
99
|
+
### Configuration
|
|
100
|
+
|
|
101
|
+
| Command | Description |
|
|
102
|
+
|---------|-------------|
|
|
103
|
+
| `config --email you@gmail.com` | Set the Google account email |
|
|
104
|
+
| `config` | Show current configuration |
|
|
105
|
+
| `setup` | First-time setup: install Chromium, configure DNS and port forwarding |
|
|
106
|
+
| `dns` | Set up `http://tracker` hostname |
|
|
107
|
+
| `dns --remove` | Remove hostname and port forwarding |
|
|
108
|
+
| `install` | Install as a launchd service (auto-start on login) |
|
|
109
|
+
| `install --remove` | Remove the launchd service |
|
|
110
|
+
|
|
111
|
+
### Data
|
|
112
|
+
|
|
113
|
+
| Command | Description |
|
|
114
|
+
|---------|-------------|
|
|
115
|
+
| `where <person>` | Show someone's latest known location |
|
|
116
|
+
| `history <person> --days 7` | Show recent location history |
|
|
117
|
+
| `stats` | Print tracking statistics (distance, stops, dwell time) |
|
|
118
|
+
| `map --days 7 --output map.html` | Generate a static HTML map |
|
|
119
|
+
| `purge <days>` | Delete location records older than N days |
|
|
120
|
+
|
|
121
|
+
## Dashboard
|
|
122
|
+
|
|
123
|
+
The web dashboard provides:
|
|
124
|
+
|
|
125
|
+
- **Map views** -- Road, Satellite, Hybrid, Terrain, and Dark map layers via Google/CARTO tiles
|
|
126
|
+
- **Visualization modes** -- Path view (color-coded routes with stop nodes), Heatmap, and Points
|
|
127
|
+
- **Time filtering** -- 24h, 3 days, 7 days, 30 days, 90 days, or all time
|
|
128
|
+
- **Timeline scrubber** -- Drag to view historical positions with date/time labels
|
|
129
|
+
- **Person cards** -- Click to focus; shows speed badge (Stationary/Walking/Driving/Highway)
|
|
130
|
+
- **Self-tracking** -- Enable browser geolocation to appear on the map yourself
|
|
131
|
+
- **Export** -- Download data as JSON, CSV, or GeoJSON
|
|
132
|
+
- **Toast notifications** -- Visual feedback for all actions
|
|
133
|
+
|
|
134
|
+
## How It Works
|
|
135
|
+
|
|
136
|
+
### Polling
|
|
137
|
+
|
|
138
|
+
The tracker polls Google Maps location sharing via [`locationsharinglib`](https://github.com/costastf/locationsharinglib). Polling frequency adapts to detected movement speed:
|
|
139
|
+
|
|
140
|
+
| Speed | Category | Poll Interval |
|
|
141
|
+
|-------|----------|--------------|
|
|
142
|
+
| > 60 km/h | Highway | 15 seconds |
|
|
143
|
+
| 10-60 km/h | Driving | 30 seconds |
|
|
144
|
+
| 1-10 km/h | Walking | 60 seconds |
|
|
145
|
+
| < 1 km/h | Stationary | 10 minutes |
|
|
146
|
+
|
|
147
|
+
The person being tracked receives no notification. This is a passive read of data they have already chosen to share.
|
|
148
|
+
|
|
149
|
+
### Security
|
|
150
|
+
|
|
151
|
+
- **Cookie encryption** -- Google auth cookies are encrypted with `cryptography.Fernet` before writing to disk. The encryption key is stored in macOS Keychain, never on the filesystem.
|
|
152
|
+
- **Localhost only** -- The Flask server binds to `127.0.0.1`; not accessible from the network.
|
|
153
|
+
- **XSS protection** -- All user-controlled data is HTML-escaped before rendering.
|
|
154
|
+
- **Input validation** -- Lat/lon bounds checking, type coercion, and error handling on all API endpoints.
|
|
155
|
+
- **Atomic writes** -- SQLite with WAL mode for concurrent safety.
|
|
156
|
+
|
|
157
|
+
### Data Storage
|
|
158
|
+
|
|
159
|
+
Location history is stored in a local SQLite database (`location_history.db`) with indexed columns for fast queries. Existing `location_history.json` files are automatically migrated on first run.
|
|
160
|
+
|
|
161
|
+
## Project Structure
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
location-tracker/
|
|
165
|
+
main.py # CLI entry point and daemon management
|
|
166
|
+
tracker.py # Location polling, stats, and map generation
|
|
167
|
+
dashboard.py # Flask web server and API endpoints
|
|
168
|
+
db.py # SQLite database layer
|
|
169
|
+
cookie_store.py # Encrypted cookie storage (Fernet + Keychain)
|
|
170
|
+
get_cookies.py # Browser-based Google authentication
|
|
171
|
+
templates/
|
|
172
|
+
index.html # Dashboard HTML
|
|
173
|
+
static/
|
|
174
|
+
style.css # Dashboard styles
|
|
175
|
+
app.js # Dashboard JavaScript
|
|
176
|
+
setup.sh # One-command install script
|
|
177
|
+
build.sh # PyInstaller standalone build
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## License
|
|
181
|
+
|
|
182
|
+
MIT
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Location Tracker
|
|
2
|
+
|
|
3
|
+
A self-hosted location tracking dashboard that polls Google Maps location sharing and visualizes movement history on an interactive map. Runs as a background daemon with a real-time web interface.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Real-time tracking** -- Polls Google Maps shared locations with adaptive intervals (15s when driving, 10min when stationary)
|
|
8
|
+
- **Interactive dashboard** -- Dark-themed Leaflet map with path visualization, heatmaps, stop detection, and timeline scrubbing
|
|
9
|
+
- **Self-tracking** -- Track your own position via browser geolocation
|
|
10
|
+
- **Encrypted cookie storage** -- Google auth tokens encrypted at rest with Fernet; key stored in macOS Keychain
|
|
11
|
+
- **Auto cookie refresh** -- Headless browser automatically re-authenticates when cookies expire
|
|
12
|
+
- **SQLite storage** -- Location history stored in an indexed SQLite database with WAL mode
|
|
13
|
+
- **Mobile responsive** -- Bottom-sheet sidebar on phones, touch-friendly controls
|
|
14
|
+
- **Multiple export formats** -- JSON, CSV, and GeoJSON
|
|
15
|
+
- **Persistent daemon** -- Optional launchd integration to survive reboots
|
|
16
|
+
- **CLI query tools** -- Look up anyone's latest location or history from the terminal
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Clone and set up
|
|
22
|
+
git clone https://github.com/dcondrey/location-tracker.git
|
|
23
|
+
cd location-tracker
|
|
24
|
+
./setup.sh
|
|
25
|
+
|
|
26
|
+
# Or manually:
|
|
27
|
+
uv sync
|
|
28
|
+
uv run location-tracker setup
|
|
29
|
+
|
|
30
|
+
# Configure your Google account
|
|
31
|
+
uv run location-tracker config --email you@gmail.com
|
|
32
|
+
|
|
33
|
+
# Authenticate with Google (opens browser)
|
|
34
|
+
uv run location-tracker cookies
|
|
35
|
+
|
|
36
|
+
# Start tracking
|
|
37
|
+
uv run location-tracker on
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The dashboard will be available at **http://tracker** (or `http://localhost:7070` if DNS isn't configured).
|
|
41
|
+
|
|
42
|
+
## Prerequisites
|
|
43
|
+
|
|
44
|
+
- **Python 3.11+**
|
|
45
|
+
- **macOS** (uses Keychain for cookie encryption, launchd for persistence)
|
|
46
|
+
- **uv** package manager ([install](https://docs.astral.sh/uv/getting-started/installation/))
|
|
47
|
+
- A Google account with [location sharing](https://support.google.com/maps/answer/7326816) enabled
|
|
48
|
+
|
|
49
|
+
## Commands
|
|
50
|
+
|
|
51
|
+
### Core
|
|
52
|
+
|
|
53
|
+
| Command | Description |
|
|
54
|
+
|---------|-------------|
|
|
55
|
+
| `on` | Start the tracker daemon and web dashboard |
|
|
56
|
+
| `off` | Stop the tracker |
|
|
57
|
+
| `status` | Check if the tracker is running |
|
|
58
|
+
| `cookies` | Open browser to authenticate with Google |
|
|
59
|
+
| `test` | Verify cookies are valid and list shared contacts |
|
|
60
|
+
|
|
61
|
+
### Configuration
|
|
62
|
+
|
|
63
|
+
| Command | Description |
|
|
64
|
+
|---------|-------------|
|
|
65
|
+
| `config --email you@gmail.com` | Set the Google account email |
|
|
66
|
+
| `config` | Show current configuration |
|
|
67
|
+
| `setup` | First-time setup: install Chromium, configure DNS and port forwarding |
|
|
68
|
+
| `dns` | Set up `http://tracker` hostname |
|
|
69
|
+
| `dns --remove` | Remove hostname and port forwarding |
|
|
70
|
+
| `install` | Install as a launchd service (auto-start on login) |
|
|
71
|
+
| `install --remove` | Remove the launchd service |
|
|
72
|
+
|
|
73
|
+
### Data
|
|
74
|
+
|
|
75
|
+
| Command | Description |
|
|
76
|
+
|---------|-------------|
|
|
77
|
+
| `where <person>` | Show someone's latest known location |
|
|
78
|
+
| `history <person> --days 7` | Show recent location history |
|
|
79
|
+
| `stats` | Print tracking statistics (distance, stops, dwell time) |
|
|
80
|
+
| `map --days 7 --output map.html` | Generate a static HTML map |
|
|
81
|
+
| `purge <days>` | Delete location records older than N days |
|
|
82
|
+
|
|
83
|
+
## Dashboard
|
|
84
|
+
|
|
85
|
+
The web dashboard provides:
|
|
86
|
+
|
|
87
|
+
- **Map views** -- Road, Satellite, Hybrid, Terrain, and Dark map layers via Google/CARTO tiles
|
|
88
|
+
- **Visualization modes** -- Path view (color-coded routes with stop nodes), Heatmap, and Points
|
|
89
|
+
- **Time filtering** -- 24h, 3 days, 7 days, 30 days, 90 days, or all time
|
|
90
|
+
- **Timeline scrubber** -- Drag to view historical positions with date/time labels
|
|
91
|
+
- **Person cards** -- Click to focus; shows speed badge (Stationary/Walking/Driving/Highway)
|
|
92
|
+
- **Self-tracking** -- Enable browser geolocation to appear on the map yourself
|
|
93
|
+
- **Export** -- Download data as JSON, CSV, or GeoJSON
|
|
94
|
+
- **Toast notifications** -- Visual feedback for all actions
|
|
95
|
+
|
|
96
|
+
## How It Works
|
|
97
|
+
|
|
98
|
+
### Polling
|
|
99
|
+
|
|
100
|
+
The tracker polls Google Maps location sharing via [`locationsharinglib`](https://github.com/costastf/locationsharinglib). Polling frequency adapts to detected movement speed:
|
|
101
|
+
|
|
102
|
+
| Speed | Category | Poll Interval |
|
|
103
|
+
|-------|----------|--------------|
|
|
104
|
+
| > 60 km/h | Highway | 15 seconds |
|
|
105
|
+
| 10-60 km/h | Driving | 30 seconds |
|
|
106
|
+
| 1-10 km/h | Walking | 60 seconds |
|
|
107
|
+
| < 1 km/h | Stationary | 10 minutes |
|
|
108
|
+
|
|
109
|
+
The person being tracked receives no notification. This is a passive read of data they have already chosen to share.
|
|
110
|
+
|
|
111
|
+
### Security
|
|
112
|
+
|
|
113
|
+
- **Cookie encryption** -- Google auth cookies are encrypted with `cryptography.Fernet` before writing to disk. The encryption key is stored in macOS Keychain, never on the filesystem.
|
|
114
|
+
- **Localhost only** -- The Flask server binds to `127.0.0.1`; not accessible from the network.
|
|
115
|
+
- **XSS protection** -- All user-controlled data is HTML-escaped before rendering.
|
|
116
|
+
- **Input validation** -- Lat/lon bounds checking, type coercion, and error handling on all API endpoints.
|
|
117
|
+
- **Atomic writes** -- SQLite with WAL mode for concurrent safety.
|
|
118
|
+
|
|
119
|
+
### Data Storage
|
|
120
|
+
|
|
121
|
+
Location history is stored in a local SQLite database (`location_history.db`) with indexed columns for fast queries. Existing `location_history.json` files are automatically migrated on first run.
|
|
122
|
+
|
|
123
|
+
## Project Structure
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
location-tracker/
|
|
127
|
+
main.py # CLI entry point and daemon management
|
|
128
|
+
tracker.py # Location polling, stats, and map generation
|
|
129
|
+
dashboard.py # Flask web server and API endpoints
|
|
130
|
+
db.py # SQLite database layer
|
|
131
|
+
cookie_store.py # Encrypted cookie storage (Fernet + Keychain)
|
|
132
|
+
get_cookies.py # Browser-based Google authentication
|
|
133
|
+
templates/
|
|
134
|
+
index.html # Dashboard HTML
|
|
135
|
+
static/
|
|
136
|
+
style.css # Dashboard styles
|
|
137
|
+
app.js # Dashboard JavaScript
|
|
138
|
+
setup.sh # One-command install script
|
|
139
|
+
build.sh # PyInstaller standalone build
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|