@ricardodeazambuja/browser-mcp-server 1.3.0 → 1.4.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.
@@ -0,0 +1,203 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Security Tools Test Suite
5
+ * Tests security headers, CSP monitoring, and mixed content detection
6
+ */
7
+
8
+ const { spawn } = require('child_process');
9
+ const path = require('path');
10
+ const readline = require('readline');
11
+
12
+ const serverPath = path.join(__dirname, '..', 'src', 'index.js');
13
+ const proc = spawn('node', [serverPath], { stdio: ['pipe', 'pipe', 'pipe'] });
14
+
15
+ proc.stderr.on('data', (data) => {
16
+ // Suppress stderr for cleaner test output
17
+ });
18
+
19
+ proc.on('error', (err) => {
20
+ console.error('Server error:', err);
21
+ process.exit(1);
22
+ });
23
+
24
+ const rl = readline.createInterface({ input: proc.stdout, terminal: false });
25
+
26
+ let messageId = 1;
27
+ let testStep = 0;
28
+
29
+ function sendRequest(method, params) {
30
+ const request = { jsonrpc: '2.0', id: messageId++, method, params };
31
+ proc.stdin.write(JSON.stringify(request) + '\n');
32
+ }
33
+
34
+ console.log('šŸ”’ Security Tools Test Suite\n');
35
+
36
+ rl.on('line', (line) => {
37
+ try {
38
+ const response = JSON.parse(line);
39
+ if (response.method === 'notifications/resources/list_changed') return;
40
+ if (response.error) {
41
+ console.error('āŒ Error:', response.error.message);
42
+ process.exit(1);
43
+ }
44
+ if (response.result && response.id) {
45
+ handleResponse(response);
46
+ }
47
+ } catch (e) {
48
+ // Ignore non-JSON lines
49
+ }
50
+ });
51
+
52
+ function handleResponse(response) {
53
+ const currentTest = steps[testStep];
54
+ if (!currentTest) return;
55
+
56
+ console.log(`āž”ļø ${currentTest.name}`);
57
+
58
+ try {
59
+ currentTest.verify(response);
60
+ console.log(` āœ… Passed\n`);
61
+ } catch (err) {
62
+ console.error(` āŒ Failed: ${err.message}`);
63
+ process.exit(1);
64
+ }
65
+
66
+ testStep++;
67
+ if (testStep < steps.length) {
68
+ setTimeout(() => {
69
+ sendRequest(steps[testStep].method, steps[testStep].params());
70
+ }, 500);
71
+ } else {
72
+ console.log('šŸŽ‰ All security tests passed!');
73
+ proc.kill();
74
+ process.exit(0);
75
+ }
76
+ }
77
+
78
+ const steps = [
79
+ {
80
+ name: 'Initialize',
81
+ method: 'initialize',
82
+ params: () => ({
83
+ protocolVersion: '2024-11-05',
84
+ capabilities: {},
85
+ clientInfo: { name: 'security-test', version: '1.0.0' }
86
+ }),
87
+ verify: () => { }
88
+ },
89
+ {
90
+ name: 'Navigate to Security Test Page',
91
+ method: 'tools/call',
92
+ params: () => ({
93
+ name: 'browser_navigate',
94
+ arguments: { url: 'file://' + path.join(__dirname, 'fixtures', 'test-security.html') }
95
+ }),
96
+ verify: () => { }
97
+ },
98
+ {
99
+ name: 'Wait for Page Load',
100
+ method: 'tools/call',
101
+ params: () => ({
102
+ name: 'browser_wait',
103
+ arguments: { ms: 1000 }
104
+ }),
105
+ verify: () => { }
106
+ },
107
+ {
108
+ name: 'Get Security Headers',
109
+ method: 'tools/call',
110
+ params: () => ({
111
+ name: 'browser_sec_get_security_headers',
112
+ arguments: {}
113
+ }),
114
+ verify: (res) => {
115
+ const text = res.result.content[0].text;
116
+ if (res.result.isError) {
117
+ throw new Error('Get security headers failed: ' + text);
118
+ }
119
+ if (!text.includes('content-security-policy') && !text.includes('Security Headers')) {
120
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
121
+ }
122
+ }
123
+ },
124
+ {
125
+ name: 'Start CSP Monitoring',
126
+ method: 'tools/call',
127
+ params: () => ({
128
+ name: 'browser_sec_start_csp_monitoring',
129
+ arguments: {}
130
+ }),
131
+ verify: (res) => {
132
+ const text = res.result.content[0].text;
133
+ // Accept success, already active, or error
134
+ if (!text.includes('monitoring started') && !text.includes('already active') && !text.includes('Error')) {
135
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
136
+ }
137
+ }
138
+ },
139
+ {
140
+ name: 'Wait for CSP Events',
141
+ method: 'tools/call',
142
+ params: () => ({
143
+ name: 'browser_wait',
144
+ arguments: { ms: 1000 }
145
+ }),
146
+ verify: () => { }
147
+ },
148
+ {
149
+ name: 'Get CSP Violations',
150
+ method: 'tools/call',
151
+ params: () => ({
152
+ name: 'browser_sec_get_csp_violations',
153
+ arguments: {}
154
+ }),
155
+ verify: (res) => {
156
+ const text = res.result.content[0].text;
157
+ // May or may not have violations depending on browser behavior
158
+ if (!text.includes('violations') && !text.includes('No CSP') && !text.includes('not active') && !text.includes('Error')) {
159
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
160
+ }
161
+ }
162
+ },
163
+ {
164
+ name: 'Stop CSP Monitoring',
165
+ method: 'tools/call',
166
+ params: () => ({
167
+ name: 'browser_sec_stop_csp_monitoring',
168
+ arguments: {}
169
+ }),
170
+ verify: (res) => {
171
+ const text = res.result.content[0].text;
172
+ // Accept stopped, not active, or error
173
+ if (!text.includes('stopped') && !text.includes('not active') && !text.includes('Error')) {
174
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
175
+ }
176
+ }
177
+ },
178
+ {
179
+ name: 'Detect Mixed Content (HTTP page)',
180
+ method: 'tools/call',
181
+ params: () => ({
182
+ name: 'browser_sec_detect_mixed_content',
183
+ arguments: {}
184
+ }),
185
+ verify: (res) => {
186
+ const text = res.result.content[0].text;
187
+ // On file:// protocol, should indicate HTTPS-only
188
+ if (!text.includes('HTTPS') && !text.includes('No mixed content')) {
189
+ throw new Error('Invalid mixed content response');
190
+ }
191
+ }
192
+ }
193
+ ];
194
+
195
+ // Start tests
196
+ setTimeout(() => sendRequest(steps[0].method, steps[0].params()), 500);
197
+
198
+ // Timeout after 60 seconds
199
+ setTimeout(() => {
200
+ console.error('\nāŒ Test timeout');
201
+ proc.kill();
202
+ process.exit(1);
203
+ }, 60000);
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Storage Tools Test Suite
5
+ * Tests IndexedDB, Cache Storage, and Service Worker inspection
6
+ */
7
+
8
+ const { spawn } = require('child_process');
9
+ const path = require('path');
10
+ const readline = require('readline');
11
+
12
+ const serverPath = path.join(__dirname, '..', 'src', 'index.js');
13
+ const proc = spawn('node', [serverPath], { stdio: ['pipe', 'pipe', 'pipe'] });
14
+
15
+ proc.stderr.on('data', (data) => {
16
+ // Suppress stderr for cleaner test output
17
+ });
18
+
19
+ proc.on('error', (err) => {
20
+ console.error('Server error:', err);
21
+ process.exit(1);
22
+ });
23
+
24
+ const rl = readline.createInterface({ input: proc.stdout, terminal: false });
25
+
26
+ let messageId = 1;
27
+ let testStep = 0;
28
+
29
+ function sendRequest(method, params) {
30
+ const request = { jsonrpc: '2.0', id: messageId++, method, params };
31
+ proc.stdin.write(JSON.stringify(request) + '\n');
32
+ }
33
+
34
+ console.log('šŸ’¾ Storage Tools Test Suite\n');
35
+
36
+ rl.on('line', (line) => {
37
+ try {
38
+ const response = JSON.parse(line);
39
+ if (response.method === 'notifications/resources/list_changed') return;
40
+ if (response.error) {
41
+ console.error('āŒ Error:', response.error.message);
42
+ process.exit(1);
43
+ }
44
+ if (response.result && response.id) {
45
+ handleResponse(response);
46
+ }
47
+ } catch (e) {
48
+ // Ignore non-JSON lines
49
+ }
50
+ });
51
+
52
+ function handleResponse(response) {
53
+ const currentTest = steps[testStep];
54
+ if (!currentTest) return;
55
+
56
+ console.log(`āž”ļø ${currentTest.name}`);
57
+
58
+ try {
59
+ currentTest.verify(response);
60
+ console.log(` āœ… Passed\n`);
61
+ } catch (err) {
62
+ console.error(` āŒ Failed: ${err.message}`);
63
+ process.exit(1);
64
+ }
65
+
66
+ testStep++;
67
+ if (testStep < steps.length) {
68
+ setTimeout(() => {
69
+ sendRequest(steps[testStep].method, steps[testStep].params());
70
+ }, 500);
71
+ } else {
72
+ console.log('šŸŽ‰ All storage tests passed!');
73
+ proc.kill();
74
+ process.exit(0);
75
+ }
76
+ }
77
+
78
+ const steps = [
79
+ {
80
+ name: 'Initialize',
81
+ method: 'initialize',
82
+ params: () => ({
83
+ protocolVersion: '2024-11-05',
84
+ capabilities: {},
85
+ clientInfo: { name: 'storage-test', version: '1.0.0' }
86
+ }),
87
+ verify: () => { }
88
+ },
89
+ {
90
+ name: 'Navigate to Storage Test Page',
91
+ method: 'tools/call',
92
+ params: () => ({
93
+ name: 'browser_navigate',
94
+ arguments: { url: 'file://' + path.join(__dirname, 'fixtures', 'test-storage.html') }
95
+ }),
96
+ verify: () => { }
97
+ },
98
+ {
99
+ name: 'Wait for Storage Setup',
100
+ method: 'tools/call',
101
+ params: () => ({
102
+ name: 'browser_wait',
103
+ arguments: { ms: 2000 }
104
+ }),
105
+ verify: () => { }
106
+ },
107
+ {
108
+ name: 'List IndexedDB Databases',
109
+ method: 'tools/call',
110
+ params: () => ({
111
+ name: 'browser_storage_get_indexeddb',
112
+ arguments: {}
113
+ }),
114
+ verify: (res) => {
115
+ const text = res.result.content[0].text;
116
+ // Should list databases, indicate none found, or CDP error
117
+ if (!text.includes('databases') && !text.includes('No IndexedDB') && !text.includes('CDP Error') && !text.includes('Error')) {
118
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
119
+ }
120
+ }
121
+ },
122
+ {
123
+ name: 'Inspect IndexedDB Database',
124
+ method: 'tools/call',
125
+ params: () => ({
126
+ name: 'browser_storage_get_indexeddb',
127
+ arguments: { databaseName: 'testDB' }
128
+ }),
129
+ verify: (res) => {
130
+ const text = res.result.content[0].text;
131
+ // Should show database structure or error if not found
132
+ if (!text.includes('objectStores') && !text.includes('not found') && !text.includes('error') && !text.includes('Error') && !text.includes('CDP Error')) {
133
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
134
+ }
135
+ }
136
+ },
137
+ {
138
+ name: 'List Cache Storage',
139
+ method: 'tools/call',
140
+ params: () => ({
141
+ name: 'browser_storage_get_cache_storage',
142
+ arguments: {}
143
+ }),
144
+ verify: (res) => {
145
+ const text = res.result.content[0].text;
146
+ // Should list caches, indicate none found, or error
147
+ if (!text.includes('caches') && !text.includes('No Cache') && !text.includes('CDP Error') && !text.includes('Error')) {
148
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
149
+ }
150
+ }
151
+ },
152
+ {
153
+ name: 'Inspect Cache Entries',
154
+ method: 'tools/call',
155
+ params: () => ({
156
+ name: 'browser_storage_get_cache_storage',
157
+ arguments: { cacheName: 'test-cache-v1' }
158
+ }),
159
+ verify: (res) => {
160
+ const text = res.result.content[0].text;
161
+ // Should show cache entries, not found, or error
162
+ if (!text.includes('entries') && !text.includes('not found') && !text.includes('CDP Error') && !text.includes('Error')) {
163
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
164
+ }
165
+ }
166
+ },
167
+ {
168
+ name: 'Get Service Workers',
169
+ method: 'tools/call',
170
+ params: () => ({
171
+ name: 'browser_storage_get_service_workers',
172
+ arguments: {}
173
+ }),
174
+ verify: (res) => {
175
+ const text = res.result.content[0].text;
176
+ // Should list service workers, indicate none/not supported, or error
177
+ if (!text.includes('Service Worker') && !text.includes('supported') && !text.includes('No service') && !text.includes('Error') && !text.includes('CDP Error')) {
178
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
179
+ }
180
+ }
181
+ }
182
+ ];
183
+
184
+ // Start tests
185
+ setTimeout(() => sendRequest(steps[0].method, steps[0].params()), 500);
186
+
187
+ // Timeout after 60 seconds
188
+ setTimeout(() => {
189
+ console.error('\nāŒ Test timeout');
190
+ proc.kill();
191
+ process.exit(1);
192
+ }, 60000);