Skip to content

Commit

Permalink
feat: improve configuration settings UX, increase auth waiting time (#26
Browse files Browse the repository at this point in the history
)
  • Loading branch information
michelkaporin authored Jul 16, 2021
1 parent e3ab414 commit 467e33b
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 65 deletions.
51 changes: 15 additions & 36 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,42 +46,24 @@
{
"title": "Snyk Vulnerability Scanner",
"properties": {
"snyk.advancedMode": {
"type": "boolean",
"default": false,
"description": "Toggle advanced tools for expert users",
"scope": "application"
},
"snyk.token": {
"type": "string",
"default": "",
"description": "API key",
"scope": "application"
},
"snyk.uploadApproved": {
"type": "boolean",
"default": false,
"markdownDescription": "User consent for code upload to Snyk in agreement with our [terms and conditions](https://snyk.io/policies/terms-of-service/?utm_source=vsc). **This setting will be removed soon. Please use `snyk.codeEnabled` instead.**",
"scope": "window"
},
"snyk.codeEnabled": {
"type": "boolean",
"description": "Snyk Code is enabled. If Snyk organization settings has Snyk Code disabled, this flag will be automatically set to false.",
"scope": "window",
"default": null
},
"snyk.yesCrashReport": {
"//": "Name starts with y to put it at the end, as configs are sorted alphbetically",
"type": "boolean",
"default": true,
"markdownDescription": "Allow crash reports to be reported to Snyk",
"markdownDescription": "Allow crash reports to be reported to Snyk.",
"scope": "application"
},
"snyk.yesTelemetry": {
"//": "Name starts with y to put it at the end, as configs are sorted alphbetically",
"type": "boolean",
"default": true,
"markdownDescription": "Allow extension's telemetry to be sent to Snyk",
"markdownDescription": "Allow extension's telemetry to be sent to Snyk.",
"scope": "application"
},
"snyk.yesWelcomeNotification": {
Expand All @@ -90,6 +72,18 @@
"default": true,
"markdownDescription": "Show welcome notification after installation and restart",
"scope": "application"
},
"snyk.advanced.advancedMode": {
"type": "boolean",
"default": false,
"description": "Allows the user to configure if Snyk analysis is run automatically, manually or every 30 minutes. Default is automatically on save.",
"scope": "application"
},
"snyk.advanced.codeEnabled": {
"type": "boolean",
"markdownDescription": "Mirrors if Snyk Code is enabled or disabled for [your Snyk organisation](https://app.snyk.io/manage/snyk-code). Please do not manually edit this configuration as it might cause unpredictable behaviour.",
"scope": "window",
"default": null
}
}
}
Expand Down Expand Up @@ -143,24 +137,9 @@
},
{
"view": "snyk.views.analysis",
"contents": "Thanks for connecting with Snyk. ✅\n 👉 You are almost set 🤗.",
"when": "!snyk:error && snyk:loggedIn && !snyk:codeEnabled && !snyk:uploadApproved"
},
{
"view": "snyk.views.analysis",
"contents": "👋 Thank you for using Snyk Code! To minimize the chances of unwanted source code upload, we've introduced a new flag, to control if source code is uploaded from a single place. This flag is valid for your Snyk organization and supersedes previous upload approval.",
"when": "!snyk:error && snyk:loggedIn && !snyk:codeEnabled && snyk:uploadApproved"
},
{
"view": "snyk.views.analysis",
"contents": "[Enable Snyk Code and start analysing](command:snyk.enableCode 'Upload code to Snyk')",
"contents": "Thanks for connecting with Snyk. ✅\n 👉 You are almost set 🤗.\n[Enable Snyk Code and start analysing](command:snyk.enableCode 'Upload code to Snyk')\nIt looks like your organization's configuration is disabled, that's why you are seeing this message. You can easily enable it by pressing the above button and switching it on.\nWe apologize for the inconvenience and please [contact us](https://snyk.io/contact-us/?utm_source=vsc) if you have any other questions or concerns!",
"when": "!snyk:error && snyk:loggedIn && !snyk:codeEnabled"
},
{
"view": "snyk.views.analysis",
"contents": "It looks like your organization's configuration is disabled, that's why you are seeing this message. You can easily enable it by pressing the above button and switching it on.\nWe apologize for the inconvenience and please [contact us](https://snyk.io/contact-us/?utm_source=vsc) if you have any other questions or concerns!",
"when": "!snyk:error && snyk:loggedIn && !snyk:codeEnabled && snyk:uploadApproved"
},
{
"view": "snyk.views.analysis",
"contents": "Open a workspace or a folder in Visual Studio Code to start the analysis.",
Expand Down
57 changes: 39 additions & 18 deletions src/snyk/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { URL } from 'url';
import * as vscode from 'vscode';
import { IDE_NAME } from './constants/general';
import {
ADVANCED_ADVANCED_CODE_ENABLED_SETTING,
ADVANCED_ADVANCED_MODE_SETTING,
CONFIGURATION_IDENTIFIER,
TOKEN_SETTING,
YES_CRASH_REPORT_SETTING,
YES_TELEMETRY_SETTING,
YES_WELCOME_NOTIFICATION_SETTING,
} from './constants/settings';

export interface IConfiguration {
isDevelopment: boolean;
Expand All @@ -10,7 +19,6 @@ export interface IConfiguration {
snykCodeUrl: string;
token: string | undefined;
setToken(token: string): Promise<void>;
uploadApproved: boolean;
codeEnabled: boolean | undefined;
shouldReportErrors: boolean;
shouldReportEvents: boolean;
Expand Down Expand Up @@ -49,57 +57,70 @@ export class Configuration implements IConfiguration {
}

get token(): string | undefined {
return this.staticToken || this.vscodeWorkspace.getConfiguration('snyk').get('token');
return (
this.staticToken ||
this.vscodeWorkspace.getConfiguration(CONFIGURATION_IDENTIFIER).get(this.getConfigName(TOKEN_SETTING))
);
}

async setToken(token: string): Promise<void> {
this.staticToken = '';
await this.vscodeWorkspace.getConfiguration('snyk').update('token', token, true);
await this.vscodeWorkspace
.getConfiguration(CONFIGURATION_IDENTIFIER)
.update(this.getConfigName(TOKEN_SETTING), token, true);
}

get source(): string {
return this.processEnv.GITPOD_WORKSPACE_ID ? 'gitpod' : IDE_NAME;
}

get uploadApproved(): boolean {
return (
this.staticCodeEnabled ||
this.source !== IDE_NAME ||
!!this.vscodeWorkspace.getConfiguration('snyk').get<boolean>('uploadApproved') // TODO: remove once grace period is out
);
}

get codeEnabled(): boolean | undefined {
return (
this.staticCodeEnabled ||
this.source !== IDE_NAME ||
this.vscodeWorkspace.getConfiguration('snyk').get<boolean | undefined>('codeEnabled')
this.vscodeWorkspace
.getConfiguration(CONFIGURATION_IDENTIFIER)
.get<boolean | undefined>(this.getConfigName(ADVANCED_ADVANCED_CODE_ENABLED_SETTING))
);
}

async setCodeEnabled(value = true): Promise<void> {
await this.vscodeWorkspace.getConfiguration('snyk').update('codeEnabled', value, true);
await this.vscodeWorkspace
.getConfiguration(CONFIGURATION_IDENTIFIER)
.update(this.getConfigName(ADVANCED_ADVANCED_CODE_ENABLED_SETTING), value, true);
}

get shouldReportErrors(): boolean {
return !!this.vscodeWorkspace.getConfiguration('snyk').get<boolean>('yesCrashReport');
return !!this.vscodeWorkspace
.getConfiguration(CONFIGURATION_IDENTIFIER)
.get<boolean>(this.getConfigName(YES_CRASH_REPORT_SETTING));
}

get shouldReportEvents(): boolean {
return !!this.vscodeWorkspace.getConfiguration('snyk').get<boolean>('yesTelemetry');
return !!this.vscodeWorkspace
.getConfiguration(CONFIGURATION_IDENTIFIER)
.get<boolean>(this.getConfigName(YES_TELEMETRY_SETTING));
}

get shouldShowWelcomeNotification(): boolean {
return !!this.vscodeWorkspace.getConfiguration('snyk').get<boolean>('yesWelcomeNotification');
return !!this.vscodeWorkspace
.getConfiguration(CONFIGURATION_IDENTIFIER)
.get<boolean>(this.getConfigName(YES_WELCOME_NOTIFICATION_SETTING));
}

async hideWelcomeNotification(): Promise<void> {
await this.vscodeWorkspace.getConfiguration('snyk').update('yesWelcomeNotification', false, true);
await this.vscodeWorkspace
.getConfiguration(CONFIGURATION_IDENTIFIER)
.update(this.getConfigName(YES_WELCOME_NOTIFICATION_SETTING), false, true);
}

get shouldShowAdvancedView(): boolean {
return !!this.vscodeWorkspace.getConfiguration('snyk').get<boolean>('advancedMode');
return !!this.vscodeWorkspace
.getConfiguration(CONFIGURATION_IDENTIFIER)
.get<boolean>(this.getConfigName(ADVANCED_ADVANCED_MODE_SETTING));
}

private getConfigName = (setting: string) => setting.replace(`${CONFIGURATION_IDENTIFIER}.`, '');
}

export const configuration = new Configuration();
11 changes: 10 additions & 1 deletion src/snyk/constants/settings.ts
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
export const REVIEW_RESULTS_SETTINGS = 'snyk.review.results';
// VS Code configuration settings
// Ensure consistency with package.json when changing these constants
export const CONFIGURATION_IDENTIFIER = 'snyk';

export const TOKEN_SETTING = `${CONFIGURATION_IDENTIFIER}.token`;
export const YES_CRASH_REPORT_SETTING = `${CONFIGURATION_IDENTIFIER}.yesCrashReport`;
export const YES_TELEMETRY_SETTING = `${CONFIGURATION_IDENTIFIER}.yesTelemetry`;
export const YES_WELCOME_NOTIFICATION_SETTING = `${CONFIGURATION_IDENTIFIER}.yesWelcomeNotification`;
export const ADVANCED_ADVANCED_MODE_SETTING = `${CONFIGURATION_IDENTIFIER}.advanced.advancedMode`;
export const ADVANCED_ADVANCED_CODE_ENABLED_SETTING = `${CONFIGURATION_IDENTIFIER}.advanced.codeEnabled`;
1 change: 0 additions & 1 deletion src/snyk/constants/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export const SNYK_VIEW_SUGGESTION = 'snyk.views.suggestion';
export const SNYK_CONTEXT = {
LOGGEDIN: 'loggedIn',
AUTHENTICATING: 'authenticating',
APPROVED: 'uploadApproved', // todo: removed once 'uploadApproved' is deprecated
CODE_ENABLED: 'codeEnabled',
WORKSPACE_FOUND: 'workspaceFound',
ERROR: 'error',
Expand Down
11 changes: 7 additions & 4 deletions src/snyk/lib/modules/LoginModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,23 +78,26 @@ abstract class LoginModule extends ReportModule implements LoginModuleInterface
}

private async waitLoginConfirmation(draftToken: string): Promise<string> {
// 20 attempts to wait for user's login & consent
for (let i = 0; i < 20; i += 1) {
await sleep(1000);
// 90 seconds to wait for user's authentication
/* eslint-disable no-await-in-loop */
for (let i = 0; i < 50; i += 1) {
const waitTime = i < 30 ? 1000 : 3000; // wait 1s for the first 30s, then poll each 3s
await sleep(waitTime);

const token = await this.checkSession(draftToken);
if (token) {
return token;
}
}
/* eslint-enable no-await-in-loop */

return '';
}

async checkCodeEnabled(): Promise<boolean> {
const enabled = await this.snykCode.isEnabled();

await this.contextService.setContext(SNYK_CONTEXT.CODE_ENABLED, enabled);
await this.contextService.setContext(SNYK_CONTEXT.APPROVED, configuration.uploadApproved); // todo: removed once 'uploadApproved' is deprecated
if (!enabled) {
this.loadAnalytics();

Expand Down
17 changes: 12 additions & 5 deletions src/snyk/lib/watchers/SnykSettingsWatcher.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import * as vscode from 'vscode';
import { ExtensionInterface, SnykWatcherInterface } from '../../../interfaces/SnykInterfaces';
import {
ADVANCED_ADVANCED_CODE_ENABLED_SETTING,
ADVANCED_ADVANCED_MODE_SETTING,
TOKEN_SETTING,
} from '../../constants/settings';
import { errorsLogs } from '../../messages/errorsServerLogMessages';

class SnykSettingsWatcher implements SnykWatcherInterface {
private async onChangeConfiguration(extension: ExtensionInterface, key: string): Promise<void> {
if (key === 'snyk.advancedMode') {
if (key === ADVANCED_ADVANCED_MODE_SETTING) {
return extension.checkAdvancedMode();
} else if (key === 'snyk.codeEnabled') {
} else if (key === ADVANCED_ADVANCED_CODE_ENABLED_SETTING) {
void extension.checkCodeEnabled();
return;
}
Expand All @@ -25,9 +30,11 @@ class SnykSettingsWatcher implements SnykWatcherInterface {
public activate(extension: ExtensionInterface): void {
vscode.workspace.onDidChangeConfiguration(
async (event: vscode.ConfigurationChangeEvent): Promise<void> => {
const change = ['snyk.url', 'snyk.token', 'snyk.codeEnabled', 'snyk.advancedMode'].find(config =>
event.affectsConfiguration(config),
);
const change = [
TOKEN_SETTING,
ADVANCED_ADVANCED_CODE_ENABLED_SETTING,
ADVANCED_ADVANCED_MODE_SETTING,
].find(config => event.affectsConfiguration(config));
if (change) {
try {
await this.onChangeConfiguration(extension, change);
Expand Down

0 comments on commit 467e33b

Please sign in to comment.