Skip to content

Commit f99e4db

Browse files
committed
feat: add local GeoIP firewall and free session manager
Remove premium gating from the admin/server flow, add regression tests for session lifecycle fixes, and wire a local MaxMind GeoLite2 provider for geofencing. Add admin UI controls and backend routes for storing MaxMind credentials and downloading/updating the local MMDB database from inside the plugin. Verification: npm test; npm run build; npm run verify; npm run verify:runtime; npm pack --dry-run --json.
1 parent 0709e2d commit f99e4db

52 files changed

Lines changed: 7528 additions & 5376 deletions

Some content is hidden

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

.gitignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ test-*.ts
1010
*.test.ts
1111
*.spec.js
1212
*.spec.ts
13+
!tests/
14+
!tests/*.test.js
15+
!tests/*.test.mjs
1316
TEST_*.md
1417
TEST_RESULTS.md
1518
RELEASE_CHECKLIST.md
@@ -63,4 +66,7 @@ tmp/
6366

6467
# Build artifacts
6568
*.map
66-
.cache/
69+
.cache/
70+
71+
# Local agent archive
72+
.archive/

.planning/HANDOFF.json

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
{
2+
"version": "1.0",
3+
"timestamp": "2026-06-20T22:04:41.326Z",
4+
"source": "auto-postool",
5+
"partial": false,
6+
"phase": null,
7+
"phase_name": null,
8+
"phase_dir": null,
9+
"plan": null,
10+
"task": null,
11+
"total_tasks": null,
12+
"status": "auto-checkpoint",
13+
"completed_tasks": [],
14+
"remaining_tasks": [],
15+
"blockers": [],
16+
"human_actions_pending": [],
17+
"decisions": [],
18+
"uncommitted_files": [
19+
{
20+
"status": "M",
21+
"path": "README.md"
22+
},
23+
{
24+
"status": "M",
25+
"path": "admin/src/components/LicenseGuard.jsx"
26+
},
27+
{
28+
"status": "M",
29+
"path": "admin/src/components/SessionDetailModal.jsx"
30+
},
31+
{
32+
"status": "D",
33+
"path": "admin/src/hooks/useLicense.js"
34+
},
35+
{
36+
"status": "M",
37+
"path": "admin/src/index.js"
38+
},
39+
{
40+
"status": "M",
41+
"path": "admin/src/pages/Analytics.jsx"
42+
},
43+
{
44+
"status": "M",
45+
"path": "admin/src/pages/HomePage.jsx"
46+
},
47+
{
48+
"status": "M",
49+
"path": "admin/src/pages/License.jsx"
50+
},
51+
{
52+
"status": "M",
53+
"path": "admin/src/pages/Settings.jsx"
54+
},
55+
{
56+
"status": "D",
57+
"path": "admin/src/pages/UpgradePage.jsx"
58+
},
59+
{
60+
"status": "M",
61+
"path": "admin/src/translations/de.json"
62+
},
63+
{
64+
"status": "M",
65+
"path": "admin/src/translations/en.json"
66+
},
67+
{
68+
"status": "M",
69+
"path": "admin/src/translations/es.json"
70+
},
71+
{
72+
"status": "M",
73+
"path": "admin/src/translations/fr.json"
74+
},
75+
{
76+
"status": "M",
77+
"path": "admin/src/translations/pt.json"
78+
},
79+
{
80+
"status": "M",
81+
"path": "package-lock.json"
82+
},
83+
{
84+
"status": "M",
85+
"path": "package.json"
86+
},
87+
{
88+
"status": "M",
89+
"path": "server/src/bootstrap.js"
90+
},
91+
{
92+
"status": "M",
93+
"path": "server/src/controllers/license.js"
94+
},
95+
{
96+
"status": "M",
97+
"path": "server/src/controllers/session.js"
98+
},
99+
{
100+
"status": "M",
101+
"path": "server/src/controllers/settings.js"
102+
},
103+
{
104+
"status": "M",
105+
"path": "server/src/destroy.js"
106+
},
107+
{
108+
"status": "M",
109+
"path": "server/src/routes/admin.js"
110+
},
111+
{
112+
"status": "M",
113+
"path": "server/src/services/license-guard.js"
114+
},
115+
{
116+
"status": "M",
117+
"path": "server/src/services/session.js"
118+
},
119+
{
120+
"status": "M",
121+
"path": "server/src/utils/settings-loader.js"
122+
},
123+
{
124+
"status": "M",
125+
"path": "strapi-admin.js"
126+
},
127+
{
128+
"status": "M",
129+
"path": "strapi-server.js"
130+
},
131+
{
132+
"status": "??",
133+
"path": ".planning/"
134+
},
135+
{
136+
"status": "??",
137+
"path": "scripts/build-server-bundle.mjs"
138+
},
139+
{
140+
"status": "??",
141+
"path": "scripts/verify-server-bundle.mjs"
142+
}
143+
],
144+
"next_action": null,
145+
"context_notes": "Recent commits:\n1402eef fix(build): use non-destructured require for @strapi/utils\n2100783 chore(release): 4.5.12 [skip ci]\n729e794 fix(build): declare @strapi/utils as peerDependency — preventive zod/v4 fix\nb165368 chore(release): 4.5.11 [skip ci]\n21779d8 fix(rbac): make plugin::magic-sessionmanager.access visible in role editor"
146+
}

README.md

Lines changed: 86 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
Track logins, monitor active users, and secure your app with one simple plugin. No complicated setup required.
66

7+
Free and open under the MIT license. All features are available without a paid license or activation key.
8+
79
[![NPM](https://img.shields.io/npm/v/strapi-plugin-magic-sessionmanager.svg)](https://www.npmjs.com/package/strapi-plugin-magic-sessionmanager)
810
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
911

@@ -45,8 +47,8 @@ Track logins, monitor active users, and secure your app with one simple plugin.
4547
- Full device information
4648
- Browser and operating system
4749
- Complete session history
48-
- IP geolocation (Premium)
49-
- Security risk score (Premium)
50+
- IP geolocation
51+
- Security risk score
5052

5153
---
5254

@@ -199,7 +201,7 @@ SESSION_ENCRYPTION_KEY=your-key-here
199201
- Last time they did something
200202
- What browser/device they use
201203
- Their IP address
202-
- Location (if Premium)
204+
- Location
203205

204206
### 4. Multiple Devices
205207

@@ -269,7 +271,7 @@ Add to `config/plugins.ts`:
269271

270272
---
271273

272-
## 🌍 Premium Features (Optional License)
274+
## 🌍 Security Features
273275

274276
### IP Geolocation
275277

@@ -279,6 +281,77 @@ Add to `config/plugins.ts`:
279281
- ISP Provider
280282
- Coordinates (for map)
281283

284+
### Local GeoIP Firewall (Recommended)
285+
286+
For login blocking, use a local MaxMind GeoLite2 Country database. This avoids
287+
remote API timeouts and rate limits in the login path.
288+
289+
1. Create a free MaxMind account and download `GeoLite2-Country.mmdb`:
290+
https://dev.maxmind.com/geoip/geolite2-free-geolocation-data/
291+
2. Store the file on your Strapi server, for example:
292+
`/var/lib/strapi/GeoLite2-Country.mmdb`
293+
3. Configure the plugin:
294+
295+
```bash
296+
MAGIC_SESSIONMANAGER_GEOIP_DATABASE=/var/lib/strapi/GeoLite2-Country.mmdb
297+
MAXMIND_ACCOUNT_ID=your-account-id
298+
MAXMIND_LICENSE_KEY=your-license-key
299+
```
300+
301+
You can also manage this from the Strapi admin UI. Open
302+
**Magic Session Manager -> Settings -> Geofencing**, choose `local-mmdb`,
303+
enter the MaxMind account ID and license key, then use **Download / Update DB**.
304+
The plugin stores the credentials in the Strapi plugin store and never returns
305+
the license key to the browser after saving it.
306+
307+
Download or update the database:
308+
309+
```bash
310+
npm run geoip:update
311+
```
312+
313+
When installed as a package in a Strapi project, run the packaged binary:
314+
315+
```bash
316+
npx strapi-magic-sessionmanager-geoip
317+
```
318+
319+
The updater checks MaxMind's `Last-Modified` header first and skips the download
320+
when the local metadata is current. Use `npm run geoip:update -- --force` in the
321+
plugin repo or `npx strapi-magic-sessionmanager-geoip --force` in an installed
322+
Strapi project to force a refresh. Schedule it weekly or twice weekly with
323+
cron/systemd. MaxMind requires GeoLite databases to stay up to date and
324+
currently limits GeoLite users to 30 database downloads per day.
325+
326+
```typescript
327+
// config/plugins.ts
328+
export default () => ({
329+
'magic-sessionmanager': {
330+
enabled: true,
331+
config: {
332+
geoIpProvider: 'local-mmdb',
333+
geoIpDatabasePath: process.env.MAGIC_SESSIONMANAGER_GEOIP_DATABASE,
334+
// "auto": fail closed for suspicious-session blocking, fail open for plain geofencing
335+
// "block": fail closed whenever GEOIP lookup is unavailable
336+
// "allow": fail open whenever GEOIP lookup is unavailable
337+
geoLookupFailureMode: 'block',
338+
enableGeofencing: true,
339+
allowedCountries: ['DE', 'AT', 'CH'],
340+
},
341+
},
342+
});
343+
```
344+
345+
Provider options:
346+
- `local-mmdb`: local MaxMind-compatible database only
347+
- `auto`: use local database when configured, otherwise use the legacy remote provider
348+
- `ipapi`: legacy remote provider
349+
- `disabled`: no GEOIP lookup
350+
351+
Country firewall rules use the local database. VPN/proxy/threat detection still
352+
requires a provider that supplies those risk signals; a free country database
353+
does not reliably identify VPNs or proxies.
354+
282355
### Threat Detection
283356

284357
**Automatically check if IP is:**
@@ -305,7 +378,7 @@ Add to `config/plugins.ts`:
305378

306379
---
307380

308-
## 📧 Email Alerts Setup (Premium)
381+
## 📧 Email Alerts Setup
309382

310383
The Session Manager uses **Strapi's Email Plugin** to send notifications. You need to configure an email provider first.
311384

@@ -713,11 +786,11 @@ When you install this plugin, you get:
713786
- ✅ Encryption (secure)
714787
- ✅ Multi-device support
715788

716-
**Premium features require a license (free to generate):**
717-
- 🔒 IP Geolocation
718-
- 🔒 Threat detection
719-
- 🔒 Auto-blocking
720-
- 🔒 Email/webhook alerts
789+
**All features are included for free:**
790+
- IP Geolocation
791+
- Threat detection
792+
- Auto-blocking
793+
- Email/webhook alerts
721794

722795
---
723796

@@ -757,32 +830,11 @@ A: Not yet, but it's planned for future versions!
757830

758831
**Copyright © 2025 Schero D.**
759832

760-
### Important License Restriction
761-
762-
This plugin is **free and open source**, BUT:
763-
764-
⚠️ **You CANNOT modify the license validation system**
765-
766-
This means:
767-
- ❌ Cannot remove `license-guard.js`
768-
- ❌ Cannot bypass license activation
769-
- ❌ Cannot disable license checks
770-
- ❌ Cannot modify license-related endpoints
771-
772-
**Why?** The license system ensures:
773-
- Quality and ongoing support
774-
- Spam prevention
775-
- Usage analytics for improvements
776-
- Fair use tracking
833+
### Optional license-key activation
777834

778-
**What you CAN do:**
779-
- ✅ Use freely (personal & commercial)
780-
- ✅ View and study source code
781-
- ✅ Report issues and contribute
782-
- ✅ Deploy in production without fees
783-
- ✅ Integrate in your projects
835+
The admin panel includes a License page where you can register an optional key. This is only used for install tracking and support context; it does not unlock or restrict any plugin feature.
784836

785-
See [LICENSE](./LICENSE) and [COPYRIGHT_NOTICE.txt](./COPYRIGHT_NOTICE.txt) for full terms.
837+
See [LICENSE](./LICENSE) for full terms.
786838

787839
---
788840

0 commit comments

Comments
 (0)