Skip to content

Commit

Permalink
chore: change default API endpoint (#274)
Browse files Browse the repository at this point in the history
  • Loading branch information
ShawkyZ authored Jun 12, 2024
1 parent 040ae6f commit a947c0e
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 81 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Snyk Security Changelog

## [1.1.59]

### Fixed
- Change Default API Endpoint to https://api.snyk.io.

## [1.1.58]

### Fixed
Expand Down
66 changes: 30 additions & 36 deletions Snyk.Common/Service/ApiEndpointResolver.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
namespace Snyk.Common.Service
{
using System;
using Snyk.Common.Authentication;
using Snyk.Common.Settings;
using System;
using System.Text.RegularExpressions;
using Snyk.Common.Authentication;
using Snyk.Common.Settings;

namespace Snyk.Common.Service
{
/// <summary>
/// Helper class for resolve API endpoints. It's one place for all endpoint calculations.
/// </summary>
public class ApiEndpointResolver
{
private readonly ISnykOptions options;
private const string DefaultApiEndpoint = "https://api.snyk.io";
public const string DefaultAppEndpoint = "https://app.snyk.io";

/// <summary>
/// Initializes a new instance of the <see cref="ApiEndpointResolver"/> class.
Expand Down Expand Up @@ -53,7 +56,7 @@ public string GetSnykApiEndpoint()
{
var customEndpoint = ResolveCustomEndpoint(this.options.CustomEndpoint);

var sastUrl = string.IsNullOrEmpty(customEndpoint) ? "https://snyk.io/api/" : customEndpoint;
var sastUrl = string.IsNullOrEmpty(customEndpoint) ? DefaultApiEndpoint : customEndpoint;

return !sastUrl.EndsWith("/") ? $"{sastUrl}/" : sastUrl;
}
Expand All @@ -63,54 +66,45 @@ public string GetSnykApiEndpoint()
/// </summary>
public string GetSnykCodeApiUrl()
{
if (this.IsLocalEngine())
if (IsLocalEngine())
{
return this.options.SastSettings.LocalCodeEngine.Url + "/";
return options.SastSettings.LocalCodeEngine.Url + "/";
}

var endpoint = ResolveCustomEndpoint(this.options.CustomEndpoint);
var uri = new Uri(endpoint);

var result = uri.Scheme + "://" + uri.Host.Replace("api.", "deeproxy.").Replace("app.", "deeproxy.");

if (!result.Contains("deeproxy."))
{
result = uri.Scheme + "://" + "deeproxy." + uri.Host;
}

var result = GetCustomEndpointUrlFromSnykApi(endpoint, "deeproxy");

return result + "/";
}

private bool IsSnykCodeAvailable(string endpointUrl)
{
var endpoint = ResolveCustomEndpoint(endpointUrl);
var uri = new Uri(endpoint);
return IsSaaS(uri) || IsSingleTenant(uri);
}

/// <summary>
/// Resolves the custom endpoint.
/// If the endpointUrl is null or empty, then https://snyk.io/api" will be used.
/// If the endpointUrl is null or empty, then https://api.snyk.io" will be used.
/// </summary>
private string ResolveCustomEndpoint(string endpointUrl)
{
var resolvedEndpoint = string.IsNullOrEmpty(endpointUrl)
? "https://snyk.io/api"
? DefaultApiEndpoint
: endpointUrl.RemoveTrailingSlashes().Trim().ReplaceFirst("/v1", string.Empty);
return resolvedEndpoint;
}

/// <summary>
/// Checks if the deployment type is SaaS (production or development).
/// </summary>
private bool IsSaaS(Uri uri) =>
!uri.Host.StartsWith("app") && uri.Host.EndsWith("snyk.io");

/// <summary>
/// Checks if the deployment type is Single Tenant.
/// </summary>
private bool IsSingleTenant(Uri uri) =>
uri.Host.StartsWith("app") && uri.Host.EndsWith("snyk.io");
public static string GetCustomEndpointUrlFromSnykApi(string apiEndpoint, string subdomain)
{
const string regex = @"^(ap[pi]\.)?";
if (string.IsNullOrEmpty(subdomain))
throw new ArgumentException("subdomain must have a value to calculate the result endpoint");

if (string.IsNullOrEmpty(apiEndpoint) || !Uri.IsWellFormedUriString(apiEndpoint, UriKind.Absolute))
return string.Empty;

var endpointUri = new Uri(apiEndpoint);

var host = Regex.Replace(endpointUri.Host, regex, $"{subdomain}.");
var uriBuilder = new UriBuilder(endpointUri.Scheme, host);
return uriBuilder.ToString().RemoveTrailingSlashes();
}

private bool IsLocalEngine() => this.options.SastSettings?.LocalCodeEngineEnabled ?? false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
namespace Snyk.VisualStudio.Extension.Shared.Settings
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.VisualStudio.Shell;
using Serilog;
using Snyk.Common;
using Snyk.Common.Authentication;
using Snyk.Common.Service;
using Snyk.Common.Settings;
using Snyk.VisualStudio.Extension.Shared.Service;
using Snyk.VisualStudio.Extension.Shared.UI.Notifications;

namespace Snyk.VisualStudio.Extension.Shared.Settings
{
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.VisualStudio.Shell;
using Serilog;
using Snyk.Common;
using Snyk.Common.Authentication;
using Snyk.Common.Service;
using Snyk.Common.Settings;
using Snyk.VisualStudio.Extension.Shared.Service;
using Snyk.VisualStudio.Extension.Shared.UI.Notifications;

/// <summary>
/// Snyk general settings page.
/// </summary>
[Guid("d45468c1-33d2-4dca-9780-68abaedf95e7")]
[ComVisible(true)]
public class SnykGeneralOptionsDialogPage : DialogPage, ISnykOptions
{

public String Application { get; set; }
public String ApplicationVersion { get; set; }
public String IntegrationName { get; } = SnykExtension.IntegrationName;
public String IntegrationVersion { get; } = SnykExtension.Version;
public String IntegrationEnvironment { get; set; }
public String IntegrationEnvironmentVersion { get; set;}

public string Application { get; set; }
public string ApplicationVersion { get; set; }
public string IntegrationName { get; } = SnykExtension.IntegrationName;
public string IntegrationVersion { get; } = SnykExtension.Version;
public string IntegrationEnvironment { get; set; }
public string IntegrationEnvironmentVersion { get; set;}

private ISnykServiceProvider serviceProvider;

private SnykUserStorageSettingsService userStorageSettingsService;
Expand Down Expand Up @@ -117,9 +116,9 @@ public bool IsFedramp()
/// <returns></returns>
public bool IsAnalyticsPermitted()
{
var endpointUri = new Uri(this.GetBaseAppURL());
var endpointUri = new Uri(this.GetBaseAppUrl());

string[] permittedHosts = new string[] { "app.snyk.io", "app.us.snyk.io" };
var permittedHosts = new string[] { "app.snyk.io", "app.us.snyk.io" };
return permittedHosts.Contains(endpointUri.Host.ToLower());
}

Expand Down Expand Up @@ -153,7 +152,7 @@ public string CustomEndpoint
}

/// <inheritdoc/>
public string SnykCodeSettingsUrl => $"{this.GetBaseAppURL()}/manage/snyk-code";
public string SnykCodeSettingsUrl => $"{this.GetBaseAppUrl()}/manage/snyk-code";

public SastSettings SastSettings
{
Expand Down Expand Up @@ -416,23 +415,14 @@ public bool Authenticate()

private void FireSettingsChangedEvent() => this.SettingsChanged?.Invoke(this, new SnykSettingsChangedEventArgs());

private string GetBaseAppURL()
private string GetBaseAppUrl()
{
var endpoint = this.customEndpoint.IsNullOrEmpty() ? "https://app.snyk.io" : this.customEndpoint.RemoveTrailingSlashes();
Uri uri = new Uri(endpoint);
if (string.IsNullOrEmpty(customEndpoint))
return ApiEndpointResolver.DefaultAppEndpoint;

if (!uri.Host.StartsWith("app") && (uri.Host.EndsWith("snyk.io") || uri.Host.EndsWith("snykgov.io")))
{
return endpoint.Replace("https://", "https://app.").RemoveFromEnd("/api");
}
else if (uri.Host.StartsWith("app") && (uri.Host.EndsWith("snyk.io") || uri.Host.EndsWith("snykgov.io")))
{
return endpoint.RemoveFromEnd("/api");
}
else
{
return "https://app.snyk.io";
}
var result = ApiEndpointResolver.GetCustomEndpointUrlFromSnykApi(customEndpoint, "app");

return string.IsNullOrEmpty(result) ? ApiEndpointResolver.DefaultAppEndpoint : result;
}

private void ThrowFileNotFoundException()
Expand Down
13 changes: 11 additions & 2 deletions Snyk.VisualStudio.Extension.Tests/GeneralOptionsDialogPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,18 @@ public void ApiEndpointChanged_InvalidatesCliToken()
}

[Theory]
[InlineData("https://app.snyk.io/api", true)]
[InlineData("https://snyk.io/api", true)]
[InlineData("https://app.snyk.io/api", true)]
[InlineData("https://app.us.snyk.io/api", true)]
[InlineData("https://app.eu.snyk.io/api", false)]
[InlineData("https://app.au.snyk.io/api", false)]
[InlineData("https://app.snykgov.io/api", false)]

[InlineData("https://api.snyk.io", true)]
[InlineData("https://api.us.snyk.io", true)]
[InlineData("https://api.eu.snyk.io", false)]
[InlineData("https://api.au.snyk.io", false)]
[InlineData("https://api.snykgov.io", false)]
public void IsAnalyticsPermitted(string endpoint, bool expected)
{
var optionsDialogPage = new SnykGeneralOptionsDialogPage();
Expand All @@ -53,7 +59,10 @@ public void IsAnalyticsPermitted(string endpoint, bool expected)
[InlineData("https://app.snyk.io/api", "https://app.snyk.io/manage/snyk-code")]
[InlineData("https://app.eu.snyk.io/api", "https://app.eu.snyk.io/manage/snyk-code")]
[InlineData("https://app.snykgov.io/api", "https://app.snykgov.io/manage/snyk-code")]
[InlineData("https://example.org", "https://app.snyk.io/manage/snyk-code")]
[InlineData("https://api.snyk.io", "https://app.snyk.io/manage/snyk-code")]
[InlineData("https://api.snyk.io/", "https://app.snyk.io/manage/snyk-code")]
[InlineData("https://api.snykgov.io", "https://app.snykgov.io/manage/snyk-code")]
[InlineData("https://api.eu.snyk.io", "https://app.eu.snyk.io/manage/snyk-code")]
public void SnykCodeSettingsUrl(string endpoint, string expected)
{
var optionsDialogPage = new SnykGeneralOptionsDialogPage();
Expand Down

0 comments on commit a947c0e

Please sign in to comment.