@harshankur/viewcounter 3.0.1 → 3.2.0

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.
Files changed (64) hide show
  1. package/.env.example +50 -6
  2. package/README.md +444 -104
  3. package/admin/apple-touch-icon.png +0 -0
  4. package/admin/assets/world-map.json +1 -0
  5. package/admin/css/admin.css +2568 -0
  6. package/admin/favicon.ico +0 -0
  7. package/admin/favicon.svg +9 -0
  8. package/admin/icon-192.png +0 -0
  9. package/admin/icon-512.png +0 -0
  10. package/admin/index.html +95 -0
  11. package/admin/js/api.js +146 -0
  12. package/admin/js/appTabs.js +100 -0
  13. package/admin/js/charts.js +842 -0
  14. package/admin/js/clamp.js +41 -0
  15. package/admin/js/constants.js +239 -0
  16. package/admin/js/dataTable.js +478 -0
  17. package/admin/js/dom.js +83 -0
  18. package/admin/js/format.js +130 -0
  19. package/admin/js/i18n.js +80 -0
  20. package/admin/js/icons.js +168 -0
  21. package/admin/js/listbox.js +145 -0
  22. package/admin/js/logs.js +318 -0
  23. package/admin/js/main.js +399 -0
  24. package/admin/js/modal.js +171 -0
  25. package/admin/js/overview.js +905 -0
  26. package/admin/js/passwordPrompt.js +75 -0
  27. package/admin/js/table.js +94 -0
  28. package/admin/js/theme.js +72 -0
  29. package/admin/js/toast.js +47 -0
  30. package/admin/js/viewDialogs.js +224 -0
  31. package/admin/js/views.js +751 -0
  32. package/admin/locales/en.json +683 -0
  33. package/admin/site.webmanifest +20 -0
  34. package/config/index.js +122 -4
  35. package/constants.js +334 -3
  36. package/db/AdminRepository.js +488 -0
  37. package/db/DatabaseManager.js +148 -26
  38. package/db/LogRepository.js +354 -0
  39. package/db/adminSchema.js +329 -0
  40. package/db/adminSessionStore.js +104 -0
  41. package/db/analysis.js +479 -0
  42. package/db/rejectionCounter.js +117 -0
  43. package/db/retention.js +97 -0
  44. package/index.js +91 -24
  45. package/middleware/adminAuth.js +244 -0
  46. package/middleware/adminValidation.js +319 -0
  47. package/middleware/auth.js +2 -2
  48. package/middleware/security.js +26 -2
  49. package/middleware/validation.js +50 -2
  50. package/package.json +20 -10
  51. package/routes/admin.js +546 -0
  52. package/routes/analytics.js +207 -19
  53. package/tracker/tracker.js +191 -0
  54. package/utils/appIdUtils.js +1 -1
  55. package/utils/cookieUtils.js +47 -0
  56. package/utils/durationUtils.js +33 -0
  57. package/utils/errorUtils.js +39 -1
  58. package/utils/geoCity.js +87 -0
  59. package/utils/ipUtils.js +1 -1
  60. package/utils/privacyUtils.js +2 -2
  61. package/utils/referrerParser.js +23 -5
  62. package/utils/secretStore.js +1 -1
  63. package/utils/userAgentParser.js +52 -3
  64. package/utils/visitorContext.js +70 -0
package/.env.example CHANGED
@@ -1,7 +1,7 @@
1
1
  # ViewCounter configuration
2
2
  #
3
3
  # Copy to `.env` and fill in. Every value here can also come from dbInfo.json /
4
- # allowed.json, which take precedence — see config/index.js for the resolution
4
+ # allowed.json, which take precedence. See config/index.js for the resolution
5
5
  # order (config file > environment variable > built-in default).
6
6
  #
7
7
  # Anything marked Required is checked at startup in production: the server
@@ -37,7 +37,7 @@ CORS_ORIGINS=https://example.com,https://www.example.com
37
37
  # Credentials for the analytics READ endpoints (/stats, /views, /trends, ...),
38
38
  # comma-separated, sent by clients as the `x-api-key` header. Keys shorter than
39
39
  # 32 characters are ignored. List several so one consumer's key can be revoked
40
- # without rotating everyone else's. With none set, the read API returns 503 —
40
+ # without rotating everyone else's. With none set, the read API returns 503:
41
41
  # it fails closed rather than serving your analytics to anyone who asks.
42
42
  # Generate one with:
43
43
  # node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
@@ -50,6 +50,26 @@ READ_API_KEYS=
50
50
  # provisioning over HTTP entirely.
51
51
  ADMIN_API_KEYS=
52
52
 
