Skip to content

Commit a7a68dc

Browse files
authored
Fix: Auth login and UI issues (#310)
* feat: auth window * fix: tree horizontal alignment * fix: back slashes for package title
1 parent f505cbc commit a7a68dc

19 files changed

+268
-203
lines changed

Snyk.Common/Settings/ISnykOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public interface ISnykOptions
100100
/// If the token is invalid, attempts to run the authentication command.
101101
/// </summary>
102102
/// <returns>Returns true if authenticated successfully, or if a valid token was loaded from storage.</returns>
103-
bool Authenticate();
103+
void Authenticate();
104104
public string CurrentCliVersion { get; set; }
105105

106106
SastSettings SastSettings { get; set; }
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<ui:DialogWindow x:Class="Snyk.VisualStudio.Extension.AuthDialogWindow"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6+
xmlns:toolkit="clr-namespace:Community.VisualStudio.Toolkit;assembly=Community.VisualStudio.Toolkit"
7+
xmlns:ui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0"
8+
mc:Ignorable="d"
9+
WindowStartupLocation="CenterScreen"
10+
IsCloseButtonEnabled="True"
11+
HasHelpButton="False"
12+
MinHeight="290" Height="290"
13+
MinWidth="500" Width="500"
14+
BorderBrush="{x:Static SystemColors.WindowFrameBrush}" BorderThickness="1"
15+
WindowStyle="None" ResizeMode="NoResize" AllowsTransparency="True"
16+
xmlns:catalog="clr-namespace:Microsoft.VisualStudio.Imaging;assembly=Microsoft.VisualStudio.ImageCatalog"
17+
xmlns:imaging="clr-namespace:Microsoft.VisualStudio.Imaging;assembly=Microsoft.VisualStudio.Imaging"
18+
toolkit:Themes.UseVsTheme="True"
19+
Title="Authenticating Snyk Plugin"
20+
MouseDown="AuthDialogWindow_OnMouseDown">
21+
<DockPanel Margin="10">
22+
<Button DockPanel.Dock="Top" HorizontalAlignment="Right" Click="CancelButton_OnClick" MinWidth="1"
23+
MinHeight="1" Width="35" Margin="0" Padding="0">
24+
<imaging:CrispImage Moniker="{x:Static catalog:KnownMonikers.Close}" />
25+
</Button>
26+
<DockPanel DockPanel.Dock="Bottom">
27+
<Button x:Name="CopyLinkButton" Margin="5, 5" Content="📄Copy URL" Click="CopyLinkButton_OnClick" Width="96" />
28+
<Button x:Name="CancelButton" DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="5, 5" Content="Cancel" Click="CancelButton_OnClick" Width="78" />
29+
</DockPanel>
30+
<Grid>
31+
<Grid.RowDefinitions>
32+
<RowDefinition Height="auto" />
33+
<RowDefinition Height="auto" />
34+
</Grid.RowDefinitions>
35+
<Grid Grid.Row="0">
36+
<Grid.ColumnDefinitions>
37+
<ColumnDefinition Width="*" />
38+
<ColumnDefinition Width="5*" />
39+
</Grid.ColumnDefinitions>
40+
<imaging:CrispImage Grid.Column="0" Width="50"
41+
Moniker="{x:Static catalog:KnownMonikers.StatusInformation}" />
42+
<StackPanel VerticalAlignment="Center" Grid.Column="1" Margin="0, 0, 10, 0"/>
43+
</Grid>
44+
<StackPanel Grid.Row="1" Margin="5">
45+
<TextBlock TextWrapping="Wrap">
46+
We are now redirecting you to our auth page, go ahead and log in.
47+
<LineBreak />
48+
<LineBreak />
49+
Once the authentication is complete, return to the IDE and you'll be ready to start using Snyk.
50+
<LineBreak />
51+
<LineBreak />
52+
If a browser window doesn't open after a few seconds, please copy the url using the button below and manually paste it in a browser.
53+
<LineBreak />
54+
<LineBreak />
55+
56+
</TextBlock>
57+
<ProgressBar Height="10" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" IsIndeterminate="True" />
58+
</StackPanel>
59+
</Grid>
60+
</DockPanel>
61+
</ui:DialogWindow>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System.Windows;
2+
using System.Windows.Input;
3+
using Microsoft.VisualStudio.PlatformUI;
4+
using Microsoft.VisualStudio.Shell;
5+
using Snyk.VisualStudio.Extension.Language;
6+
7+
namespace Snyk.VisualStudio.Extension
8+
{
9+
public partial class AuthDialogWindow : DialogWindow
10+
{
11+
public static AuthDialogWindow Instance { get; } = new AuthDialogWindow();
12+
13+
public AuthDialogWindow()
14+
{
15+
this.InitializeComponent();
16+
this.Closing += AuthDialogWindow_Closing;
17+
}
18+
19+
private void AuthDialogWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
20+
{
21+
e.Cancel = true;
22+
this.Visibility = Visibility.Hidden;
23+
}
24+
25+
private void AuthDialogWindow_OnMouseDown(object sender, MouseButtonEventArgs e)
26+
{
27+
if (e.ChangedButton == MouseButton.Left)
28+
{
29+
this.DragMove();
30+
}
31+
}
32+
33+
private void CopyLinkButton_OnClick(object sender, RoutedEventArgs e)
34+
{
35+
ThreadHelper.JoinableTaskFactory.RunAsync(async () => await LanguageClientHelper.LanguageClientManager().InvokeCopyLinkAsync(SnykVSPackage.Instance.DisposalToken)).FireAndForget();
36+
}
37+
38+
private void CancelButton_OnClick(object sender, RoutedEventArgs e)
39+
{
40+
this.Close();
41+
}
42+
}
43+
}

Snyk.VisualStudio.Extension.2022/Language/ILanguageClientManager.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ public interface ILanguageClientManager
1919
Task<string> InvokeLogin(CancellationToken cancellationToken);
2020
Task<object> InvokeLogout(CancellationToken cancellationToken);
2121
Task<object> DidChangeConfigurationAsync(CancellationToken cancellationToken);
22+
Task<string> InvokeCopyLinkAsync(CancellationToken cancellationToken);
2223
event AsyncEventHandler<SnykLanguageServerEventArgs> OnLanguageServerReadyAsync;
2324
event AsyncEventHandler<SnykLanguageServerEventArgs> OnLanguageClientNotInitializedAsync;
25+
void FireOnLanguageClientNotInitializedAsync();
2426
}
2527
}

