Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented API to get security bulletins #13

Merged
merged 1 commit into from
Feb 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions Controllers/SecurityController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// MIT License
// Copyright DNN Community

using Dnn.Modules.SecurityCenter.Services;
using DotNetNuke.Web.Api;
using System;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

namespace Dnn.Modules.SecurityCenter.Controllers
{
/// <summary>
/// Provides information about DNN security services.
/// </summary>
public class SecurityController : ModuleApiController
{
private readonly ISecurityService securityService;

/// <summary>
/// Initializes a new instance of the <see cref="SecurityController"/> class.
/// </summary>
/// <param name="securityService">Provides access to DNN security bulletins service.</param>
public SecurityController(ISecurityService securityService)
{
this.securityService = securityService;
}

/// <summary>
/// Gets all the DNN security bulletins.
/// </summary>
/// <param name="versionString">The version for which to get the security bulletins for in the format 090202 for v9.9.2.</param>
/// <returns>A list of DNN security bulletins.</returns>
[ValidateAntiForgeryToken]
[HttpGet]
[DnnModuleAuthorize(AccessLevel = DotNetNuke.Security.SecurityAccessLevel.View)]
public async Task<IHttpActionResult> GetSecurityBulletins(string versionString)
{
try
{
var viewModel = await this.securityService.GetAllSecurityBulletinsAsync(versionString);
return this.Ok(viewModel);
}
catch (HttpException)
{
return this.InternalServerError(new Exception("The update service is currently not available."));
throw;
}
}
}
}
5 changes: 5 additions & 0 deletions Module.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
Expand All @@ -55,6 +56,7 @@
<Compile Include="Common\Globals.cs" />
<Compile Include="Common\Extensions\IQueryableExtensions.cs" />
<Compile Include="Controllers\LocalizationController.cs" />
<Compile Include="Controllers\SecurityController.cs" />
<Compile Include="DTO\GetItemsPageDTO.cs" />
<Compile Include="Controllers\ValidateModelAttribute.cs" />
<Compile Include="Data\Entities\BaseEntity.cs" />
Expand All @@ -72,15 +74,18 @@
<Compile Include="Controllers\ModuleExceptionFilterAttribute.cs" />
<Compile Include="Controllers\ServiceRouteMapper.cs" />
<Compile Include="Services\ILoggingService.cs" />
<Compile Include="Services\ISecurityService.cs" />
<Compile Include="Services\LoggingService.cs" />
<Compile Include="Services\IItemService.cs" />
<Compile Include="Services\ILocalizationService.cs" />
<Compile Include="Services\ItemService.cs" />
<Compile Include="Services\LocalizationService.cs" />
<Compile Include="Services\SecurityService.cs" />
<Compile Include="Startup.cs" />
<Compile Include="ViewModels\ItemsPageViewModel.cs" />
<Compile Include="ViewModels\ItemViewModel.cs" />
<Compile Include="ViewModels\LocalizationViewModel.cs" />
<Compile Include="ViewModels\SecurityBulletinsViewModel.cs" />
<Resource Include=".gitignore" />
<Resource Include="resources\images\module-icon.png" />
<Resource Include="resources\views\view.html" />
Expand Down
21 changes: 21 additions & 0 deletions Services/ISecurityService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// MIT License
// Copyright DNN Community

using Dnn.Modules.SecurityCenter.ViewModels;
using System.Threading.Tasks;

namespace Dnn.Modules.SecurityCenter.Services
{
/// <summary>
/// Provides access to the DNN security service at dnnplatform.io.
/// </summary>
public interface ISecurityService
{
/// <summary>
/// Gets a list of all security bulletins that apply for a given version.
/// </summary>
/// <param name="versionString">A string representation of a DNN version in the format 090202 for v9.2.2.</param>
/// <returns><see cref="SecurityBulletinsViewModel"/>.</returns>
Task<SecurityBulletinsViewModel> GetAllSecurityBulletinsAsync(string versionString);
}
}
53 changes: 53 additions & 0 deletions Services/SecurityService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// MIT License
// Copyright DNN Community

using Dnn.Modules.SecurityCenter.ViewModels;
using DotNetNuke.Common.Utilities;
using System;
using System.Linq;
using System.ServiceModel.Syndication;
using System.Threading.Tasks;
using System.Xml;

namespace Dnn.Modules.SecurityCenter.Services
{
/// <summary>
/// Provides access to the DNN security service at dnnplatform.io.
/// </summary>
internal class SecurityService : ISecurityService
{
/// <inheritdoc/>
public async Task<SecurityBulletinsViewModel> GetAllSecurityBulletinsAsync(string versionString)
{
return await Task.Run(() =>
{
var cacheKey = "Dnn.Security_SecurityBelletinsViewModel";
var cached = DataCache.GetCache<SecurityBulletinsViewModel>(cacheKey);
if (cached is null)
{
XmlReader reader = XmlReader.Create($"https://dnnplatform.io/security.aspx?type=Framework&name=DNNCorp.CE&version={versionString}");
var feed = SyndicationFeed.Load(reader);

var viewModel = new SecurityBulletinsViewModel
{
Bulletins = feed.Items.Select(item => new SecurityBulletinsViewModel.Bulletin
{
Description = item.Summary.Text,
Link = item.Links.FirstOrDefault().Uri.ToString(),
PublicationDateUtc = item.PublishDate.UtcDateTime,
Title = item.Title.Text,
}),
Description = feed.Description.Text,
Link = feed.Links.FirstOrDefault().Uri.ToString(),
Title = feed.Title.Text,
};

DataCache.SetCache(cacheKey, viewModel, DateTime.Now.AddHours(1));
return viewModel;
}

return cached;
});
}
}
}
1 change: 1 addition & 0 deletions Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddScoped<IItemService>(provider => new ItemService(provider.GetService<IRepository<Item>>()));
services.AddScoped<ILoggingService, LoggingService>();
services.AddScoped<ILocalizationService, LocalizationService>();
services.AddSingleton<ISecurityService, SecurityService>();
}
}
}
60 changes: 60 additions & 0 deletions ViewModels/SecurityBulletinsViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// MIT License
// Copyright DNN Community

using System;
using System.Collections.Generic;

namespace Dnn.Modules.SecurityCenter.ViewModels
{
/// <summary>
/// A viewmodel that represents DNN Security Bulletins.
/// </summary>
public class SecurityBulletinsViewModel
{
/// <summary>
/// Gets or sets the title of the RSS feed.
/// </summary>
public string Title { get; set; }

/// <summary>
/// Gets or sets the url to download DNN Platform.
/// </summary>
public string Link { get; set; }

/// <summary>
/// Gets or sets the RSS feed description.
/// </summary>
public string Description { get; set; }

/// <summary>
/// Gets or sets the list of security bulletins.
/// </summary>
public IEnumerable<Bulletin> Bulletins { get; set; }

/// <summary>
/// Represents a single DNN Security Bulletin.
/// </summary>
public class Bulletin
{
/// <summary>
/// Gets or sets a link to the detailed security bulletin.
/// </summary>
public string Link { get; set; }

/// <summary>
/// Gets or sets the title of the bulletin.
/// </summary>
public string Title { get; set; }

/// <summary>
/// Gets or sets the short description of the bulletin.
/// </summary>
public string Description { get; set; }

/// <summary>
/// Gets or sets a string representing the date of announcement.
/// </summary>
public DateTime PublicationDateUtc { get; set; }
}
}
}