Skip to content

Commit

Permalink
feat!: anonymous event data collection
Browse files Browse the repository at this point in the history
  • Loading branch information
gabidobo authored and andreimarinescu committed Sep 13, 2022
1 parent 1f10ebb commit 4ad3988
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 1 deletion.
57 changes: 57 additions & 0 deletions cli/index.js
@@ -1,15 +1,71 @@
#!/usr/bin/env node
const http = require('http');
const https = require('https');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

const logger = console;
const port = process.env.SANDWORM_INSPECTOR_PORT || 7071;
const refreshRate = 1000; // in milliseconds
// Each Inspector run gets a sessionId to help us make sense of telemetry data
const sessionId = crypto.randomUUID();

let history = [];
const eventSubscribers = [];

const disableTelemetry = process.argv.includes('--no-telemetry');

const createTelemetryBody = (data) =>
JSON.stringify(
data
.map((event) => {
let {module} = event;
try {
const url = new URL(module);
if (url.protocol === 'http:' || url.protocol === 'https:') {
// Truncate this URL so we don't collect private data
module = url.hostname;
}
// eslint-disable-next-line no-empty
} catch (error) {}
return {
module,
family: event.family,
method: event.method,
sessionId,
};
})
// We only care about package activity
.filter(({module}) => module !== 'root'),
);

// This sends anonymous data about module activity to our collection service.
// We use this to build an open catalogue of package permission requirements.
// To disable, run the Inspector with `--no-telemetry`
const sendTelemetry = (data) => {
if (disableTelemetry) {
return;
}

const body = createTelemetryBody(data);
const req = https.request({
hostname: 'collect.sandworm.dev',
port: 443,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': body.length,
},
});

req.on('error', (error) => {
logger.error('collection failed:', error);
});
req.write(body);
req.end();
};

const server = http.createServer((request, response) => {
switch (request.url) {
// Serve the frontend React app
Expand Down Expand Up @@ -51,6 +107,7 @@ const server = http.createServer((request, response) => {
request.on('end', () => {
try {
const body = JSON.parse(stringBody);
sendTelemetry(body);

// Add a UID to every event
// React can use this as a unique event key when rendering the UI
Expand Down
4 changes: 3 additions & 1 deletion docs/index.md
Expand Up @@ -18,7 +18,7 @@ description: Easy sandboxing for your JavaScript dependencies 馃
* audit your dependencies and see what your code is doing under the hood;
* secure your app against supply chain attacks by enforcing per-module permissions.
* Install it as an `npm` module in your existing Node or browser app.
* Use the Inspector CLI tool to monitor activity and permissions.
* Use the Inspector tool to monitor activity and permissions.

#### Get involved

Expand Down Expand Up @@ -89,6 +89,8 @@ If your automated test process has good coverage, this is an excellent time to r

![Sandworm Inspector](../cli/screenshot.png)

\| **Note**: We're building a public database of per-package permissions based on anonymous info about requirements sent by the inspector. This will allow us to make Sandworm easier to set up for future users and also enable us to create a public catalog of package requirements, making it easier to perform a security audit for an application's dependencies. To opt out of sharing data with the community, run the inspector with the `--no-telemetry` option. You can also audit [what's getting sent](https://github.com/sandworm-hq/sandworm-js/blob/main/cli/index.js#L19) and the [server code](https://github.com/sandworm-hq/sandworm-collect).

### Enforcing Permissions in Production Mode

To use in production mode and start enforcing module API access restrictions, provide a `permissions` array to `Sandworm.init`:
Expand Down

0 comments on commit 4ad3988

Please sign in to comment.