|
1 | 1 | # JavaScript Rules |
2 | | - |
3 | | -httpjail uses the V8 JavaScript engine to evaluate requests efficiently and securely. |
4 | | - |
5 | | -## The Request Object |
6 | | - |
7 | | -Each request is exposed to your JavaScript code as the `r` object with the following properties: |
8 | | - |
9 | | -- `r.url` - Full URL (string) |
10 | | -- `r.method` - HTTP method (string, e.g., "GET", "POST") |
11 | | -- `r.host` - Hostname (string, e.g., "example.com") |
12 | | -- `r.scheme` - URL scheme (string, "http" or "https") |
13 | | -- `r.path` - URL path (string, e.g., "/api/users") |
14 | | - |
15 | | -## Rule Syntax |
16 | | - |
17 | | -### Inline Rules |
18 | | - |
19 | | -Simple expressions can be passed directly via `--js`: |
20 | | - |
21 | | -```bash |
22 | | -# Single condition |
23 | | -httpjail --js "r.host === 'github.com'" -- command |
24 | | - |
25 | | -# Multiple conditions |
26 | | -httpjail --js "r.host === 'api.example.com' && r.method === 'GET'" -- command |
27 | | - |
28 | | -# Using arrays |
29 | | -httpjail --js "['GET', 'POST'].includes(r.method)" -- command |
30 | | -``` |
31 | | - |
32 | | -### File-based Rules |
33 | | - |
34 | | -For complex logic, use a JavaScript file: |
35 | | - |
36 | | -```javascript |
37 | | -// rules.js |
38 | | -// Define your logic |
39 | | -const allowedHosts = ['github.com', 'api.github.com']; |
40 | | -const isProduction = process.env.NODE_ENV === 'production'; |
41 | | - |
42 | | -// The last expression is the result |
43 | | -allowedHosts.includes(r.host) && (!isProduction || r.method !== 'DELETE'); |
44 | | -``` |
45 | | - |
46 | | -```bash |
47 | | -httpjail --js-file rules.js -- command |
48 | | -``` |
49 | | - |
50 | | -## Common Patterns |
51 | | - |
52 | | -### Domain Allowlisting |
53 | | - |
54 | | -```javascript |
55 | | -// Allow specific domains |
56 | | -const allowed = ['example.com', 'api.example.com']; |
57 | | -allowed.includes(r.host) |
58 | | -``` |
59 | | - |
60 | | -### Subdomain Matching |
61 | | - |
62 | | -```javascript |
63 | | -// Allow all subdomains of example.com |
64 | | -r.host === 'example.com' || r.host.endsWith('.example.com') |
65 | | -``` |
66 | | - |
67 | | -### Path-based Rules |
68 | | - |
69 | | -```javascript |
70 | | -// Allow only specific API endpoints |
71 | | -r.host === 'api.example.com' && |
72 | | -r.path.startsWith('/v1/public/') |
73 | | -``` |
74 | | - |
75 | | -### Method Restrictions |
76 | | - |
77 | | -```javascript |
78 | | -// Read-only access |
79 | | -['GET', 'HEAD', 'OPTIONS'].includes(r.method) |
80 | | -``` |
81 | | - |
82 | | -### Regular Expressions |
83 | | - |
84 | | -```javascript |
85 | | -// Match patterns |
86 | | -/^api\d+\.example\.com$/.test(r.host) |
87 | | -``` |
88 | | - |
89 | | -## Advanced Examples |
90 | | - |
91 | | -### Environment-based Rules |
92 | | - |
93 | | -```javascript |
94 | | -// Different rules for different environments |
95 | | -const isDev = r.host === 'localhost' || r.host === '127.0.0.1'; |
96 | | -const isProd = r.host.endsWith('.production.example.com'); |
97 | | - |
98 | | -if (isDev) { |
99 | | - true; // Allow all in development |
100 | | -} else if (isProd) { |
101 | | - r.method === 'GET'; // Read-only in production |
102 | | -} else { |
103 | | - false; // Deny everything else |
104 | | -} |
105 | | -``` |
106 | | - |
107 | | -### Service-specific Rules |
108 | | - |
109 | | -```javascript |
110 | | -// Package manager rules |
111 | | -const npmHosts = ['registry.npmjs.org', 'registry.yarnpkg.com']; |
112 | | -const pypiHosts = ['pypi.org', 'files.pythonhosted.org']; |
113 | | -const cargoHosts = ['crates.io', 'static.crates.io']; |
114 | | - |
115 | | -const isPackageManager = |
116 | | - npmHosts.includes(r.host) || |
117 | | - pypiHosts.includes(r.host) || |
118 | | - cargoHosts.includes(r.host); |
119 | | - |
120 | | -isPackageManager |
121 | | -``` |
122 | | - |
123 | | -### API Rate Limiting Preparation |
124 | | - |
125 | | -```javascript |
126 | | -// Log specific endpoints for rate limiting analysis |
127 | | -if (r.host === 'api.example.com' && r.path.startsWith('/v1/')) { |
128 | | - console.log(`API call: ${r.method} ${r.path}`); |
129 | | - true; |
130 | | -} else { |
131 | | - false; |
132 | | -} |
133 | | -``` |
134 | | - |
135 | | -## Security Considerations |
136 | | - |
137 | | -- JavaScript evaluation is sandboxed using V8 isolates |
138 | | -- No access to file system, network, or other system resources |
139 | | -- Limited execution time to prevent infinite loops |
140 | | -- The `r` object is read-only |
141 | | - |
142 | | -## Performance |
143 | | - |
144 | | -JavaScript rules are compiled once and cached, making them very fast for repeated evaluations. For best performance: |
145 | | - |
146 | | -1. Keep expressions simple |
147 | | -2. Avoid complex regular expressions |
148 | | -3. Use early returns in conditional logic |
149 | | -4. Prefer simple property checks over method calls |
150 | | - |
151 | | -## Debugging |
152 | | - |
153 | | -Test your rules before deployment: |
154 | | - |
155 | | -```bash |
156 | | -# Test with verbose output |
157 | | -httpjail --js-file rules.js --request-log /dev/stdout -- curl https://example.com |
158 | | -``` |
159 | | - |
160 | | -Look for blocked requests in the log to understand what's being filtered. |
0 commit comments