* .NET 8 migration

* Fixed bugs with song management

* More cleanup and making some constants

* Updated yml

* Clean up

Removing comments, some cleanup, and moving the startup code into Program.cs

* Removing comments

* Fixed song deletion issue

* Added functionality to delete song directories

* Updated README
This commit was merged in pull request #89.
This commit is contained in:
Kun Deng
2024-06-15 12:17:12 -04:00
committed by GitHub
parent ececcb5ba3
commit 23c50de468
22 changed files with 182 additions and 454 deletions
+1
View File
@@ -47,6 +47,7 @@ public class CoverArtManager : BaseManager
{
_logger.Info("Attempting to delete cover art from the database");
_coverArtContext.Attach(coverArt);
_coverArtContext.Remove(coverArt);
_coverArtContext.SaveChanges();
}
+9 -13
View File
@@ -145,7 +145,7 @@ public class SongManager : BaseManager
{
try
{
if (DeleteSongFromFilesystem(song))
if (DeleteSongFromFilesystem(song, true))
{
_logger.Error("Failed to delete the song");
@@ -158,8 +158,8 @@ public class SongManager : BaseManager
var coverArt = coverMgr.GetCoverArt(song);
coverMgr.DeleteCoverArt(coverArt);
coverMgr.DeleteCoverArtFromDatabase(coverArt);
DeleteSongFromDatabase(song);
coverMgr.DeleteCoverArtFromDatabase(coverArt);
}
catch (Exception ex)
{
@@ -241,13 +241,7 @@ public class SongManager : BaseManager
}
var coverMgr = new CoverArtManager(_config);
var meta = new MetadataRetriever();
var coverArt = coverMgr.SaveCoverArt(coverArtData, song);
meta.UpdateCoverArt(song, coverArt);
song.Duration = meta.RetrieveSongDuration(song.SongPath());
meta.UpdateMetadata(song, song);
DirectoryManager dirMgr = new DirectoryManager(_config, song);
dirMgr.CreateDirectory();
@@ -406,7 +400,7 @@ public class SongManager : BaseManager
}
private bool DeleteSongFromFilesystem(Song song)
private bool DeleteSongFromFilesystem(Song song, bool deleteDirectory = false)
{
var songPath = song.SongPath();
@@ -415,6 +409,8 @@ public class SongManager : BaseManager
try
{
System.IO.File.Delete(songPath);
DeleteEmptyDirectories(ref song, ref song);
}
catch(Exception ex)
{
@@ -425,6 +421,7 @@ public class SongManager : BaseManager
return DoesSongExistOnFilesystem(song);
}
private bool DoesSongExistOnFilesystem(Song song)
{
if (!System.IO.File.Exists(song.SongPath()))
@@ -494,13 +491,12 @@ public class SongManager : BaseManager
var albumMgr = new AlbumManager(_config);
var artistMgr = new ArtistManager(_config);
var genreMgr = new GenreManager(_config);
albumMgr.DeleteAlbumFromDatabase(song);
artistMgr.DeleteArtistFromDatabase(song);
genreMgr.DeleteGenreFromDatabase(song);
var sngContext = new SongContext(_connectionString);
sngContext.Songs.Remove(song);
sngContext.SaveChanges();
artistMgr.DeleteArtistFromDatabase(song);
albumMgr.DeleteAlbumFromDatabase(song);
genreMgr.DeleteGenreFromDatabase(song);
}
#endregion
}
+18 -173
View File
@@ -2,20 +2,13 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using JWT;
using JWT.Serializers;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using RestSharp;
using Icarus.Models;
@@ -87,35 +80,6 @@ public class TokenManager : BaseManager
}
[Obsolete("Asymmetric key signing for tokens have been deprecated")]
public LoginResult LogIn(User user)
{
var tokenResult = new TokenTierOne();
tokenResult.TokenType = "Jwt";
var privateKey = ReadKeyContent(_privateKeyPath).Result;
var publicKey = ReadKeyContent(_publicKeyPath).Result;
var payload = Payload();
var token = CreateToken(payload, privateKey);
tokenResult.AccessToken = token;
var expClaim = payload.FirstOrDefault(cl =>
{
return cl.Type.Equals("exp");
});
tokenResult.Expiration = System.Convert.ToInt32(expClaim.Value);
return new LoginResult
{
UserID = user.UserID, Username = user.Username, Token = tokenResult.AccessToken,
TokenType = tokenResult.TokenType, Expiration = tokenResult.Expiration,
Message = "Successfully retrieved token"
};
}
public LoginResult LoginSymmetric(User user)
{
var tokenResult = new TokenTierOne();
@@ -124,16 +88,25 @@ public class TokenManager : BaseManager
var payload = Payload();
payload.Add(new System.Security.Claims.Claim("user_id", user.UserID.ToString(), ClaimValueTypes.Integer));
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["JWT:Secret"]));
var signIn = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
_config["JWT:Issuer"],
_config["JWT:Audience"],
payload,
expires: DateTime.UtcNow.AddMinutes(30),
signingCredentials: signIn);
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_config["JWT:Secret"]);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim("user_id", user.UserID.ToString(), ClaimValueTypes.Integer)
// Add more claims as needed
}),
Expires = DateTime.UtcNow.AddHours(1),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
Issuer = _config["Jwt:Issuer"], // Add this line
Audience = _config["Jwt:Audience"]
};
var token = tokenHandler.CreateToken(tokenDescriptor);
tokenResult.AccessToken = new JwtSecurityTokenHandler().WriteToken(token);
tokenResult.AccessToken = tokenHandler.WriteToken(token);
var expClaim = payload.FirstOrDefault(cl =>
{
@@ -152,59 +125,6 @@ public class TokenManager : BaseManager
};
}
[Obsolete("Asymmetric key signing for tokens have been deprecated")]
public bool IsTokenValid(string scope, string accessToken)
{
var result = false;
var token = DecodeToken(accessToken);
if (token == null || token.Erroneous())
{
return result;
}
result = (!token.TokenExpired() && token.ContainsScope(scope)) ? true : false;
// What would make a token valid?
// 1. The expiration date must be before the current date
// 2. The desired scope must be part of the scopes within the access token
// 3. Must be able to be decoded
return result;
}
[Obsolete("Asymmetric key signing for tokens have been deprecated")]
public Token DecodeToken(string accessToken)
{
var rsaParams = GetRSAPublic(_publicKey);
Token tok = null;
try
{
using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(rsaParams);
IJsonSerializer serializer = new JsonNetSerializer();
IDateTimeProvider provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
var algorithm = new JWT.Algorithms.RS256Algorithm(rsa);
IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
var json = decoder.Decode(accessToken);
tok = JsonConvert.DeserializeObject<Token>(json);
}
}
catch (Exception ex)
{
_logger.Error("An error occurred: {0}", ex.Message);
}
return tok;
}
private string AllScopes()
{
@@ -266,81 +186,6 @@ public class TokenManager : BaseManager
return claim;
}
[Obsolete("Asymmetric key signing for tokens have been deprecated")]
private string CreateToken(List<Claim> claims, string privateKey)
{
var token = string.Empty;
if (string.IsNullOrEmpty(privateKey))
{
privateKey = ReadKeyContent(_privateKeyPath).Result;
}
RSAParameters rsaParams;
using (var tr = new System.IO.StringReader(privateKey))
{
var pemReader = new PemReader(tr);
var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
if (keyPair == null)
{
throw new Exception("Could not read RSA private key");
}
var privateRsaParams = keyPair.Private as RsaPrivateCrtKeyParameters;
rsaParams = DotNetUtilities.ToRSAParameters(privateRsaParams);
}
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
var rsaParamsPublic = GetRSAPublic(ReadKeyContent(_publicKeyPath).Result);
var rsaPublic = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParams);
rsaPublic.ImportParameters(rsaParamsPublic);
Dictionary<string, object> payload = new Dictionary<string, object>();
foreach (var claim in claims)
{
var type = claim.Type;
var val = Int32.TryParse(claim.Value, out _);
if (val)
{
payload.Add(type, Convert.ToInt32(claim.Value));
}
else
{
payload.Add(type, claim.Value);
}
}
var algorithm = new JWT.Algorithms.RS256Algorithm(rsaPublic, rsa);
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
token = encoder.Encode(payload, privateKey);
}
return token;
}
[Obsolete("Asymmetric key signing for tokens have been deprecated")]
private RSAParameters GetRSAPublic(string publicKey)
{
using (var tr = new System.IO.StringReader(publicKey))
{
var pemReader = new PemReader(tr);
var publicKeyParams = pemReader.ReadObject() as RsaKeyParameters;
if (publicKeyParams == null)
{
throw new Exception("Could not read RSA public key");
}
return DotNetUtilities.ToRSAParameters(publicKeyParams);
}
}
private async Task<string> ReadKeyContent(string filepath)
{
return await System.IO.File.ReadAllTextAsync(filepath);
+1 -1
View File
@@ -83,7 +83,7 @@ public class SongCompression
Console.WriteLine(exMsg);
}
if (songDetails.Filename.Contains(".mp3"))
if (songDetails.Filename.Contains(Constants.FileExtensions.WAV_EXTENSION))
{
_compressedSongFilename = StripMP3Extension(songDetails.Filename);
}
-11
View File
@@ -4,8 +4,6 @@ using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Icarus.Controllers.Managers;
namespace Icarus.Controllers.V1;
@@ -39,14 +37,5 @@ public class BaseController : ControllerBase
return token;
}
[ApiExplorerSettings(IgnoreApi = true)]
[Obsolete("Asymmetric key signing for tokens have been deprecated")]
protected bool IsTokenValid(string scope)
{
var token = ParseBearerTokenFromHeader();
var tokMgr = new TokenManager(_config);
return tokMgr.IsTokenValid(scope, token);
}
#endregion
}
+1 -1
View File
@@ -148,7 +148,7 @@ public class SongDataController : BaseController
_songMgr.DeleteSong(songMetaData);
return Ok();
return Ok(songMetaData);
}
}
+6 -1
View File
@@ -53,7 +53,12 @@ public class SongStreamController : BaseController
var stream = new FileStream(song.SongPath(), FileMode.Open, FileAccess.Read);
stream.Position = 0;
var filename = $"{song.Title}.mp3";
var filename = song.Filename;
if (string.IsNullOrEmpty(song.Filename))
{
filename = song.GenerateFilename();
}
_logger.LogInformation("Starting to stream song...>");
Console.WriteLine("Starting to streamsong...");