securegate-cli-tool 2.1.3 → 2.1.5

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/index.js CHANGED
@@ -1,351 +1,351 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * SecureGate CLI - Setup and manage security keys
5
- * Run: npx securegate setup
6
- */
7
-
8
- const https = require('https');
9
- const http = require('http');
10
- const crypto = require('crypto');
11
- const os = require('os');
12
- const fs = require('fs');
13
- const path = require('path');
14
- const readline = require('readline');
15
-
16
- // Configuration
17
- const SUPABASE_URL = 'https://pbrmsfoowrjqsikgkijb.supabase.co';
18
- const CONFIG_DIR = path.join(os.homedir(), '.securegate');
19
- const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
20
-
21
- // ANSI colors
22
- const colors = {
23
- reset: '\x1b[0m',
24
- green: '\x1b[32m',
25
- yellow: '\x1b[33m',
26
- cyan: '\x1b[36m',
27
- red: '\x1b[31m',
28
- bold: '\x1b[1m',
29
- dim: '\x1b[2m',
30
- };
31
-
32
- function log(msg, color = '') {
33
- console.log(`${color}${msg}${colors.reset}`);
34
- }
35
-
36
- function banner() {
37
- console.log(`
38
- ${colors.cyan}${colors.bold}🔐 SecureGate Setup${colors.reset}
39
- ${colors.dim}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
40
- `);
41
- }
42
-
43
- // Get device fingerprint (machine-based)
44
- function getDeviceFingerprint() {
45
- const cpus = os.cpus();
46
- const networkInterfaces = os.networkInterfaces();
47
-
48
- // Get first MAC address
49
- let mac = '';
50
- for (const [name, interfaces] of Object.entries(networkInterfaces)) {
51
- for (const iface of interfaces) {
52
- if (iface.mac && iface.mac !== '00:00:00:00:00:00') {
53
- mac = iface.mac;
54
- break;
55
- }
56
- }
57
- if (mac) break;
58
- }
59
-
60
- const fingerprint = [
61
- os.hostname(),
62
- os.platform(),
63
- os.arch(),
64
- cpus[0]?.model || 'unknown',
65
- mac,
66
- os.totalmem().toString(),
67
- ].join('|');
68
-
69
- return crypto.createHash('sha256').update(fingerprint).digest('hex').substring(0, 32);
70
- }
71
-
72
- // Get public IP
73
- async function getPublicIP() {
74
- return new Promise((resolve) => {
75
- https.get('https://api.ipify.org?format=json', (res) => {
76
- let data = '';
77
- res.on('data', chunk => data += chunk);
78
- res.on('end', () => {
79
- try {
80
- resolve(JSON.parse(data).ip);
81
- } catch {
82
- resolve('unknown');
83
- }
84
- });
85
- }).on('error', () => resolve('unknown'));
86
- });
87
- }
88
-
89
- // Get geolocation
90
- async function getGeoLocation(ip) {
91
- return new Promise((resolve) => {
92
- http.get(`http://ip-api.com/json/${ip}?fields=status,country,countryCode,city`, (res) => {
93
- let data = '';
94
- res.on('data', chunk => data += chunk);
95
- res.on('end', () => {
96
- try {
97
- const result = JSON.parse(data);
98
- if (result.status === 'success') {
99
- resolve({ country: result.country, code: result.countryCode, city: result.city });
100
- } else {
101
- resolve(null);
102
- }
103
- } catch {
104
- resolve(null);
105
- }
106
- });
107
- }).on('error', () => resolve(null));
108
- });
109
- }
110
-
111
- // Make HTTP request
112
- function httpRequest(url, options = {}) {
113
- return new Promise((resolve, reject) => {
114
- const urlObj = new URL(url);
115
- const isHttps = urlObj.protocol === 'https:';
116
- const lib = isHttps ? https : http;
117
-
118
- const req = lib.request(url, {
119
- method: options.method || 'GET',
120
- headers: options.headers || {},
121
- }, (res) => {
122
- let data = '';
123
- res.on('data', chunk => data += chunk);
124
- res.on('end', () => {
125
- try {
126
- resolve({ status: res.statusCode, data: JSON.parse(data) });
127
- } catch {
128
- resolve({ status: res.statusCode, data });
129
- }
130
- });
131
- });
132
-
133
- req.on('error', reject);
134
-
135
- if (options.body) {
136
- req.write(options.body);
137
- }
138
- req.end();
139
- });
140
- }
141
-
142
- // Create readline interface
143
- function createPrompt() {
144
- return readline.createInterface({
145
- input: process.stdin,
146
- output: process.stdout,
147
- });
148
- }
149
-
150
- // Ask question
151
- function ask(rl, question) {
152
- return new Promise((resolve) => {
153
- rl.question(question, (answer) => {
154
- resolve(answer.trim());
155
- });
156
- });
157
- }
158
-
159
- // Load config
160
- function loadConfig() {
161
- try {
162
- if (fs.existsSync(CONFIG_FILE)) {
163
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
164
- }
165
- } catch { }
166
- return {};
167
- }
168
-
169
- // Save config
170
- function saveConfig(config) {
171
- if (!fs.existsSync(CONFIG_DIR)) {
172
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
173
- }
174
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
175
- }
176
-
177
- // Main setup flow
178
- async function setup() {
179
- banner();
180
-
181
- const rl = createPrompt();
182
-
183
- try {
184
- // Step 1: Get JWT token
185
- log('1. Authentication', colors.bold);
186
- log(' Enter your Supabase JWT token (from browser after login):', colors.dim);
187
- const token = await ask(rl, ' Token: ');
188
-
189
- if (!token) {
190
- log(' ❌ Token required', colors.red);
191
- process.exit(1);
192
- }
193
- log(' ✓ Token received', colors.green);
194
-
195
- // Step 2: Get connection ID
196
- log('\n2. Connection', colors.bold);
197
- log(' Enter your connection_id (e.g., open_abc123):', colors.dim);
198
- const connectionId = await ask(rl, ' Connection ID: ');
199
-
200
- if (!connectionId) {
201
- log(' ❌ Connection ID required', colors.red);
202
- process.exit(1);
203
- }
204
- log(` ✓ Connection: ${connectionId}`, colors.green);
205
-
206
- // Step 3: Detect environment
207
- log('\n3. Detecting environment...', colors.bold);
208
-
209
- const ip = await getPublicIP();
210
- log(` ✓ IP: ${ip}`, colors.green);
211
-
212
- const geo = await getGeoLocation(ip);
213
- if (geo) {
214
- log(` ✓ Location: ${geo.city}, ${geo.country} (${geo.code})`, colors.green);
215
- } else {
216
- log(' ⚠ Could not detect location', colors.yellow);
217
- }
218
-
219
- const fingerprint = getDeviceFingerprint();
220
- log(` ✓ Device: ${os.hostname()} (${os.platform()})`, colors.green);
221
- log(` ✓ Fingerprint: ${fingerprint.substring(0, 8)}...`, colors.dim);
222
-
223
- // Step 4: Activate key
224
- log('\n4. Generating security key...', colors.bold);
225
-
226
- const response = await httpRequest(`${SUPABASE_URL}/functions/v1/activate-key`, {
227
- method: 'POST',
228
- headers: {
229
- 'Authorization': `Bearer ${token}`,
230
- 'Content-Type': 'application/json',
231
- },
232
- body: JSON.stringify({
233
- connection_id: connectionId,
234
- device_fingerprint: fingerprint,
235
- label: `${os.hostname()} (${os.platform()})`,
236
- }),
237
- });
238
-
239
- if (response.status !== 201) {
240
- log(` ❌ Failed: ${response.data.error || 'Unknown error'}`, colors.red);
241
- process.exit(1);
242
- }
243
-
244
- const { security_key, bound_to, provider, usage } = response.data;
245
-
246
- log(' ✓ Key activated!', colors.green);
247
-
248
- // Save to config
249
- const config = loadConfig();
250
- config[connectionId] = {
251
- security_key,
252
- provider,
253
- bound_to,
254
- created_at: new Date().toISOString(),
255
- };
256
- saveConfig(config);
257
-
258
- // Display result
259
- console.log(`
260
- ${colors.dim}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
261
-
262
- ${colors.bold}${colors.green}✓ Security Key Generated!${colors.reset}
263
-
264
- ${colors.yellow}⚠ SAVE THIS KEY - IT WILL NOT BE SHOWN AGAIN!${colors.reset}
265
-
266
- ${colors.cyan}Security Key:${colors.reset}
267
- ${colors.bold}${security_key}${colors.reset}
268
-
269
- ${colors.cyan}Bound to:${colors.reset}
270
- • IP: ${bound_to.ip}
271
- • Country: ${bound_to.country}
272
- • Device: ${bound_to.device}
273
-
274
- ${colors.cyan}Usage:${colors.reset}
275
- ${colors.dim}const openai = new OpenAI({
276
- apiKey: '${security_key}',
277
- baseURL: '${usage.baseURL}'
278
- });${colors.reset}
279
-
280
- ${colors.dim}Config saved to: ${CONFIG_FILE}${colors.reset}
281
-
282
- ${colors.dim}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
283
- `);
284
-
285
- } finally {
286
- rl.close();
287
- }
288
- }
289
-
290
- // List configured keys
291
- async function list() {
292
- banner();
293
-
294
- const config = loadConfig();
295
- const keys = Object.entries(config);
296
-
297
- if (keys.length === 0) {
298
- log('No security keys configured yet.', colors.dim);
299
- log('Run: npx securegate setup', colors.cyan);
300
- return;
301
- }
302
-
303
- log('Configured Security Keys:', colors.bold);
304
- console.log();
305
-
306
- for (const [connectionId, data] of keys) {
307
- const keyPreview = data.security_key.substring(0, 12) + '...';
308
- log(` ${connectionId}`, colors.cyan);
309
- log(` Key: ${keyPreview}`, colors.dim);
310
- log(` Provider: ${data.provider}`, colors.dim);
311
- log(` IP: ${data.bound_to?.ip || 'unknown'}`, colors.dim);
312
- log(` Created: ${data.created_at}`, colors.dim);
313
- console.log();
314
- }
315
- }
316
-
317
- // Show usage instructions
318
- function usage() {
319
- console.log(`
320
- ${colors.cyan}${colors.bold}SecureGate CLI${colors.reset}
321
-
322
- ${colors.bold}Usage:${colors.reset}
323
- npx securegate setup Generate a new security key
324
- npx securegate list List configured keys
325
- npx securegate help Show this help
326
-
327
- ${colors.bold}Example:${colors.reset}
328
- 1. First, create a connection in the SecureGate dashboard
329
- 2. Run: npx securegate setup
330
- 3. Enter your JWT token and connection ID
331
- 4. Use the generated key with OpenAI SDK
332
- `);
333
- }
334
-
335
- // Main
336
- const command = process.argv[2] || 'help';
337
-
338
- switch (command) {
339
- case 'setup':
340
- setup().catch(err => {
341
- log(`Error: ${err.message}`, colors.red);
342
- process.exit(1);
343
- });
344
- break;
345
- case 'list':
346
- list();
347
- break;
348
- case 'help':
349
- default:
350
- usage();
351
- }
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SecureGate CLI - Setup and manage security keys
5
+ * Run: npx securegate setup
6
+ */
7
+
8
+ const https = require('https');
9
+ const http = require('http');
10
+ const crypto = require('crypto');
11
+ const os = require('os');
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const readline = require('readline');
15
+
16
+ // Configuration
17
+ const SUPABASE_URL = 'https://pbrmsfoowrjqsikgkijb.supabase.co';
18
+ const CONFIG_DIR = path.join(os.homedir(), '.securegate');
19
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
20
+
21
+ // ANSI colors
22
+ const colors = {
23
+ reset: '\x1b[0m',
24
+ green: '\x1b[32m',
25
+ yellow: '\x1b[33m',
26
+ cyan: '\x1b[36m',
27
+ red: '\x1b[31m',
28
+ bold: '\x1b[1m',
29
+ dim: '\x1b[2m',
30
+ };
31
+
32
+ function log(msg, color = '') {
33
+ console.log(`${color}${msg}${colors.reset}`);
34
+ }
35
+
36
+ function banner() {
37
+ console.log(`
38
+ ${colors.cyan}${colors.bold}🔐 SecureGate Setup${colors.reset}
39
+ ${colors.dim}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
40
+ `);
41
+ }
42
+
43
+ // Get device fingerprint (machine-based)
44
+ function getDeviceFingerprint() {
45
+ const cpus = os.cpus();
46
+ const networkInterfaces = os.networkInterfaces();
47
+
48
+ // Get first MAC address
49
+ let mac = '';
50
+ for (const [name, interfaces] of Object.entries(networkInterfaces)) {
51
+ for (const iface of interfaces) {
52
+ if (iface.mac && iface.mac !== '00:00:00:00:00:00') {
53
+ mac = iface.mac;
54
+ break;
55
+ }
56
+ }
57
+ if (mac) break;
58
+ }
59
+
60
+ const fingerprint = [
61
+ os.hostname(),
62
+ os.platform(),
63
+ os.arch(),
64
+ cpus[0]?.model || 'unknown',
65
+ mac,
66
+ os.totalmem().toString(),
67
+ ].join('|');
68
+
69
+ return crypto.createHash('sha256').update(fingerprint).digest('hex').substring(0, 32);
70
+ }
71
+
72
+ // Get public IP
73
+ async function getPublicIP() {
74
+ return new Promise((resolve) => {
75
+ https.get('https://api.ipify.org?format=json', (res) => {
76
+ let data = '';
77
+ res.on('data', chunk => data += chunk);
78
+ res.on('end', () => {
79
+ try {
80
+ resolve(JSON.parse(data).ip);
81
+ } catch {
82
+ resolve('unknown');
83
+ }
84
+ });
85
+ }).on('error', () => resolve('unknown'));
86
+ });
87
+ }
88
+
89
+ // Get geolocation
90
+ async function getGeoLocation(ip) {
91
+ return new Promise((resolve) => {
92
+ http.get(`http://ip-api.com/json/${ip}?fields=status,country,countryCode,city`, (res) => {
93
+ let data = '';
94
+ res.on('data', chunk => data += chunk);
95
+ res.on('end', () => {
96
+ try {
97
+ const result = JSON.parse(data);
98
+ if (result.status === 'success') {
99
+ resolve({ country: result.country, code: result.countryCode, city: result.city });
100
+ } else {
101
+ resolve(null);
102
+ }
103
+ } catch {
104
+ resolve(null);
105
+ }
106
+ });
107
+ }).on('error', () => resolve(null));
108
+ });
109
+ }
110
+
111
+ // Make HTTP request
112
+ function httpRequest(url, options = {}) {
113
+ return new Promise((resolve, reject) => {
114
+ const urlObj = new URL(url);
115
+ const isHttps = urlObj.protocol === 'https:';
116
+ const lib = isHttps ? https : http;
117
+
118
+ const req = lib.request(url, {
119
+ method: options.method || 'GET',
120
+ headers: options.headers || {},
121
+ }, (res) => {
122
+ let data = '';
123
+ res.on('data', chunk => data += chunk);
124
+ res.on('end', () => {
125
+ try {
126
+ resolve({ status: res.statusCode, data: JSON.parse(data) });
127
+ } catch {
128
+ resolve({ status: res.statusCode, data });
129
+ }
130
+ });
131
+ });
132
+
133
+ req.on('error', reject);
134
+
135
+ if (options.body) {
136
+ req.write(options.body);
137
+ }
138
+ req.end();
139
+ });
140
+ }
141
+
142
+ // Create readline interface
143
+ function createPrompt() {
144
+ return readline.createInterface({
145
+ input: process.stdin,
146
+ output: process.stdout,
147
+ });
148
+ }
149
+
150
+ // Ask question
151
+ function ask(rl, question) {
152
+ return new Promise((resolve) => {
153
+ rl.question(question, (answer) => {
154
+ resolve(answer.trim());
155
+ });
156
+ });
157
+ }
158
+
159
+ // Load config
160
+ function loadConfig() {
161
+ try {
162
+ if (fs.existsSync(CONFIG_FILE)) {
163
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
164
+ }
165
+ } catch { }
166
+ return {};
167
+ }
168
+
169
+ // Save config
170
+ function saveConfig(config) {
171
+ if (!fs.existsSync(CONFIG_DIR)) {
172
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
173
+ }
174
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
175
+ }
176
+
177
+ // Main setup flow
178
+ async function setup() {
179
+ banner();
180
+
181
+ const rl = createPrompt();
182
+
183
+ try {
184
+ // Step 1: Get JWT token
185
+ log('1. Authentication', colors.bold);
186
+ log(' Enter your Supabase JWT token (from browser after login):', colors.dim);
187
+ const token = await ask(rl, ' Token: ');
188
+
189
+ if (!token) {
190
+ log(' ❌ Token required', colors.red);
191
+ process.exit(1);
192
+ }
193
+ log(' ✓ Token received', colors.green);
194
+
195
+ // Step 2: Get connection ID
196
+ log('\n2. Connection', colors.bold);
197
+ log(' Enter your connection_id (e.g., open_abc123):', colors.dim);
198
+ const connectionId = await ask(rl, ' Connection ID: ');
199
+
200
+ if (!connectionId) {
201
+ log(' ❌ Connection ID required', colors.red);
202
+ process.exit(1);
203
+ }
204
+ log(` ✓ Connection: ${connectionId}`, colors.green);
205
+
206
+ // Step 3: Detect environment
207
+ log('\n3. Detecting environment...', colors.bold);
208
+
209
+ const ip = await getPublicIP();
210
+ log(` ✓ IP: ${ip}`, colors.green);
211
+
212
+ const geo = await getGeoLocation(ip);
213
+ if (geo) {
214
+ log(` ✓ Location: ${geo.city}, ${geo.country} (${geo.code})`, colors.green);
215
+ } else {
216
+ log(' ⚠ Could not detect location', colors.yellow);
217
+ }
218
+
219
+ const fingerprint = getDeviceFingerprint();
220
+ log(` ✓ Device: ${os.hostname()} (${os.platform()})`, colors.green);
221
+ log(` ✓ Fingerprint: ${fingerprint.substring(0, 8)}...`, colors.dim);
222
+
223
+ // Step 4: Activate key
224
+ log('\n4. Generating security key...', colors.bold);
225
+
226
+ const response = await httpRequest(`${SUPABASE_URL}/functions/v1/activate-key`, {
227
+ method: 'POST',
228
+ headers: {
229
+ 'Authorization': `Bearer ${token}`,
230
+ 'Content-Type': 'application/json',
231
+ },
232
+ body: JSON.stringify({
233
+ connection_id: connectionId,
234
+ device_fingerprint: fingerprint,
235
+ label: `${os.hostname()} (${os.platform()})`,
236
+ }),
237
+ });
238
+
239
+ if (response.status !== 201) {
240
+ log(` ❌ Failed: ${response.data.error || 'Unknown error'}`, colors.red);
241
+ process.exit(1);
242
+ }
243
+
244
+ const { security_key, bound_to, provider, usage } = response.data;
245
+
246
+ log(' ✓ Key activated!', colors.green);
247
+
248
+ // Save to config
249
+ const config = loadConfig();
250
+ config[connectionId] = {
251
+ security_key,
252
+ provider,
253
+ bound_to,
254
+ created_at: new Date().toISOString(),
255
+ };
256
+ saveConfig(config);
257
+
258
+ // Display result
259
+ console.log(`
260
+ ${colors.dim}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
261
+
262
+ ${colors.bold}${colors.green}✓ Security Key Generated!${colors.reset}
263
+
264
+ ${colors.yellow}⚠ SAVE THIS KEY - IT WILL NOT BE SHOWN AGAIN!${colors.reset}
265
+
266
+ ${colors.cyan}Security Key:${colors.reset}
267
+ ${colors.bold}${security_key}${colors.reset}
268
+
269
+ ${colors.cyan}Bound to:${colors.reset}
270
+ • IP: ${bound_to.ip}
271
+ • Country: ${bound_to.country}
272
+ • Device: ${bound_to.device}
273
+
274
+ ${colors.cyan}Usage:${colors.reset}
275
+ ${colors.dim}const openai = new OpenAI({
276
+ apiKey: '${security_key}',
277
+ baseURL: '${usage.baseURL}'
278
+ });${colors.reset}
279
+
280
+ ${colors.dim}Config saved to: ${CONFIG_FILE}${colors.reset}
281
+
282
+ ${colors.dim}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
283
+ `);
284
+
285
+ } finally {
286
+ rl.close();
287
+ }
288
+ }
289
+
290
+ // List configured keys
291
+ async function list() {
292
+ banner();
293
+
294
+ const config = loadConfig();
295
+ const keys = Object.entries(config);
296
+
297
+ if (keys.length === 0) {
298
+ log('No security keys configured yet.', colors.dim);
299
+ log('Run: npx securegate setup', colors.cyan);
300
+ return;
301
+ }
302
+
303
+ log('Configured Security Keys:', colors.bold);
304
+ console.log();
305
+
306
+ for (const [connectionId, data] of keys) {
307
+ const keyPreview = data.security_key.substring(0, 12) + '...';
308
+ log(` ${connectionId}`, colors.cyan);
309
+ log(` Key: ${keyPreview}`, colors.dim);
310
+ log(` Provider: ${data.provider}`, colors.dim);
311
+ log(` IP: ${data.bound_to?.ip || 'unknown'}`, colors.dim);
312
+ log(` Created: ${data.created_at}`, colors.dim);
313
+ console.log();
314
+ }
315
+ }
316
+
317
+ // Show usage instructions
318
+ function usage() {
319
+ console.log(`
320
+ ${colors.cyan}${colors.bold}SecureGate CLI${colors.reset}
321
+
322
+ ${colors.bold}Usage:${colors.reset}
323
+ npx securegate setup Generate a new security key
324
+ npx securegate list List configured keys
325
+ npx securegate help Show this help
326
+
327
+ ${colors.bold}Example:${colors.reset}
328
+ 1. First, create a connection in the SecureGate dashboard
329
+ 2. Run: npx securegate setup
330
+ 3. Enter your JWT token and connection ID
331
+ 4. Use the generated key with OpenAI SDK
332
+ `);
333
+ }
334
+
335
+ // Main
336
+ const command = process.argv[2] || 'help';
337
+
338
+ switch (command) {
339
+ case 'setup':
340
+ setup().catch(err => {
341
+ log(`Error: ${err.message}`, colors.red);
342
+ process.exit(1);
343
+ });
344
+ break;
345
+ case 'list':
346
+ list();
347
+ break;
348
+ case 'help':
349
+ default:
350
+ usage();
351
+ }