carom-link 1.0.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.
- package/README.md +221 -0
- package/bin/carom.js +2 -0
- package/package.json +46 -0
- package/public/app.js +519 -0
- package/public/index.html +233 -0
- package/public/style.css +756 -0
- package/src/cli/commands/add.js +106 -0
- package/src/cli/commands/config.js +95 -0
- package/src/cli/commands/install.js +50 -0
- package/src/cli/commands/list.js +62 -0
- package/src/cli/commands/logs.js +70 -0
- package/src/cli/commands/remove.js +36 -0
- package/src/cli/commands/rules.js +168 -0
- package/src/cli/commands/start.js +43 -0
- package/src/cli/commands/stats.js +86 -0
- package/src/cli/commands/status.js +89 -0
- package/src/cli/commands/uninstall.js +28 -0
- package/src/cli/formatters.js +132 -0
- package/src/cli/index.js +45 -0
- package/src/cloak/detector.js +243 -0
- package/src/cloak/ipLookup.js +146 -0
- package/src/cloak/patterns.js +160 -0
- package/src/cloak/safePage.js +146 -0
- package/src/cloak/tokens.js +67 -0
- package/src/config.js +152 -0
- package/src/constants.js +78 -0
- package/src/db.js +256 -0
- package/src/server/app.js +110 -0
- package/src/server/routes/api.js +268 -0
- package/src/server/routes/redirect.js +141 -0
- package/src/server/server.js +117 -0
- package/src/service/launchd.js +166 -0
- package/src/service/manager.js +79 -0
- package/src/service/systemd.js +147 -0
package/README.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# carom
|
|
2
|
+
|
|
3
|
+
Link redirect server with bot and automated traffic protection, plus CLI management.
|
|
4
|
+
|
|
5
|
+
Wrap destination URLs behind your own clean domain. When a link is clicked, real humans get a fast 301 redirect. Automated scanners — carrier pre-fetchers, security crawlers, bot scrapers — see a benign safe page instead.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Global install
|
|
11
|
+
npm install -g carom
|
|
12
|
+
|
|
13
|
+
# Or use npx
|
|
14
|
+
npx carom start
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Requires Node.js ≥ 18.
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Start the server
|
|
23
|
+
carom start --port 3000
|
|
24
|
+
|
|
25
|
+
# Create a link
|
|
26
|
+
carom add https://example.com/landing-page my-slug
|
|
27
|
+
# → http://localhost:3000/my-slug
|
|
28
|
+
|
|
29
|
+
# List your links
|
|
30
|
+
carom ls
|
|
31
|
+
|
|
32
|
+
# Check click analytics
|
|
33
|
+
carom stats my-slug
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## How Bot Protection Works
|
|
37
|
+
|
|
38
|
+
Every request to a short link is scored by the detection engine:
|
|
39
|
+
|
|
40
|
+
| Signal | Weight | What it detects |
|
|
41
|
+
|--------|--------|-----------------|
|
|
42
|
+
| `ua_pattern` | +30 | Known bot/crawler User-Agent substrings (80+ patterns) |
|
|
43
|
+
| `ua_missing` | +15 | No User-Agent header at all |
|
|
44
|
+
| `headers_suspicious` | +20 | Missing Accept-Language, unusual Accept header |
|
|
45
|
+
| `datacenter_ip` | +25 | IP belongs to a cloud provider (AWS, GCP, Azure, etc.) |
|
|
46
|
+
| `timing_fast` | +15 | Click arrives <3s after link creation |
|
|
47
|
+
| `velocity_high` | +15 | Same slug hit 5+ times in 10s window |
|
|
48
|
+
| Custom rules | configurable | Your own UA patterns, IP ranges, or ASNs |
|
|
49
|
+
|
|
50
|
+
**Score ≥ 40 (default)** → Bot → Serve safe page (HTTP 200)
|
|
51
|
+
**Score < 40** → Human → 301 redirect to destination
|
|
52
|
+
|
|
53
|
+
## CLI Reference
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
carom <command> [options]
|
|
57
|
+
|
|
58
|
+
Commands:
|
|
59
|
+
start Start the redirect server
|
|
60
|
+
add <url> [slug] Create a new short link
|
|
61
|
+
ls List all links with click stats
|
|
62
|
+
rm <id|slug> Deactivate a link
|
|
63
|
+
stats <id|slug> Show detailed click analytics
|
|
64
|
+
rules ls List detection rules
|
|
65
|
+
rules add <pattern> Add custom bot pattern
|
|
66
|
+
rules rm <id> Remove a custom rule
|
|
67
|
+
rules test <ua> Test a user-agent string
|
|
68
|
+
config ls Show current config
|
|
69
|
+
config set <key> <val> Set a config value
|
|
70
|
+
config reset Reset to defaults
|
|
71
|
+
install Install as system service (auto-start on boot)
|
|
72
|
+
uninstall Remove system service
|
|
73
|
+
status Show server status
|
|
74
|
+
logs Tail server logs
|
|
75
|
+
|
|
76
|
+
Global Options:
|
|
77
|
+
--data-dir <path> Data directory (default: ~/.carom)
|
|
78
|
+
--port <number> Server port (default: 3000)
|
|
79
|
+
--host <addr> Bind address (default: localhost)
|
|
80
|
+
--api-key <key> API key for the REST API
|
|
81
|
+
-v, --verbose Verbose logging
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Service Management (Survives Reboots)
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Install as a system service
|
|
88
|
+
carom install --port 3000 --api-key your-secret-key
|
|
89
|
+
# macOS: creates ~/Library/LaunchAgents/com.carom.plist
|
|
90
|
+
# Linux: creates /etc/systemd/system/carom.service
|
|
91
|
+
|
|
92
|
+
# Check status
|
|
93
|
+
carom status
|
|
94
|
+
|
|
95
|
+
# View logs
|
|
96
|
+
carom logs
|
|
97
|
+
|
|
98
|
+
# Remove service (keeps data)
|
|
99
|
+
carom uninstall
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## REST API
|
|
103
|
+
|
|
104
|
+
All API endpoints require the `x-api-key` header (if an API key is configured).
|
|
105
|
+
|
|
106
|
+
### Links
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Create a link
|
|
110
|
+
curl -X POST http://localhost:3000/api/links \
|
|
111
|
+
-H "Content-Type: application/json" \
|
|
112
|
+
-H "x-api-key: your-key" \
|
|
113
|
+
-d '{"url": "https://example.com", "slug": "my-link"}'
|
|
114
|
+
|
|
115
|
+
# List links
|
|
116
|
+
curl http://localhost:3000/api/links -H "x-api-key: your-key"
|
|
117
|
+
|
|
118
|
+
# Get link stats
|
|
119
|
+
curl http://localhost:3000/api/links/1/stats -H "x-api-key: your-key"
|
|
120
|
+
|
|
121
|
+
# Delete link
|
|
122
|
+
curl -X DELETE http://localhost:3000/api/links/1 -H "x-api-key: your-key"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Detection Rules
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# List rules
|
|
129
|
+
curl http://localhost:3000/api/rules -H "x-api-key: your-key"
|
|
130
|
+
|
|
131
|
+
# Add a custom rule
|
|
132
|
+
curl -X POST http://localhost:3000/api/rules \
|
|
133
|
+
-H "Content-Type: application/json" \
|
|
134
|
+
-H "x-api-key: your-key" \
|
|
135
|
+
-d '{"type": "ua_pattern", "pattern": "CarrierIQ", "weight": 30}'
|
|
136
|
+
|
|
137
|
+
# Test a user-agent
|
|
138
|
+
curl -X POST http://localhost:3000/api/rules/test \
|
|
139
|
+
-H "Content-Type: application/json" \
|
|
140
|
+
-H "x-api-key: your-key" \
|
|
141
|
+
-d '{"userAgent": "curl/8.0"}'
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Admin Dashboard
|
|
145
|
+
|
|
146
|
+
Access the web dashboard at `http://localhost:3000/dashboard` when the server is running.
|
|
147
|
+
|
|
148
|
+
Features:
|
|
149
|
+
- Create and manage short links
|
|
150
|
+
- View click analytics with human/bot breakdown
|
|
151
|
+
- Add and manage detection rules
|
|
152
|
+
- Test user-agent strings against the detection engine
|
|
153
|
+
|
|
154
|
+
## Configuration
|
|
155
|
+
|
|
156
|
+
Config is stored in `~/.carom/config.json`. Set values via CLI or env vars:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Via CLI
|
|
160
|
+
carom config set shield.threshold 50
|
|
161
|
+
carom config set shield.mode interstitial
|
|
162
|
+
carom config set baseUrl https://yourdomain.com
|
|
163
|
+
|
|
164
|
+
# Via environment variables
|
|
165
|
+
SHIELD_ENABLED=true
|
|
166
|
+
SHIELD_THRESHOLD=40
|
|
167
|
+
SHIELD_MODE=direct
|
|
168
|
+
BASE_URL=https://yourdomain.com
|
|
169
|
+
API_KEY=your-secret
|
|
170
|
+
PORT=3000
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Configuration Keys
|
|
174
|
+
|
|
175
|
+
| Key | Default | Description |
|
|
176
|
+
|-----|---------|-------------|
|
|
177
|
+
| `port` | 3000 | Server port |
|
|
178
|
+
| `host` | localhost | Bind address |
|
|
179
|
+
| `baseUrl` | (empty) | Public URL for generated short links |
|
|
180
|
+
| `apiKey` | (empty) | API key (empty = open access) |
|
|
181
|
+
| `shield.enabled` | true | Enable/disable bot protection |
|
|
182
|
+
| `shield.threshold` | 40 | Bot score threshold (0-100) |
|
|
183
|
+
| `shield.mode` | direct | `direct` or `interstitial` |
|
|
184
|
+
| `shield.safePage.title` | Welcome | Safe page title |
|
|
185
|
+
| `shield.safePage.description` | Visit our website... | Safe page description |
|
|
186
|
+
| `shield.safePage.brand` | YourBrand | Safe page brand name |
|
|
187
|
+
|
|
188
|
+
## Programmatic Usage
|
|
189
|
+
|
|
190
|
+
```js
|
|
191
|
+
import { startServer } from 'carom';
|
|
192
|
+
|
|
193
|
+
const { app, server, db } = await startServer({
|
|
194
|
+
port: 3000,
|
|
195
|
+
host: 'localhost',
|
|
196
|
+
apiKey: 'my-key',
|
|
197
|
+
shield: {
|
|
198
|
+
enabled: true,
|
|
199
|
+
threshold: 40,
|
|
200
|
+
mode: 'direct',
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Data Storage
|
|
206
|
+
|
|
207
|
+
All data is stored in `~/.carom/` (configurable via `--data-dir`):
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
~/.carom/
|
|
211
|
+
├── data.db # SQLite database (links, clicks, rules)
|
|
212
|
+
├── config.json # Configuration
|
|
213
|
+
├── carom.pid # PID file (when running)
|
|
214
|
+
└── logs/
|
|
215
|
+
├── stdout.log # Server output
|
|
216
|
+
└── stderr.log # Error output
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## License
|
|
220
|
+
|
|
221
|
+
MIT
|
package/bin/carom.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "carom-link",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Link redirect server with bot and automated traffic protection, plus CLI management",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"carom": "./bin/carom.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "src/server/server.js",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./src/server/server.js",
|
|
12
|
+
"./shield": "./src/cloak/detector.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"bin/",
|
|
16
|
+
"src/",
|
|
17
|
+
"public/"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"start": "node bin/carom.js start",
|
|
21
|
+
"dev": "node --watch bin/carom.js start --verbose"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18.0.0"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"carom",
|
|
28
|
+
"link",
|
|
29
|
+
"redirect",
|
|
30
|
+
"bot-detection",
|
|
31
|
+
"carrier",
|
|
32
|
+
"shortener"
|
|
33
|
+
],
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"better-sqlite3": "^11.0.0",
|
|
37
|
+
"chalk": "^5.3.0",
|
|
38
|
+
"commander": "^12.0.0",
|
|
39
|
+
"cors": "^2.8.5",
|
|
40
|
+
"dotenv": "^16.4.0",
|
|
41
|
+
"express": "^4.21.0",
|
|
42
|
+
"express-rate-limit": "^7.4.0",
|
|
43
|
+
"helmet": "^8.0.0",
|
|
44
|
+
"nanoid": "^5.0.0"
|
|
45
|
+
}
|
|
46
|
+
}
|