53
+ # Password for the admin UI at /admin, where recorded views can be browsed,
54
+ # edited, annotated, trashed, and erased. At least 16 characters. It is its own
55
+ # credential tier: independent of READ_API_KEYS and ADMIN_API_KEYS, so leaking
56
+ # one never unlocks another (the server warns if you reuse an API key here).
57
+ # Leave unset and the admin UI does not exist at all. In production, a value
58
+ # shorter than 16 characters stops the server from starting.
59
+ # Generate one with: openssl rand -base64 24
60
+ #ADMIN_PASSWORD=
61
+
62
+ # How long an admin UI session lasts: it ends after this long without use, or
63
+ # this long after signing in, whichever comes first. Sessions are kept in the
64
+ # database (only a hash of the token), so they survive restarts, and using the
65
+ # UI, even just reading it, keeps one alive. A number with m, h, or d, such as
66
+ # 30m, 12h, or 7d. A malformed value, or an idle time longer than the maximum,
67
+ # stops the server from starting. Erasing views permanently asks for the
68
+ # password again unless it was entered in the last 15 minutes, however long
69
+ # the session. Defaults: 7d idle, 30d maximum.
70
+ #ADMIN_SESSION_IDLE_TIMEOUT=7d
71
+ #ADMIN_SESSION_MAX_AGE=30d
72
+
53
73
  # Number of reverse proxies in front of this service, or a comma-separated list
54
74
  # of trusted proxy CIDRs. Leave unset if nothing proxies it.
55
75
  #
@@ -63,8 +83,8 @@ ADMIN_API_KEYS=
63
83
  # Where the visitor-hash secret is persisted. Generated with a CSPRNG on first
64
84
  # run at mode 0600. This secret is the only reason a stored visitor hash cannot
65
85
  # be brute-forced back to the IP that produced it, so back it up with the same
66
- # care as the database password — and note that replacing it makes existing
67
- # hashes unlinkable from new ones (which is deliberate, not a bug).
86
+ # care as the database password. Replacing it makes existing hashes
87
+ # unlinkable from new ones (which is deliberate, not a bug).
68
88
  #VISITOR_SECRET_PATH=/var/lib/viewcounter/.visitor-secret
69
89
 
70
90
  # Supply the secret directly instead of persisting a file. Useful for
@@ -86,8 +106,8 @@ DB_PORT=3306
86
106
  PORT=3030
87
107
 
88
108
  # Defaults to `production`. Set to `development` for local work. This does not
89
- # change what is returned to callers — errors never include internal detail in
90
- # any environment — but it does relax the startup checks above.
109
+ # change what is returned to callers (errors never include internal detail in
110
+ # any environment), but it does relax the startup checks above.
91
111
  #NODE_ENV=production
92
112
 
93
113
  # Operational log verbosity: debug | info | warn | error | silent.
@@ -111,5 +131,29 @@ APP_RATE_LIMIT_MAX=1000
111
131
  # Set 0 to disable deduplication (the hash still rotates hourly).
112
132
  UNIQUE_VISITOR_WINDOW_HOURS=24
113
133
 
134
+ # Days a view stays in the admin UI's trash before it is erased for good
135
+ # (GDPR storage limitation). An admin can also erase from the trash at once.
136
+ # 0 keeps trash until someone empties it by hand. Default: 30.
137
+ TRASH_RETENTION_DAYS=30
138
+
139
+ # Days an entry stays in the tracking log (one row per accepted view, plus
140
+ # per-minute counts of bots and refused requests) before it is removed. The
141
+ # log holds no personal data; this only bounds its size, and never touches the
142
+ # views themselves. The admin operation log is never pruned. 0 keeps the
143
+ # tracking log forever. Default: 90. (The name predates the tracking log.)
144
+ VIEW_LOG_RETENTION_DAYS=90
145
+
146
+ # A city database, for the region and city of each view. Countries work
147
+ # without one (a GeoLite2 country database ships in the package). Point this
148
+ # at a MaxMind-format .mmdb file:
149
+ # - DB-IP IP to City Lite, free under CC BY 4.0, updated monthly:
150
+ # https://db-ip.com/db/download/ip-to-city-lite (the admin UI credits it
151
+ # as its licence asks)
152
+ # - or MaxMind GeoLite2 City, which needs a free MaxMind account
153
+ # The file is read again when it changes, so a monthly download that replaces
154
+ # it needs no restart. Unset: region and city stay empty. A path that cannot
155
+ # be opened stops the server from starting.
156
+ #GEOIP_CITY_DB=/var/lib/viewcounter/dbip-city-lite.mmdb
157
+
114
158
  # Device size buckets accepted on /registerView, comma-separated.
115
159
  #ALLOWED_DEVICE_SIZES=small,medium,large