Snyk.VisualStudio.Extension.2022/Language/LspAnalysisResult.cs renamed to Snyk.VisualStudio.Extension.2022/Language/LsAnalysisResult.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
namespace Snyk.VisualStudio.Extension.Language
77
{
88
[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
9-
public class LspAnalysisResult
9+
public class LsAnalysisResult
1010
{
1111
public string Status { get; set; }
1212
public string Product { get; set; }
@@ -181,4 +181,9 @@ public class Start
181181
public int Line { get; set; }
182182
public int Character { get; set; }
183183
}
184+
185+
public class LsTrust
186+
{
187+
public IList<string> TrustedFolders { get; set; }
188+
}
184189
}

Snyk.VisualStudio.Extension.2022/Language/SnykLanguageClient.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public object GetInitializationOptions()
6565
ActivateSnykIac = options.IacEnabled.ToString(),
6666
SendErrorReports = "true",
6767
ManageBinariesAutomatically = options.BinariesAutoUpdate.ToString(),
68-
EnableTrustedFoldersFeature = "false",
68+
EnableTrustedFoldersFeature = "true",
6969
TrustedFolders = options.TrustedFolders.ToList(),
7070
IntegrationName = options.IntegrationName,
7171
FilterSeverity = new FilterSeverityOptions
@@ -173,7 +173,7 @@ public async Task StartServerAsync(bool shouldStart = false)
173173
{
174174
if (CustomMessageTarget == null)
175175
{
176-
CustomMessageTarget = new SnykLanguageClientCustomTarget(SnykVSPackage.ServiceProvider, this);
176+
CustomMessageTarget = new SnykLanguageClientCustomTarget(SnykVSPackage.ServiceProvider);
177177
}
178178
Logger.Information("Starting Language Server");
179179
await StartAsync.InvokeAsync(this, EventArgs.Empty);
@@ -338,7 +338,7 @@ public async Task<object> InvokeLogout(CancellationToken cancellationToken)
338338
return isEnabled;
339339
}
340340

341-
public async Task<string> InvokeCopyLink(CancellationToken cancellationToken)
341+
public async Task<string> InvokeCopyLinkAsync(CancellationToken cancellationToken)
342342
{
343343
var param = new LSP.ExecuteCommandParams
344344
{

Snyk.VisualStudio.Extension.2022/Language/SnykLanguageClientCustomTarget.cs

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,8 @@
22
using System.Collections.Concurrent;
33
using System.Collections.Generic;
44
using System.Linq;
5-
using System.Threading;
65
using System.Threading.Tasks;
76
using Newtonsoft.Json.Linq;
8-
using Serilog;
9-
using Snyk.Common;
107
using Snyk.Common.Authentication;
118
using Snyk.VisualStudio.Extension.Service;
129
using StreamJsonRpc;
@@ -19,11 +16,10 @@ public class SnykLanguageClientCustomTarget
1916
private readonly ConcurrentDictionary<string, IEnumerable<Issue>> snykCodeIssueDictionary = new();
2017
private readonly ConcurrentDictionary<string, IEnumerable<Issue>> snykOssIssueDictionary = new();
2118
private readonly ConcurrentDictionary<string, IEnumerable<Issue>> snykIaCIssueDictionary = new();
22-
private readonly ILanguageClientManager languageClientManager;
23-
public SnykLanguageClientCustomTarget(ISnykServiceProvider serviceProvider, ILanguageClientManager languageClientManager)
19+
20+
public SnykLanguageClientCustomTarget(ISnykServiceProvider serviceProvider)
2421
{
2522
this.serviceProvider = serviceProvider;
26-
this.languageClientManager = languageClientManager;
2723
}
2824

2925
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
@@ -51,8 +47,6 @@ public async Task OnPublishDiagnostics316(JToken arg)
5147
return;
5248
}
5349

54-
// TODO: handle the case when source is: 'Snyk Error'
55-
5650
var source = LspSourceToProduct(diagnosticsArray[0]["source"].ToString());
5751
var dataList = diagnosticsArray.Where(x => x["data"] != null)
5852
.Select(x =>
@@ -89,18 +83,18 @@ public async Task OnSnykScan(JToken arg)
8983
return;
9084
}
9185

92-
var lspAnalysisResult = arg.TryParse<LspAnalysisResult>();
86+
var lspAnalysisResult = arg.TryParse<LsAnalysisResult>();
9387
if (lspAnalysisResult == null) return;
9488
switch (lspAnalysisResult.Product)
9589
{
9690
case Product.Code:
97-
await ProcessCodeScanAsnyc(lspAnalysisResult);
91+
await ProcessCodeScanAsync(lspAnalysisResult);
9892
break;
9993
case Product.Oss:
100-
await ProcessOssScanAsnyc(lspAnalysisResult);
94+
await ProcessOssScanAsync(lspAnalysisResult);
10195
break;
10296
case Product.Iac:
103-
await ProcessIacScanAsnyc(lspAnalysisResult);
97+
await ProcessIacScanAsync(lspAnalysisResult);
10498
break;
10599
}
106100
}
@@ -132,27 +126,31 @@ public async Task OnHasAuthenticated(JToken arg)
132126

133127
if (serviceProvider.Options.AutoScan)
134128
{
135-
await this.languageClientManager.InvokeWorkspaceScanAsync(SnykVSPackage.Instance.DisposalToken);
129+
await serviceProvider.TasksService.ScanAsync();
136130
}
137131
}
138132

