From a89c80ed3c03a37df13e61b86d2a0b94edb3e641 Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sun, 6 Aug 2023 13:30:18 -0700 Subject: [PATCH 1/8] Updated Authorization.cs namespace and added the claim value. --- Newsbot.Collector.Domain/Consts/Authorization.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Newsbot.Collector.Domain/Consts/Authorization.cs b/Newsbot.Collector.Domain/Consts/Authorization.cs index 89136a1..61190b7 100644 --- a/Newsbot.Collector.Domain/Consts/Authorization.cs +++ b/Newsbot.Collector.Domain/Consts/Authorization.cs @@ -1,12 +1,13 @@ -namespace Newsbot.Collector.Api.Domain; +namespace Newsbot.Collector.Api.Domain.Consts; public static class Authorization { public const string AdministratorPolicy = "Administrator"; + public const string AdministratorsRole = AdministratorPolicy; public const string AdministratorClaim = "administrator"; - public const string AdministratorsRole = AdministratorPolicy; public const string UserPolicy = "User"; public const string UsersRole = UserPolicy; + public const string UserClaim = "user"; } \ No newline at end of file From bd05c45e6e88982fdac72f57fa547bad02122e58 Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sun, 6 Aug 2023 13:31:00 -0700 Subject: [PATCH 2/8] Updated startup to reflect the correct consts and roles --- Newsbot.Collector.Api/Startup/DatabaseStartup.cs | 2 +- Newsbot.Collector.Api/Startup/IdentityStartup.cs | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Newsbot.Collector.Api/Startup/DatabaseStartup.cs b/Newsbot.Collector.Api/Startup/DatabaseStartup.cs index 1c2ca1b..9d744dd 100644 --- a/Newsbot.Collector.Api/Startup/DatabaseStartup.cs +++ b/Newsbot.Collector.Api/Startup/DatabaseStartup.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; -using Newsbot.Collector.Api.Domain; +using Newsbot.Collector.Api.Domain.Consts; using Newsbot.Collector.Database; using Newsbot.Collector.Database.Repositories; using Newsbot.Collector.Domain.Interfaces; diff --git a/Newsbot.Collector.Api/Startup/IdentityStartup.cs b/Newsbot.Collector.Api/Startup/IdentityStartup.cs index f233b6d..db74be1 100644 --- a/Newsbot.Collector.Api/Startup/IdentityStartup.cs +++ b/Newsbot.Collector.Api/Startup/IdentityStartup.cs @@ -1,7 +1,7 @@ using System.Text; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; -using Newsbot.Collector.Api.Domain; +using Newsbot.Collector.Api.Domain.Consts; using Newsbot.Collector.Domain.Models.Config; namespace Newsbot.Collector.Api.Startup; @@ -44,7 +44,9 @@ public static class IdentityStartup services.AddAuthorization(options => { options.AddPolicy(Authorization.AdministratorPolicy, - b => b.RequireClaim(Authorization.AdministratorClaim, "true")); + b => b.RequireRole(Authorization.AdministratorsRole, "true")); + options.AddPolicy(Authorization.UserPolicy, + b => b.RequireRole(Authorization.UsersRole, "true")); }); } } \ No newline at end of file From 3e1a8e841924eb65c8589a0bcc65f35624e93068 Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sun, 6 Aug 2023 13:32:35 -0700 Subject: [PATCH 3/8] Using updates --- Newsbot.Collector.Api/Controllers/v1/CodeProjectController.cs | 2 +- Newsbot.Collector.Api/Controllers/v1/IdentityController.cs | 2 +- Newsbot.Collector.Api/Controllers/v1/RssController.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Newsbot.Collector.Api/Controllers/v1/CodeProjectController.cs b/Newsbot.Collector.Api/Controllers/v1/CodeProjectController.cs index d33cba1..5937767 100644 --- a/Newsbot.Collector.Api/Controllers/v1/CodeProjectController.cs +++ b/Newsbot.Collector.Api/Controllers/v1/CodeProjectController.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; -using Newsbot.Collector.Api.Domain; +using Newsbot.Collector.Api.Domain.Consts; using Newsbot.Collector.Domain.Models.Config; using Newsbot.Collector.Services.Jobs; diff --git a/Newsbot.Collector.Api/Controllers/v1/IdentityController.cs b/Newsbot.Collector.Api/Controllers/v1/IdentityController.cs index b260be5..aac302c 100644 --- a/Newsbot.Collector.Api/Controllers/v1/IdentityController.cs +++ b/Newsbot.Collector.Api/Controllers/v1/IdentityController.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Newsbot.Collector.Api.Domain; +using Newsbot.Collector.Api.Domain.Consts; using Newsbot.Collector.Domain.Requests; using Newsbot.Collector.Domain.Response; using Newsbot.Collector.Domain.Results; diff --git a/Newsbot.Collector.Api/Controllers/v1/RssController.cs b/Newsbot.Collector.Api/Controllers/v1/RssController.cs index 9b31637..bda6e84 100644 --- a/Newsbot.Collector.Api/Controllers/v1/RssController.cs +++ b/Newsbot.Collector.Api/Controllers/v1/RssController.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; -using Newsbot.Collector.Api.Domain; +using Newsbot.Collector.Api.Domain.Consts; using Newsbot.Collector.Domain.Models.Config; using Newsbot.Collector.Domain.Models.Config.Sources; using Newsbot.Collector.Services.Jobs; From 22e9638f88dc9043ab51d35df71c8a853d2a5aa4 Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sun, 6 Aug 2023 13:33:45 -0700 Subject: [PATCH 4/8] namespace updated and using --- Newsbot.Collector.Api/Controllers/v1/SourcesController.cs | 7 ++----- Newsbot.Collector.Api/Controllers/v1/YoutubeController.cs | 3 +-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Newsbot.Collector.Api/Controllers/v1/SourcesController.cs b/Newsbot.Collector.Api/Controllers/v1/SourcesController.cs index 8bd4b27..5725b0f 100644 --- a/Newsbot.Collector.Api/Controllers/v1/SourcesController.cs +++ b/Newsbot.Collector.Api/Controllers/v1/SourcesController.cs @@ -1,17 +1,14 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Options; -using Newsbot.Collector.Api.Domain; -using Newsbot.Collector.Database.Repositories; +using Newsbot.Collector.Api.Domain.Consts; using Newsbot.Collector.Domain.Consts; using Newsbot.Collector.Domain.Dto; using Newsbot.Collector.Domain.Entities; using Newsbot.Collector.Domain.Interfaces; -using Newsbot.Collector.Domain.Models; using Newsbot.Collector.Services.HtmlParser; -namespace Newsbot.Collector.Api.Controllers; +namespace Newsbot.Collector.Api.Controllers.v1; [ApiController] [Route("api/sources")] diff --git a/Newsbot.Collector.Api/Controllers/v1/YoutubeController.cs b/Newsbot.Collector.Api/Controllers/v1/YoutubeController.cs index 66ea171..1c2c8ec 100644 --- a/Newsbot.Collector.Api/Controllers/v1/YoutubeController.cs +++ b/Newsbot.Collector.Api/Controllers/v1/YoutubeController.cs @@ -3,11 +3,10 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; -using Newsbot.Collector.Api.Domain; +using Newsbot.Collector.Api.Domain.Consts; using Newsbot.Collector.Domain.Models.Config; using Newsbot.Collector.Domain.Models.Config.Sources; using Newsbot.Collector.Services.Jobs; -using ILogger = Grpc.Core.Logging.ILogger; namespace Newsbot.Collector.Api.Controllers.v1; From 338edf8d4e213b0020596b9e80c3a340d378972e Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sun, 6 Aug 2023 13:34:54 -0700 Subject: [PATCH 5/8] Added TotalByTypeAsync to see if we need to pull multiple pages --- .../Repositories/SourcesTable.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Newsbot.Collector.Database/Repositories/SourcesTable.cs b/Newsbot.Collector.Database/Repositories/SourcesTable.cs index 8340de0..829d35e 100644 --- a/Newsbot.Collector.Database/Repositories/SourcesTable.cs +++ b/Newsbot.Collector.Database/Repositories/SourcesTable.cs @@ -1,17 +1,13 @@ -using System.Data; -using Dapper; -using Microsoft.Extensions.Configuration; +using Microsoft.EntityFrameworkCore; using Newsbot.Collector.Domain.Entities; using Newsbot.Collector.Domain.Interfaces; -using Newsbot.Collector.Domain.Models; -using Npgsql; namespace Newsbot.Collector.Database.Repositories; public class SourcesTable : ISourcesRepository { //private readonly string _connectionString; - private DatabaseContext _context; + private readonly DatabaseContext _context; public SourcesTable(string connectionString) { @@ -114,6 +110,14 @@ public class SourcesTable : ISourcesRepository return res; } + public async Task TotalByTypeAsync(string type) + { + var res = await _context.Sources + .Where(f => f.Type == type ) + .CountAsync(); + return res; + } + public int Disable(Guid id) { //using var context = new DatabaseContext(_connectionString); From 97fc34481cb639301fb00183f1fea56dbbb07cba Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sun, 6 Aug 2023 13:35:26 -0700 Subject: [PATCH 6/8] ISourcesRepository.cs updated to return total rows --- Newsbot.Collector.Domain/Interfaces/ISourcesRepository.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Newsbot.Collector.Domain/Interfaces/ISourcesRepository.cs b/Newsbot.Collector.Domain/Interfaces/ISourcesRepository.cs index 9c4c843..8276b1d 100644 --- a/Newsbot.Collector.Domain/Interfaces/ISourcesRepository.cs +++ b/Newsbot.Collector.Domain/Interfaces/ISourcesRepository.cs @@ -14,6 +14,7 @@ public interface ISourcesRepository public List List(int page, int count); public List ListBySource(string source,int page, int limit); public List ListByType(string type,int page, int limit = 25); + public Task TotalByTypeAsync(string type); public int Disable(Guid id); public int Enable(Guid id); public void Delete(Guid id); From ff272ab1467af511a1975ee923c135199444fd0e Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sun, 6 Aug 2023 13:37:36 -0700 Subject: [PATCH 7/8] Added user role on creation. Updated Unixtime call. Updated how to add a role. Roles are now added to the claim --- Newsbot.Collector.Services/IdentityService.cs | 55 ++++++++++++++----- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/Newsbot.Collector.Services/IdentityService.cs b/Newsbot.Collector.Services/IdentityService.cs index 3d587de..6df5bdc 100644 --- a/Newsbot.Collector.Services/IdentityService.cs +++ b/Newsbot.Collector.Services/IdentityService.cs @@ -3,6 +3,7 @@ using System.Security.Claims; using System.Text; using Microsoft.AspNetCore.Identity; using Microsoft.IdentityModel.Tokens; +using Newsbot.Collector.Api.Domain.Consts; using Newsbot.Collector.Domain.Results; using Newsbot.Collector.Domain.Entities; using Newsbot.Collector.Domain.Interfaces; @@ -16,22 +17,24 @@ public interface IIdentityService AuthenticationResult Register(string email, string password); AuthenticationResult Login(string email, string password); AuthenticationResult RefreshToken(string token, string refreshToken); - void AddRole(string roleName, string userId); + void AddRole(string name, string userId); } public class IdentityService : IIdentityService { private readonly UserManager _userManager; + private readonly RoleManager _roleManager; private readonly JwtSettings _jwtSettings; private readonly TokenValidationParameters _tokenValidationParameters; private readonly IRefreshTokenRepository _refreshTokenRepository; - public IdentityService(UserManager userManager, JwtSettings jwtSettings, TokenValidationParameters tokenValidationParameters, IRefreshTokenRepository refreshTokenRepository) + public IdentityService(UserManager userManager, JwtSettings jwtSettings, TokenValidationParameters tokenValidationParameters, IRefreshTokenRepository refreshTokenRepository, RoleManager roleManager) { _userManager = userManager; _jwtSettings = jwtSettings; _tokenValidationParameters = tokenValidationParameters; _refreshTokenRepository = refreshTokenRepository; + _roleManager = roleManager; } public AuthenticationResult Register(string email, string password) @@ -63,8 +66,11 @@ public class IdentityService : IIdentityService ErrorMessage = new List(createdUser.Result.Errors.Select(x => x.Description)) }; } - - return GenerateJwtToken(newUser); + + var addRole = _userManager.AddToRoleAsync(newUser, Authorization.UsersRole); + addRole.Wait(); + + return GenerateJwtToken(newUser); } public AuthenticationResult Login(string email, string password) @@ -109,8 +115,9 @@ public class IdentityService : IIdentityService var expiryDateUnix = long.Parse(validatedToken.Claims.Single(x => x.Type == JwtRegisteredClaimNames.Exp).Value); // generate the unix epoc, add expiry time - var expiryDateTimeUtc = new DateTime(1970, 0, 0, 0, 0, 0, DateTimeKind.Utc) - .AddSeconds(expiryDateUnix); + + var unixTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + var expiryDateTimeUtc = unixTime.AddSeconds(expiryDateUnix); // if it expires in the future if (expiryDateTimeUtc > DateTime.Now) @@ -179,7 +186,7 @@ public class IdentityService : IIdentityService return GenerateJwtToken(user.Result); } - public void AddRole(string roleName, string userId) + public void AddRole(string name, string userId) { var user = _userManager.FindByIdAsync(userId); user.Wait(); @@ -189,7 +196,14 @@ public class IdentityService : IIdentityService throw new Exception("User was not found"); } - _userManager.AddToRoleAsync(user.Result, roleName); + if (!name.Equals(Authorization.AdministratorClaim) + || !name.Equals(Authorization.UserClaim)) + { + throw new Exception("Invalid role"); + } + + var addRole = _userManager.AddToRoleAsync(user.Result, name); + addRole.Wait(); } private ClaimsPrincipal? CheckTokenSigner(string token) @@ -221,15 +235,25 @@ public class IdentityService : IIdentityService { var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(_jwtSettings.Secret ?? ""); + + var claims = new List + { + new Claim(JwtRegisteredClaimNames.Sub, user.Email ?? ""), + new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), + new Claim(JwtRegisteredClaimNames.Email, user.Email ?? ""), + new Claim("id", user.Id) + }; + + var userRoles = _userManager.GetRolesAsync(user); + userRoles.Wait(); + foreach (var role in userRoles.Result) + { + claims.Add(new Claim(ClaimTypes.Role, role)); + } + var tokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(new[] - { - new Claim(JwtRegisteredClaimNames.Sub, user.Email ?? ""), - new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), - new Claim(JwtRegisteredClaimNames.Email, user.Email ?? ""), - new Claim("id", user.Id) - }), + Subject = new ClaimsIdentity(claims), Expires = DateTime.UtcNow.AddHours(3), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) @@ -239,6 +263,7 @@ public class IdentityService : IIdentityService var refreshToken = new RefreshTokenEntity { + Token = token.Id, JwtId = token.Id, UserId = user.Id, CreatedDate = DateTime.UtcNow, From bb6d36cfd85a870a2538c0526d2fcdc27b663123 Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sun, 6 Aug 2023 13:37:59 -0700 Subject: [PATCH 8/8] Updated article to use UTC time --- Newsbot.Collector.Services/Jobs/CodeProjectWatcherJob.cs | 2 +- Newsbot.Collector.Services/Jobs/RssWatcherJob.cs | 2 +- Newsbot.Collector.Services/Jobs/YoutubeWatcherJob.cs | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Newsbot.Collector.Services/Jobs/CodeProjectWatcherJob.cs b/Newsbot.Collector.Services/Jobs/CodeProjectWatcherJob.cs index 1551cbd..3e43f00 100644 --- a/Newsbot.Collector.Services/Jobs/CodeProjectWatcherJob.cs +++ b/Newsbot.Collector.Services/Jobs/CodeProjectWatcherJob.cs @@ -181,7 +181,7 @@ public class CodeProjectWatcherJob Tags = source.Tags, Title = item.Title.Text, Url = itemUrl, - PubDate = item.LastUpdatedTime.DateTime, + PubDate = item.LastUpdatedTime.DateTime.ToUniversalTime(), Thumbnail = parser.Data.Header.Image, Description = item.Title.Text, CodeIsRelease = isRelease, diff --git a/Newsbot.Collector.Services/Jobs/RssWatcherJob.cs b/Newsbot.Collector.Services/Jobs/RssWatcherJob.cs index be35362..c4831ad 100644 --- a/Newsbot.Collector.Services/Jobs/RssWatcherJob.cs +++ b/Newsbot.Collector.Services/Jobs/RssWatcherJob.cs @@ -105,7 +105,7 @@ public class RssWatcherJob Title = post.Title.Text, Tags = FetchTags(post), Url = articleUrl, - PubDate = post.PublishDate.DateTime, + PubDate = post.PublishDate.DateTime.ToUniversalTime(), Thumbnail = meta.Data.Header.Image, Description = meta.Data.Header.Description, SourceId = sourceId diff --git a/Newsbot.Collector.Services/Jobs/YoutubeWatcherJob.cs b/Newsbot.Collector.Services/Jobs/YoutubeWatcherJob.cs index 325847c..5fc5077 100644 --- a/Newsbot.Collector.Services/Jobs/YoutubeWatcherJob.cs +++ b/Newsbot.Collector.Services/Jobs/YoutubeWatcherJob.cs @@ -56,7 +56,9 @@ public class YoutubeWatcherJob private void Execute() { - var sources = _source.ListByType(SourceTypes.YouTube, 100); + var totalSources = _source.TotalByTypeAsync(SourceTypes.YouTube); + + var sources = _source.ListByType(SourceTypes.YouTube, 0); foreach (var source in sources) { @@ -165,7 +167,7 @@ public class YoutubeWatcherJob Title = post.Title.Text, Tags = FetchTags(post), Url = articleUrl, - PubDate = post.PublishDate.DateTime, + PubDate = post.PublishDate.DateTime.ToUniversalTime(), Thumbnail = videoDetails.Data.Header.Image, Description = videoDetails.Data.Header.Description, SourceId = sourceId,