diff --git a/Notesnook.API/Controllers/MonographsController.cs b/Notesnook.API/Controllers/MonographsController.cs
index 70be5ab..8fc3708 100644
--- a/Notesnook.API/Controllers/MonographsController.cs
+++ b/Notesnook.API/Controllers/MonographsController.cs
@@ -33,6 +33,7 @@ using Notesnook.API.Authorization;
using Notesnook.API.Models;
using Notesnook.API.Services;
using Streetwriters.Common;
+using Streetwriters.Common.Interfaces;
using Streetwriters.Common.Messages;
using Streetwriters.Data.Interfaces;
using Streetwriters.Data.Repositories;
@@ -46,12 +47,14 @@ namespace Notesnook.API.Controllers
{
const string SVG_PIXEL = "";
private Repository Monographs { get; set; }
+ private readonly IURLAnalyzer urlAnalyzer;
private readonly IUnitOfWork unit;
private const int MAX_DOC_SIZE = 15 * 1024 * 1024;
- public MonographsController(Repository monographs, IUnitOfWork unitOfWork)
+ public MonographsController(Repository monographs, IUnitOfWork unitOfWork, IURLAnalyzer analyzer)
{
Monographs = monographs;
unit = unitOfWork;
+ urlAnalyzer = analyzer;
}
private static FilterDefinition CreateMonographFilter(string userId, Monograph monograph)
@@ -338,6 +341,20 @@ namespace Notesnook.API.Controllers
}
return document.ToHtml();
}
+
+ if (ProUserRequirement.IsUserPro(User))
+ {
+ var config = Configuration.Default.WithDefaultLoader();
+ var context = BrowsingContext.New(config);
+ var document = await context.OpenAsync(r => r.Content(content));
+ foreach (var element in document.QuerySelectorAll("a"))
+ {
+ var href = element.GetAttribute("href");
+ if (string.IsNullOrEmpty(href)) continue;
+ if (!await urlAnalyzer.IsURLSafeAsync(href)) element.RemoveAttribute("href");
+ }
+ return document.ToHtml();
+ }
return content;
}
}
diff --git a/Notesnook.API/Startup.cs b/Notesnook.API/Startup.cs
index e560f0d..ff7d37d 100644
--- a/Notesnook.API/Startup.cs
+++ b/Notesnook.API/Startup.cs
@@ -57,8 +57,10 @@ using OpenTelemetry.Resources;
using Quartz;
using Streetwriters.Common;
using Streetwriters.Common.Extensions;
+using Streetwriters.Common.Interfaces;
using Streetwriters.Common.Messages;
using Streetwriters.Common.Models;
+using Streetwriters.Common.Services;
using Streetwriters.Data;
using Streetwriters.Data.DbContexts;
using Streetwriters.Data.Interfaces;
@@ -185,6 +187,7 @@ namespace Notesnook.API
services.AddScoped();
services.AddScoped();
services.AddScoped();
+ services.AddScoped();
services.AddControllers();
diff --git a/Streetwriters.Common/Constants.cs b/Streetwriters.Common/Constants.cs
index 3631a54..2f87be0 100644
--- a/Streetwriters.Common/Constants.cs
+++ b/Streetwriters.Common/Constants.cs
@@ -70,6 +70,7 @@ namespace Streetwriters.Common
public static string SSE_CERT_KEY_PATH => Environment.GetEnvironmentVariable("SSE_CERT_KEY_PATH");
// internal
+ public static string WEBRISK_API_URI => Environment.GetEnvironmentVariable("WEBRISK_API_URI");
public static string MONGODB_CONNECTION_STRING => Environment.GetEnvironmentVariable("MONGODB_CONNECTION_STRING");
public static string MONGODB_DATABASE_NAME => Environment.GetEnvironmentVariable("MONGODB_DATABASE_NAME");
public static int SUBSCRIPTIONS_SERVER_PORT => int.Parse(Environment.GetEnvironmentVariable("SUBSCRIPTIONS_SERVER_PORT") ?? "80");
diff --git a/Streetwriters.Common/Interfaces/IURLAnalyzer.cs b/Streetwriters.Common/Interfaces/IURLAnalyzer.cs
new file mode 100644
index 0000000..5c39663
--- /dev/null
+++ b/Streetwriters.Common/Interfaces/IURLAnalyzer.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MimeKit;
+using MimeKit.Cryptography;
+using Streetwriters.Common.Models;
+
+namespace Streetwriters.Common.Interfaces
+{
+ public interface IURLAnalyzer
+ {
+ Task IsURLSafeAsync(string uri);
+ }
+}
diff --git a/Streetwriters.Common/Services/URLAnalyzer.cs b/Streetwriters.Common/Services/URLAnalyzer.cs
new file mode 100644
index 0000000..496d958
--- /dev/null
+++ b/Streetwriters.Common/Services/URLAnalyzer.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Threading.Tasks;
+using Streetwriters.Common.Interfaces;
+
+namespace Streetwriters.Common.Services
+{
+ struct Threat
+ {
+ public string[]? ThreatTypes { get; set; }
+ }
+ struct WebRiskAPIResponse
+ {
+ public Threat Threat { get; set; }
+ }
+
+ public class URLAnalyzer : IURLAnalyzer, IDisposable
+ {
+ private readonly HttpClient httpClient = new();
+
+ public async Task IsURLSafeAsync(string uri)
+ {
+ if (string.IsNullOrEmpty(Constants.WEBRISK_API_URI)) return true;
+ var response = await httpClient.PostAsJsonAsync(Constants.WEBRISK_API_URI, new { uri });
+ if (!response.IsSuccessStatusCode) return true;
+ var json = await response.Content.ReadFromJsonAsync();
+ return json.Threat.ThreatTypes == null || json.Threat.ThreatTypes.Length == 0;
+ }
+
+ void IDisposable.Dispose()
+ {
+ httpClient.Dispose();
+ }
+ }
+}
diff --git a/Streetwriters.Common/Streetwriters.Common.csproj b/Streetwriters.Common/Streetwriters.Common.csproj
index 0399971..78aa4d5 100644
--- a/Streetwriters.Common/Streetwriters.Common.csproj
+++ b/Streetwriters.Common/Streetwriters.Common.csproj
@@ -2,6 +2,7 @@
net8.0
+ enable