139133
[JsonRpcMethod(LsConstants.SnykAddTrustedFolders)]
140134
public async Task OnAddTrustedFolders(JToken arg)
141135
{
136+
var trustedFolders = arg.TryParse<LsTrust>();
137+
if (trustedFolders == null) return;
142138

139+
serviceProvider.Options.TrustedFolders = new HashSet<string>(trustedFolders.TrustedFolders);
140+
this.serviceProvider.UserStorageSettingsService?.SaveSettings();
143141
}
144142

145-
private async Task ProcessCodeScanAsnyc(LspAnalysisResult lspAnalysisResult)
143+
private async Task ProcessCodeScanAsync(LsAnalysisResult lsAnalysisResult)
146144
{
147-
if (lspAnalysisResult.Status == "inProgress")
145+
if (lsAnalysisResult.Status == "inProgress")
148146
{
149147
var featuresSettings = await serviceProvider.TasksService.GetFeaturesSettingsAsync();
150148
serviceProvider.TasksService.FireSnykCodeScanningStartedEvent(featuresSettings);
151149
return;
152150
}
153-
if (lspAnalysisResult.Status == "error")
151+
if (lsAnalysisResult.Status == "error")
154152
{
155-
serviceProvider.TasksService.OnSnykCodeError(lspAnalysisResult.ErrorMessage);
153+
serviceProvider.TasksService.OnSnykCodeError(lsAnalysisResult.ErrorMessage);
156154
serviceProvider.TasksService.FireTaskFinished();
157155
return;
158156
}
@@ -162,16 +160,16 @@ private async Task ProcessCodeScanAsnyc(LspAnalysisResult lspAnalysisResult)
162160
serviceProvider.TasksService.FireTaskFinished();
163161
}
164162

