Skip to content
This repository has been archived by the owner on Sep 11, 2023. It is now read-only.

Commit

Permalink
feat: sending statistics to analyse user flow
Browse files Browse the repository at this point in the history
  • Loading branch information
bmvermeer committed Apr 28, 2020
1 parent 66b38a7 commit f85070d
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 25 deletions.
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"dev": "webpack --mode development --watch",
"test": "jest ."
},
"author": "Remy Sharp <remy@leftlogic.com>",
"author": "Snyk <vscode@snyk.io>",
"engines": {
"vscode": "^1.40.0"
},
Expand Down Expand Up @@ -107,6 +107,10 @@
{
"command": "vulnCost.showOutput",
"title": "Snyk: Show vulnerability report"
},
{
"command": "vulnCost.openVulnPage",
"title": "Snyk: Show vulnerability page"
}
]
},
Expand All @@ -122,7 +126,7 @@
"axios": "^0.19.2",
"find-package-json": "^1.2.0",
"htmlparser2": "^4.1.0",
"uuid": "^7.0.2",
"uuid": "^7.0.3",
"validate-npm-package-name": "^3.0.0"
},
"devDependencies": {
Expand Down
27 changes: 5 additions & 22 deletions src/SnykAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,8 @@ function createShowOutputAction(args) {
return createSimpleAction({ command: 'vulnCost.showOutput', ...args });
}

function createOpenBrowserAction({
actionTitle,
title,
url,
isPreferred = false,
diagnostic,
}) {
const action = new vscode.CodeAction(
actionTitle,
vscode.CodeActionKind.QuickFix
);

action.command = {
command: 'vscode.open',
title,
arguments: [vscode.Uri.parse(url)],
};
action.diagnostics = [diagnostic];
action.isPreferred = isPreferred;
return action;
function createOpenVulnPageAction(args) {
return createSimpleAction({ command: 'vulnCost.openVulnPage', ...args });
}

/**
Expand Down Expand Up @@ -83,11 +65,12 @@ export class SnykVulnInfo {
}

res.push(
createOpenBrowserAction({
createOpenVulnPageAction({
diagnostic,
url: `https://snyk.io/test/npm/${pkg}?${utm}`,
actionTitle: 'Learn about this vulnerability',
title: 'Learn about this vulnerability',
args: [pkg],
isPreferred: true,
})
);

Expand Down
18 changes: 17 additions & 1 deletion src/extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { refreshDiagnostics } from './diagnostics';
import { v4 as uuidv4 } from 'uuid';
import authenticate from './authenticate';
import utm from './utm';
import statistics from './statistics';

const { window, workspace, commands } = vscode;

Expand All @@ -24,13 +25,16 @@ let packageWatcher = {};
export function activate(context) {
try {
logger.init(context);
statistics.init(context);

if (isAuthed()) {
logger.log('🔒 Using Snyk credentials');
} else {
logger.log('🔓 Using anonymous API');
}

statistics.sendStartup('authed: ' + isAuthed());

[JAVASCRIPT, TYPESCRIPT, HTML, PJSON].forEach(language => {
context.subscriptions.push(
vscode.languages.registerCodeActionsProvider(
Expand Down Expand Up @@ -70,6 +74,7 @@ export function activate(context) {
context.subscriptions.push(
commands.registerCommand('vulnCost.toggle', () => {
isActive = !isActive;
statistics.send('vulnCost.toggle', `active: ${isActive}`);
if (isActive && window.activeTextEditor) {
processActiveFile(window.activeTextEditor.document, diagnostics);
} else {
Expand All @@ -81,6 +86,7 @@ export function activate(context) {

context.subscriptions.push(
commands.registerCommand('vulnCost.showOutput', vuln => {
statistics.send('vulnCost.showOutput', vuln.packageName);
if (!vuln) {
return logger.show();
}
Expand All @@ -91,6 +97,7 @@ export function activate(context) {

context.subscriptions.push(
commands.registerCommand('vulnCost.signOut', () => {
statistics.send('vulnCost.signOut');
window.showInformationMessage('Removing auth token');

clearToken();
Expand All @@ -107,7 +114,7 @@ export function activate(context) {
);
return;
}

statistics.send('vulnCost.signIn');
const token = uuidv4();
const url = `https://app.snyk.io/login?${utm}&token=${token}`;

Expand All @@ -131,6 +138,15 @@ export function activate(context) {
});
})
);

context.subscriptions.push(
commands.registerCommand('vulnCost.openVulnPage', pkg => {
statistics.send('vulnCost.openVulnPage', pkg);
const url = `https://snyk.io/test/npm/${pkg}?${utm}`;
vscode.env.openExternal(vscode.Uri.parse(url));
return;
})
);
} catch (e) {
console.log(e.message);
logger.log('wrapping error: ' + e);
Expand Down
2 changes: 2 additions & 0 deletions src/getImports/testVuln.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { isAuthed, getToken } from './snykAPI';
import axios from 'axios';
import logger from '../logger';
import utm from '../utm';
import statistics from '../statistics';

const API_ROOT = 'https://snyk.io/api/v1/vuln/npm/';

Expand Down Expand Up @@ -63,6 +64,7 @@ function testWithAuth(pkg) {

export default function test(pkg) {
logger.log(`testing ${pkg.name}@${pkg.version}`);
statistics.sendTest(`${pkg.name}@${pkg.version} - authed: ${isAuthed()}`);
if (isAuthed()) {
return testWithAuth(pkg);
} else {
Expand Down
83 changes: 83 additions & 0 deletions src/statistics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { v4 as uuidv4 } from 'uuid';
import logger from './logger';
import axios from 'axios';
import * as vscode from 'vscode';

const STATS_API_ROOT = 'https://us-central1-snyk-vulncost.cloudfunctions.net/app/';
const meta = 'vulncost-analytics';
const FIRST_STARTUP = 'FIRST_STARTUP';
const STARTUP = 'STARTUP';
const TEST = 'TEST';

const extensionInfo = vscode.extensions.getExtension('snyk-security.vscode-vuln-cost').packageJSON

const instance = axios.create({
baseURL: STATS_API_ROOT,
timeout: 5000
});

class Statistics {

init(context) {
this.context = context;
this.userid = context.globalState.get('userid');
logger.log('userid found: ' + this.userid);

if (!this.userid) {
this.userid = uuidv4();
logger.log('created userid: ' + this.userid);
context.globalState.update('userid', this.userid)
}
}

ping() {
logger.log('try to ping');
instance.get('ping')
.then(response => { logger.log('pinged statistics server: ' + response.data); })
.catch(error => { logger.log(error); });
}

sendTest(comment) {
//max send once every 2 minutes
const now = new Date().getTime();
if (!this.lastTestSend || now - this.lastTestSend >= 120000) {
this.send(TEST, comment);
this.lastTestSend = now;
}
}

sendStartup(comment) {
this.firstStartup = this.context.globalState.get('firstStartup');
if (!this.firstStartup) {
this.send(FIRST_STARTUP, comment);
this.context.globalState.update('firstStartup', new Date().getTime());
} else {
this.send(STARTUP, comment);
}
}

send(action, comment) {
logger.log(`sending stats action:[${action}], comment:[${comment}]`);
const message = {
"meta": meta,
"time": new Date().getTime(),
"item": {
"user": this.userid,
"app": extensionInfo.name + ' ' + extensionInfo.version,
"action": action,
"comment": comment
}
};

instance.post('api/log', message)
.then(response => {
logger.log(`response: ${response.status} on message ${message.action} - ${message.comment}`);
})
.catch(error => {
logger.log(`error: ${error} on message ${message.action} - ${message.comment}`);
});
}
}

export default new Statistics();

0 comments on commit f85070d

Please sign in to comment.