165-
private async Task ProcessOssScanAsnyc(LspAnalysisResult lspAnalysisResult)
163+
private async Task ProcessOssScanAsync(LsAnalysisResult lsAnalysisResult)
166164
{
167-
if (lspAnalysisResult.Status == "inProgress")
165+
if (lsAnalysisResult.Status == "inProgress")
168166
{
169167
serviceProvider.TasksService.FireOssScanningStartedEvent();
170168
return;
171169
}
172-
if (lspAnalysisResult.Status == "error")
170+
if (lsAnalysisResult.Status == "error")
173171
{
174-
serviceProvider.TasksService.FireOssError(lspAnalysisResult.ErrorMessage);
172+
serviceProvider.TasksService.FireOssError(lsAnalysisResult.ErrorMessage);
175173
serviceProvider.TasksService.FireTaskFinished();
176174
return;
177175
}
@@ -181,17 +179,17 @@ private async Task ProcessOssScanAsnyc(LspAnalysisResult lspAnalysisResult)
181179
serviceProvider.TasksService.FireTaskFinished();
182180
}
183181

184-
private async Task ProcessIacScanAsnyc(LspAnalysisResult lspAnalysisResult)
182+
private async Task ProcessIacScanAsync(LsAnalysisResult lsAnalysisResult)
185183
{
186-
if (lspAnalysisResult.Status == "inProgress")
184+
if (lsAnalysisResult.Status == "inProgress")
187185
{
188186
var featuresSettings = await serviceProvider.TasksService.GetFeaturesSettingsAsync();
189187
serviceProvider.TasksService.FireIacScanningStartedEvent(featuresSettings);
190188
return;
191189
}
192-
if (lspAnalysisResult.Status == "error")
190+
if (lsAnalysisResult.Status == "error")
193191
{
194-
serviceProvider.TasksService.OnIacError(lspAnalysisResult.ErrorMessage);
192+
serviceProvider.TasksService.OnIacError(lsAnalysisResult.ErrorMessage);
195193
serviceProvider.TasksService.FireTaskFinished();
196194
return;
197195
}

Snyk.VisualStudio.Extension.2022/Service/SnykTasksService.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ public async Task ScanAsync()
229229
try
230230
{
231231
var selectedFeatures = await this.GetFeaturesSettingsAsync();
232+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
232233

233234
if (!this.serviceProvider.SolutionService.IsSolutionOpen())
234235
{
@@ -265,6 +266,8 @@ public async Task ScanAsync()
265266

266267
Assumes.Present(componentModel);
267268
var languageServerClientManager = componentModel.GetService<ILanguageClientManager>();
269+
this.SnykScanTokenSource = new CancellationTokenSource();
270+
268271
var progressWorker = new SnykProgressWorker
269272
{
270273
TasksService = this,

Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralOptionsDialogPage.cs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ public async Task OnAuthenticationFailedAsync(string errorMessage)
161161
{
162162
await this.GeneralSettingsUserControl.OnAuthenticationFailAsync(errorMessage);
163163
}
164-
165164
/// <summary>
166165
/// Gets or sets a value indicating whether organization.
167166
/// </summary>
@@ -415,7 +414,7 @@ public void Initialize(ISnykServiceProvider provider)
415414
}
416415

417416
/// <inheritdoc />
418-
public bool Authenticate()
417+
public void Authenticate()
419418
{
420419
Logger.Information("Enter Authenticate method");
421420
if (!SnykCliDownloader.IsCliFileFound(this.CliCustomPath))
@@ -427,24 +426,30 @@ public bool Authenticate()
427426
if (!LanguageClientHelper.IsLanguageServerReady())
428427
{
429428
Logger.Error("Language Server is not initialized yet.");
430-
return false;
429+
return;
431430
}
432431
if (ApiToken.IsValid())
433-
return true;
432+
return;
434433

435434
Logger.Information("Api token is invalid. Attempting to authenticate via snyk auth");
436-
ThreadHelper.JoinableTaskFactory.Run(async ()=>
435+
436+
ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
437+
{
438+
await ServiceProvider.Package.LanguageClientManager.InvokeLogout(SnykVSPackage.Instance
439+
.DisposalToken);
440+
await ServiceProvider.Package.LanguageClientManager.InvokeLogin(SnykVSPackage.Instance
441+
.DisposalToken);
442+
}).FireAndForget();
443+
444+
ThreadHelper.JoinableTaskFactory.Run(async () =>
437445
{
438-
await ServiceProvider.Package.LanguageClientManager.InvokeLogout(SnykVSPackage.Instance.DisposalToken);
439-
var token = await ServiceProvider.Package.LanguageClientManager.InvokeLogin(SnykVSPackage.Instance.DisposalToken);
440-
ApiToken = CreateAuthenticationToken(token);
446+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
447+
AuthDialogWindow.Instance.ShowDialog();
441448
});
442-
return true;
443449
}
444450
catch (Exception e)
445451
{
446452
Logger.Error(e, "Couldn't execute Invoke Login through LS.");
447-
return false;
448453
}
449454
}
450455

0 commit comments

Comments
 (0)