Net8 #89
@@ -16,7 +16,7 @@ jobs:
|
|||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v2
|
uses: actions/setup-dotnet@v2
|
||||||
with:
|
with:
|
||||||
dotnet-version: 6.0.x
|
dotnet-version: 8.0.x
|
||||||
- name: Restore dependencies
|
- name: Restore dependencies
|
||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|||||||
+6
-7
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Org.BouncyCastle.Crypto.Parameters;
|
using Org.BouncyCastle.Crypto.Parameters;
|
||||||
@@ -10,11 +9,11 @@ namespace Icarus.Certs;
|
|||||||
|
|
||||||
public class SigningIssuerCertificate : IDisposable
|
public class SigningIssuerCertificate : IDisposable
|
||||||
{
|
{
|
||||||
private readonly RSACryptoServiceProvider _rsa;
|
private readonly System.Security.Cryptography.RSACryptoServiceProvider _rsa;
|
||||||
|
|
||||||
public SigningIssuerCertificate()
|
public SigningIssuerCertificate()
|
||||||
{
|
{
|
||||||
_rsa = new RSACryptoServiceProvider();
|
_rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
public RsaSecurityKey GetIssuerSigningKey(string publicKeyPath)
|
public RsaSecurityKey GetIssuerSigningKey(string publicKeyPath)
|
||||||
@@ -26,7 +25,7 @@ public class SigningIssuerCertificate : IDisposable
|
|||||||
{
|
{
|
||||||
var pem = new PemReader(reader);
|
var pem = new PemReader(reader);
|
||||||
var o = (RsaKeyParameters)pem.ReadObject();
|
var o = (RsaKeyParameters)pem.ReadObject();
|
||||||
var parameters = new RSAParameters();
|
var parameters = new System.Security.Cryptography.RSAParameters();
|
||||||
parameters.Modulus = o.Modulus.ToByteArray();
|
parameters.Modulus = o.Modulus.ToByteArray();
|
||||||
parameters.Exponent = o.Exponent.ToByteArray();
|
parameters.Exponent = o.Exponent.ToByteArray();
|
||||||
_rsa.ImportParameters(parameters);
|
_rsa.ImportParameters(parameters);
|
||||||
@@ -45,11 +44,11 @@ public class SigningIssuerCertificate : IDisposable
|
|||||||
|
|
||||||
public class SigningAudienceCertificate : IDisposable
|
public class SigningAudienceCertificate : IDisposable
|
||||||
{
|
{
|
||||||
private readonly RSACryptoServiceProvider _rsa;
|
private readonly System.Security.Cryptography.RSACryptoServiceProvider _rsa;
|
||||||
|
|
||||||
public SigningAudienceCertificate()
|
public SigningAudienceCertificate()
|
||||||
{
|
{
|
||||||
_rsa = new RSACryptoServiceProvider();
|
_rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SigningCredentials GetAudienceSigningKey(string keyPath)
|
public SigningCredentials GetAudienceSigningKey(string keyPath)
|
||||||
@@ -61,7 +60,7 @@ public class SigningAudienceCertificate : IDisposable
|
|||||||
{
|
{
|
||||||
var pem = new PemReader(reader);
|
var pem = new PemReader(reader);
|
||||||
var o = (RsaKeyParameters)pem.ReadObject();
|
var o = (RsaKeyParameters)pem.ReadObject();
|
||||||
var parameters = new RSAParameters();
|
var parameters = new System.Security.Cryptography.RSAParameters();
|
||||||
parameters.Modulus = o.Modulus.ToByteArray();
|
parameters.Modulus = o.Modulus.ToByteArray();
|
||||||
parameters.Exponent = o.Exponent.ToByteArray();
|
parameters.Exponent = o.Exponent.ToByteArray();
|
||||||
_rsa.ImportParameters(parameters);
|
_rsa.ImportParameters(parameters);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Icarus.Constants;
|
namespace Icarus.Constants;
|
||||||
@@ -7,4 +6,6 @@ public class DirectoryPaths
|
|||||||
{
|
{
|
||||||
public static string CoverArtPath =>
|
public static string CoverArtPath =>
|
||||||
Directory.GetCurrentDirectory() + "/Images/Stock/CoverArt.png";
|
Directory.GetCurrentDirectory() + "/Images/Stock/CoverArt.png";
|
||||||
|
public static string FILENAME_CHARACTERS = "ABCDEF0123456789";
|
||||||
|
public static int FILENAME_LENGTH = 25;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace Icarus.Constants;
|
||||||
|
|
||||||
|
public class FileExtensions
|
||||||
|
{
|
||||||
|
// Contains file extension with period at the beginning
|
||||||
|
public static string MP3_EXTENSION = ".mp3";
|
||||||
|
|
||||||
|
// Contains file extension with period at the beginning
|
||||||
|
public static string WAV_EXTENSION = ".wav";
|
||||||
|
|
||||||
|
// Contains file extension with period at the beginning
|
||||||
|
public static string JPG_EXTENSION = ".jpg";
|
||||||
|
}
|
||||||
@@ -47,6 +47,7 @@ public class CoverArtManager : BaseManager
|
|||||||
{
|
{
|
||||||
_logger.Info("Attempting to delete cover art from the database");
|
_logger.Info("Attempting to delete cover art from the database");
|
||||||
|
|
||||||
|
_coverArtContext.Attach(coverArt);
|
||||||
_coverArtContext.Remove(coverArt);
|
_coverArtContext.Remove(coverArt);
|
||||||
_coverArtContext.SaveChanges();
|
_coverArtContext.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ public class SongManager : BaseManager
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (DeleteSongFromFilesystem(song))
|
if (DeleteSongFromFilesystem(song, true))
|
||||||
{
|
{
|
||||||
_logger.Error("Failed to delete the song");
|
_logger.Error("Failed to delete the song");
|
||||||
|
|
||||||
@@ -158,8 +158,8 @@ public class SongManager : BaseManager
|
|||||||
var coverArt = coverMgr.GetCoverArt(song);
|
var coverArt = coverMgr.GetCoverArt(song);
|
||||||
coverMgr.DeleteCoverArt(coverArt);
|
coverMgr.DeleteCoverArt(coverArt);
|
||||||
|
|
||||||
coverMgr.DeleteCoverArtFromDatabase(coverArt);
|
|
||||||
DeleteSongFromDatabase(song);
|
DeleteSongFromDatabase(song);
|
||||||
|
coverMgr.DeleteCoverArtFromDatabase(coverArt);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -241,13 +241,7 @@ public class SongManager : BaseManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
var coverMgr = new CoverArtManager(_config);
|
var coverMgr = new CoverArtManager(_config);
|
||||||
var meta = new MetadataRetriever();
|
|
||||||
var coverArt = coverMgr.SaveCoverArt(coverArtData, song);
|
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);
|
DirectoryManager dirMgr = new DirectoryManager(_config, song);
|
||||||
dirMgr.CreateDirectory();
|
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();
|
var songPath = song.SongPath();
|
||||||
|
|
||||||
@@ -415,6 +409,8 @@ public class SongManager : BaseManager
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
System.IO.File.Delete(songPath);
|
System.IO.File.Delete(songPath);
|
||||||
|
|
||||||
|
DeleteEmptyDirectories(ref song, ref song);
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
@@ -425,6 +421,7 @@ public class SongManager : BaseManager
|
|||||||
|
|
||||||
return DoesSongExistOnFilesystem(song);
|
return DoesSongExistOnFilesystem(song);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool DoesSongExistOnFilesystem(Song song)
|
private bool DoesSongExistOnFilesystem(Song song)
|
||||||
{
|
{
|
||||||
if (!System.IO.File.Exists(song.SongPath()))
|
if (!System.IO.File.Exists(song.SongPath()))
|
||||||
@@ -494,13 +491,12 @@ public class SongManager : BaseManager
|
|||||||
var albumMgr = new AlbumManager(_config);
|
var albumMgr = new AlbumManager(_config);
|
||||||
var artistMgr = new ArtistManager(_config);
|
var artistMgr = new ArtistManager(_config);
|
||||||
var genreMgr = new GenreManager(_config);
|
var genreMgr = new GenreManager(_config);
|
||||||
albumMgr.DeleteAlbumFromDatabase(song);
|
|
||||||
artistMgr.DeleteArtistFromDatabase(song);
|
|
||||||
genreMgr.DeleteGenreFromDatabase(song);
|
|
||||||
|
|
||||||
var sngContext = new SongContext(_connectionString);
|
var sngContext = new SongContext(_connectionString);
|
||||||
sngContext.Songs.Remove(song);
|
sngContext.Songs.Remove(song);
|
||||||
sngContext.SaveChanges();
|
sngContext.SaveChanges();
|
||||||
|
artistMgr.DeleteArtistFromDatabase(song);
|
||||||
|
albumMgr.DeleteAlbumFromDatabase(song);
|
||||||
|
genreMgr.DeleteGenreFromDatabase(song);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,13 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
using JWT;
|
|
||||||
using JWT.Serializers;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Org.BouncyCastle.Crypto;
|
|
||||||
using Org.BouncyCastle.Crypto.Parameters;
|
|
||||||
using Org.BouncyCastle.OpenSsl;
|
|
||||||
using Org.BouncyCastle.Security;
|
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
|
|
||||||
using Icarus.Models;
|
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)
|
public LoginResult LoginSymmetric(User user)
|
||||||
{
|
{
|
||||||
var tokenResult = new TokenTierOne();
|
var tokenResult = new TokenTierOne();
|
||||||
@@ -124,16 +88,25 @@ public class TokenManager : BaseManager
|
|||||||
var payload = Payload();
|
var payload = Payload();
|
||||||
payload.Add(new System.Security.Claims.Claim("user_id", user.UserID.ToString(), ClaimValueTypes.Integer));
|
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 tokenHandler = new JwtSecurityTokenHandler();
|
||||||
var signIn = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
var key = Encoding.ASCII.GetBytes(_config["JWT:Secret"]);
|
||||||
var token = new JwtSecurityToken(
|
var tokenDescriptor = new SecurityTokenDescriptor
|
||||||
_config["JWT:Issuer"],
|
{
|
||||||
_config["JWT:Audience"],
|
Subject = new ClaimsIdentity(new Claim[]
|
||||||
payload,
|
{
|
||||||
expires: DateTime.UtcNow.AddMinutes(30),
|
new Claim("user_id", user.UserID.ToString(), ClaimValueTypes.Integer)
|
||||||
signingCredentials: signIn);
|
// 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"]
|
||||||
|
};
|
||||||
|
|
||||||
tokenResult.AccessToken = new JwtSecurityTokenHandler().WriteToken(token);
|
var token = tokenHandler.CreateToken(tokenDescriptor);
|
||||||
|
|
||||||
|
|
||||||
|
tokenResult.AccessToken = tokenHandler.WriteToken(token);
|
||||||
|
|
||||||
var expClaim = payload.FirstOrDefault(cl =>
|
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()
|
private string AllScopes()
|
||||||
{
|
{
|
||||||
@@ -266,81 +186,6 @@ public class TokenManager : BaseManager
|
|||||||
return claim;
|
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)
|
private async Task<string> ReadKeyContent(string filepath)
|
||||||
{
|
{
|
||||||
return await System.IO.File.ReadAllTextAsync(filepath);
|
return await System.IO.File.ReadAllTextAsync(filepath);
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public class SongCompression
|
|||||||
Console.WriteLine(exMsg);
|
Console.WriteLine(exMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (songDetails.Filename.Contains(".mp3"))
|
if (songDetails.Filename.Contains(Constants.FileExtensions.WAV_EXTENSION))
|
||||||
{
|
{
|
||||||
_compressedSongFilename = StripMP3Extension(songDetails.Filename);
|
_compressedSongFilename = StripMP3Extension(songDetails.Filename);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ using System.Linq;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
using Icarus.Controllers.Managers;
|
|
||||||
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.V1;
|
namespace Icarus.Controllers.V1;
|
||||||
|
|
||||||
@@ -39,14 +37,5 @@ public class BaseController : ControllerBase
|
|||||||
return token;
|
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
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ public class SongDataController : BaseController
|
|||||||
|
|
||||||
_songMgr.DeleteSong(songMetaData);
|
_songMgr.DeleteSong(songMetaData);
|
||||||
|
|
||||||
return Ok();
|
return Ok(songMetaData);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,12 @@ public class SongStreamController : BaseController
|
|||||||
|
|
||||||
var stream = new FileStream(song.SongPath(), FileMode.Open, FileAccess.Read);
|
var stream = new FileStream(song.SongPath(), FileMode.Open, FileAccess.Read);
|
||||||
stream.Position = 0;
|
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...>");
|
_logger.LogInformation("Starting to stream song...>");
|
||||||
Console.WriteLine("Starting to streamsong...");
|
Console.WriteLine("Starting to streamsong...");
|
||||||
|
|||||||
@@ -25,38 +25,6 @@ public class SongContext : DbContext
|
|||||||
modelBuilder.Entity<Song>()
|
modelBuilder.Entity<Song>()
|
||||||
.ToTable("Song");
|
.ToTable("Song");
|
||||||
|
|
||||||
/**
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.HasOne(s => s.Album)
|
|
||||||
.WithMany(al => al.Songs)
|
|
||||||
.HasForeignKey(s => s.AlbumID)
|
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
|
||||||
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.HasOne(sa => sa.SongArtist)
|
|
||||||
.WithMany(ar => ar.Songs)
|
|
||||||
.HasForeignKey(s => s.ArtistID)
|
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
|
||||||
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.HasOne(s => s.SongGenre)
|
|
||||||
.WithMany(gnr => gnr.Songs)
|
|
||||||
.HasForeignKey(s => s.GenreID)
|
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
|
||||||
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.HasOne(s => s.SongYear)
|
|
||||||
.WithMany(yr => yr.Songs)
|
|
||||||
.HasForeignKey(s => s.YearID)
|
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
|
||||||
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.HasOne(s => s.SongCoverArt)
|
|
||||||
.WithMany(ca => ca.Songs)
|
|
||||||
.HasForeignKey(s => s.CoverArtID)
|
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
|
||||||
*/
|
|
||||||
|
|
||||||
modelBuilder.Entity<Song>()
|
modelBuilder.Entity<Song>()
|
||||||
.Property(s => s.Year)
|
.Property(s => s.Year)
|
||||||
.IsRequired(false);
|
.IsRequired(false);
|
||||||
|
|||||||
@@ -2,11 +2,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
// using MySql.Data.EntityFrameworkCore;
|
|
||||||
// using MySql.Data;
|
|
||||||
// using MySql.Data.EntityFrameworkCore.Extensions;
|
|
||||||
// using MySql.Data.Entity;
|
|
||||||
// using MySql.Data.MySqlClient;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
|||||||
+12
-10
@@ -1,32 +1,34 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||||
<Version>0.1.10</Version>
|
<Version>0.1.10</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.2" />
|
<PackageReference Include="BCrypt.Net-Next" Version="4.0.2" />
|
||||||
|
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
|
||||||
<PackageReference Include="DotNetZip" Version="1.15.0" />
|
<PackageReference Include="DotNetZip" Version="1.15.0" />
|
||||||
<PackageReference Include="EntityFramework" Version="6.4.4" />
|
<PackageReference Include="EntityFramework" Version="6.4.4" />
|
||||||
<PackageReference Include="ID3" Version="0.6.0" />
|
<PackageReference Include="ID3" Version="0.6.0" />
|
||||||
<PackageReference Include="JWT" Version="9.0.3" />
|
<PackageReference Include="JWT" Version="10.1.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.6" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.8" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.8">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.6">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="MySql.EntityFrameworkCore" Version="5.0.8" />
|
<PackageReference Include="MySql.EntityFrameworkCore" Version="8.0.2" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.14.0" />
|
<PackageReference Include="NLog.Web.AspNetCore" Version="4.14.0" />
|
||||||
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
|
|
||||||
<PackageReference Include="RestSharp" Version="106.15.0" />
|
<PackageReference Include="RestSharp" Version="106.15.0" />
|
||||||
<PackageReference Include="SevenZip" Version="19.0.0" />
|
<PackageReference Include="SevenZip" Version="19.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.15.0" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.6.0" />
|
||||||
|
<PackageReference Include="system.text.encoding.codepages" Version="8.0.0" />
|
||||||
<PackageReference Include="taglib" Version="2.1.0" />
|
<PackageReference Include="taglib" Version="2.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@@ -20,8 +18,4 @@ public class Album
|
|||||||
public int SongCount { get; set; }
|
public int SongCount { get; set; }
|
||||||
[JsonProperty("year")]
|
[JsonProperty("year")]
|
||||||
public int Year { get; set; }
|
public int Year { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
[NotMapped]
|
|
||||||
public List<Song> Songs { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@@ -16,7 +14,4 @@ public class Artist
|
|||||||
[JsonProperty("song_count")]
|
[JsonProperty("song_count")]
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public int SongCount { get; set; }
|
public int SongCount { get; set; }
|
||||||
[JsonIgnore]
|
|
||||||
[NotMapped]
|
|
||||||
public List<Song> Songs { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-9
@@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@@ -17,24 +18,18 @@ public class CoverArt
|
|||||||
public string SongTitle { get; set; }
|
public string SongTitle { get; set; }
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public string ImagePath { get; set; }
|
public string ImagePath { get; set; }
|
||||||
[JsonIgnore]
|
|
||||||
[NotMapped]
|
|
||||||
public int SongID { get; set; }
|
|
||||||
[JsonIgnore]
|
|
||||||
[NotMapped]
|
|
||||||
public List<Song> Songs { get; set; }
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
public string GenerateFilename(int flag)
|
public string GenerateFilename(int flag)
|
||||||
{
|
{
|
||||||
const int length = 25;
|
int length = Constants.DirectoryPaths.FILENAME_LENGTH;
|
||||||
const string chars = "ABCDEF0123456789";
|
string chars = Constants.DirectoryPaths.FILENAME_CHARACTERS;
|
||||||
var random = new Random();
|
var random = new Random();
|
||||||
var filename = new string(Enumerable.Repeat(chars, length).Select(s =>
|
var filename = new string(Enumerable.Repeat(chars, length).Select(s =>
|
||||||
s[random.Next(s.Length)]).ToArray());
|
s[random.Next(s.Length)]).ToArray());
|
||||||
var extension = ".mp3";
|
var extension = Constants.FileExtensions.JPG_EXTENSION;
|
||||||
|
|
||||||
return (flag == 0) ? filename : $"{filename}{extension}";
|
return (flag == 0) ? filename : $"{filename}{extension}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@@ -16,7 +14,4 @@ public class Genre
|
|||||||
[JsonProperty("song_count")]
|
[JsonProperty("song_count")]
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public int SongCount { get; set; }
|
public int SongCount { get; set; }
|
||||||
[JsonIgnore]
|
|
||||||
[NotMapped]
|
|
||||||
public List<Song> Songs { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -73,20 +73,20 @@ public class Song
|
|||||||
|
|
||||||
public string GenerateFilename(int flag = 0)
|
public string GenerateFilename(int flag = 0)
|
||||||
{
|
{
|
||||||
const int length = 25;
|
int length = Constants.DirectoryPaths.FILENAME_LENGTH;
|
||||||
const string chars = "ABCDEF0123456789";
|
string chars = Constants.DirectoryPaths.FILENAME_CHARACTERS;
|
||||||
var random = new Random();
|
var random = new Random();
|
||||||
var filename = new string(Enumerable.Repeat(chars, length).Select(s =>
|
var filename = new string(Enumerable.Repeat(chars, length).Select(s =>
|
||||||
s[random.Next(s.Length)]).ToArray());
|
s[random.Next(s.Length)]).ToArray());
|
||||||
var extension = ".mp3";
|
var extension = Icarus.Constants.FileExtensions.WAV_EXTENSION;
|
||||||
|
|
||||||
return flag == 0 ? filename : $"{filename}{extension}";
|
return flag == 0 ? filename : $"{filename}{extension}";
|
||||||
}
|
}
|
||||||
public async Task<string> GenerateFilenameAsync(int flag = 0)
|
public async Task<string> GenerateFilenameAsync(int flag = 0)
|
||||||
{
|
{
|
||||||
const int length = 25;
|
int length = Constants.DirectoryPaths.FILENAME_LENGTH;
|
||||||
const string chars = "ABCDEF0123456789";
|
string chars = Constants.DirectoryPaths.FILENAME_CHARACTERS;
|
||||||
var extension = ".mp3";
|
var extension = Icarus.Constants.FileExtensions.WAV_EXTENSION;
|
||||||
var random = new Random();
|
var random = new Random();
|
||||||
var filename = await Task.Run(() =>
|
var filename = await Task.Run(() =>
|
||||||
{
|
{
|
||||||
|
|||||||
+97
-37
@@ -1,45 +1,105 @@
|
|||||||
using System;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using System.Collections.Generic;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.IO;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using System.Linq;
|
using Microsoft.OpenApi.Models;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore;
|
using Icarus.Database.Contexts;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using NLog.Web;
|
|
||||||
|
|
||||||
namespace Icarus;
|
|
||||||
|
|
||||||
public class Program
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
var MAX_REQUEST_BODY_SIZE = 51200000000;
|
||||||
|
|
||||||
|
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen(c =>
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
|
||||||
|
|
||||||
|
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Icarus", Version = "v1" });
|
||||||
|
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
|
||||||
|
{
|
||||||
|
Name = "Authorization",
|
||||||
|
Scheme = "Bearer",
|
||||||
|
BearerFormat = "JWT",
|
||||||
|
Type = SecuritySchemeType.ApiKey,
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Description = "Bearer *Auth Token*",
|
||||||
|
});
|
||||||
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||||
{
|
{
|
||||||
var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
logger.Debug("init main");
|
new OpenApiSecurityScheme
|
||||||
|
|
||||||
CreateHostBuilder(args).Build().Run();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
logger.Error(ex, "An error occurred");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
NLog.LogManager.Shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
|
||||||
Host.CreateDefaultBuilder(args)
|
|
||||||
.ConfigureWebHostDefaults(webBuilder =>
|
|
||||||
{
|
{
|
||||||
webBuilder.UseStartup<Startup>();
|
Reference = new OpenApiReference
|
||||||
});
|
{
|
||||||
|
Type = ReferenceType.SecurityScheme,
|
||||||
|
Id = "Bearer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new string[] {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
builder.WebHost.UseKestrel(option =>
|
||||||
|
{
|
||||||
|
option.Limits.MaxRequestBodySize = MAX_REQUEST_BODY_SIZE;
|
||||||
|
});
|
||||||
|
|
||||||
|
var Configuration = builder.Configuration;
|
||||||
|
|
||||||
|
var connString = Configuration.GetConnectionString("DefaultConnection");
|
||||||
|
|
||||||
|
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.RequireHttpsMetadata = false;
|
||||||
|
options.SaveToken = true;
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters()
|
||||||
|
{
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidateAudience = true,
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ValidAudience = Configuration["JWT:Audience"],
|
||||||
|
ValidIssuer = Configuration["JWT:Issuer"],
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(Configuration["JWT:Secret"]))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddDbContext<SongContext>(options => options.UseMySQL(connString));
|
||||||
|
builder.Services.AddDbContext<AlbumContext>(options => options.UseMySQL(connString));
|
||||||
|
builder.Services.AddDbContext<ArtistContext>(options => options.UseMySQL(connString));
|
||||||
|
builder.Services.AddDbContext<UserContext>(options => options.UseMySQL(connString));
|
||||||
|
builder.Services.AddDbContext<GenreContext>(options => options.UseMySQL(connString));
|
||||||
|
builder.Services.AddDbContext<CoverArtContext>(options => options.UseMySQL(connString));
|
||||||
|
|
||||||
|
builder.Services.AddControllers()
|
||||||
|
.AddNewtonsoftJson();
|
||||||
|
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: This should be enabled at some point
|
||||||
|
// app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
app.UseRouting();
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
app.UseEndpoints(endpoints =>
|
||||||
|
{
|
||||||
|
endpoints.MapControllers();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
# Icarus
|
# Icarus
|
||||||
|
|
||||||
Icarus is a music streaming API Server that interacts with [Mear](https://github.com/amazing-username/mear).
|
Icarus is a music streaming API Server that interacts with [Mear](https://github.com/kdeng00/mear).
|
||||||
|
|
||||||
### Interfacing With Icarus
|
### Interfacing With Icarus
|
||||||
|
|
||||||
One can interface with Icarus the music server either by:
|
One can interface with Icarus the music server either by:
|
||||||
|
|
||||||
* [Mear](https://github.com/amazing-username/mear) - Partially implemented (under development)
|
* [Mear](https://github.com/kdeng00/mear) - Partially implemented (under development)
|
||||||
* [IcarusDownloadManager](https://github.com/amazing-username/IcarusDownloadManager)
|
* [IcarusDownloadManager](https://github.com/kdeng00/IcarusDownloadManager)
|
||||||
|
|
||||||
|
|
||||||
## Built With
|
## Built With
|
||||||
|
|
||||||
* C# [.NET](https://dotnet.microsoft.com/) 6
|
* C# [.NET](https://dotnet.microsoft.com/) 8
|
||||||
* [MySql](https://www.nuget.org/packages/MySql.Data/)
|
* [MySql](https://www.nuget.org/packages/MySql.Data/)
|
||||||
* OpenSSL
|
* OpenSSL
|
||||||
* BCrypt.Net-Next
|
* BCrypt.Net-Next
|
||||||
@@ -120,7 +120,7 @@ Prior to starting the API, the Migrations must be applied. There are 6 tables wi
|
|||||||
* Year
|
* Year
|
||||||
* Genre
|
* Genre
|
||||||
|
|
||||||
There is a script for Linux systems to apply these migrations, it can be found in the [Scripts/Migrations/Linux](https://github.com/amazing-username/Icarus/blob/master/Scripts/Migrations/Linux/AddUpdate.sh) directory. Just merely execute:
|
There is a script for Linux systems to apply these migrations, it can be found in the [Scripts/Migrations/Linux](https://github.com/kdeng00/Icarus/blob/master/Scripts/Migrations/Linux/AddUpdate.sh) directory. Just merely execute:
|
||||||
```shell
|
```shell
|
||||||
scripts/Migrations/Linux/AddUpdate.sh
|
scripts/Migrations/Linux/AddUpdate.sh
|
||||||
```
|
```
|
||||||
|
|||||||
-125
@@ -1,125 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Text;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using NLog;
|
|
||||||
using NLog.Web;
|
|
||||||
using NLog.Web.AspNetCore;
|
|
||||||
|
|
||||||
using Icarus.Database.Contexts;
|
|
||||||
|
|
||||||
namespace Icarus;
|
|
||||||
public class Startup
|
|
||||||
{
|
|
||||||
#region Constructors
|
|
||||||
public Startup(IConfiguration configuration)
|
|
||||||
{
|
|
||||||
Configuration = configuration;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
public IConfiguration Configuration { get; }
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
|
||||||
public void ConfigureServices(IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddControllers();
|
|
||||||
|
|
||||||
var auth_id = Configuration["Auth0:Domain"];
|
|
||||||
var domain = $"https://{auth_id}/";
|
|
||||||
var audience = Configuration["Auth0:ApiIdentifier"];
|
|
||||||
|
|
||||||
var connString = Configuration.GetConnectionString("DefaultConnection");
|
|
||||||
|
|
||||||
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
|
|
||||||
{
|
|
||||||
options.RequireHttpsMetadata = false;
|
|
||||||
options.SaveToken = true;
|
|
||||||
options.TokenValidationParameters = new TokenValidationParameters()
|
|
||||||
{
|
|
||||||
ValidateIssuer = true,
|
|
||||||
ValidateAudience = true,
|
|
||||||
ValidAudience = Configuration["JWT:Audience"],
|
|
||||||
ValidIssuer = Configuration["JWT:Issuer"],
|
|
||||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWT:Secret"]))
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddDbContext<SongContext>(options => options.UseMySQL(connString));
|
|
||||||
services.AddDbContext<AlbumContext>(options => options.UseMySQL(connString));
|
|
||||||
services.AddDbContext<ArtistContext>(options => options.UseMySQL(connString));
|
|
||||||
services.AddDbContext<UserContext>(options => options.UseMySQL(connString));
|
|
||||||
services.AddDbContext<GenreContext>(options => options.UseMySQL(connString));
|
|
||||||
services.AddDbContext<CoverArtContext>(options => options.UseMySQL(connString));
|
|
||||||
|
|
||||||
services.AddControllers()
|
|
||||||
.AddNewtonsoftJson();
|
|
||||||
|
|
||||||
services.AddEndpointsApiExplorer();
|
|
||||||
services.AddSwaggerGen(c =>
|
|
||||||
{
|
|
||||||
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
|
|
||||||
|
|
||||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Icarus", Version = "v1" });
|
|
||||||
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
|
|
||||||
{
|
|
||||||
Name = "Authorization",
|
|
||||||
Scheme = "Bearer",
|
|
||||||
BearerFormat = "JWT",
|
|
||||||
Type = SecuritySchemeType.ApiKey,
|
|
||||||
In = ParameterLocation.Header,
|
|
||||||
Description = "Bearer *Auth Token*",
|
|
||||||
});
|
|
||||||
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
|
||||||
{
|
|
||||||
{
|
|
||||||
new OpenApiSecurityScheme
|
|
||||||
{
|
|
||||||
Reference = new OpenApiReference
|
|
||||||
{
|
|
||||||
Type = ReferenceType.SecurityScheme,
|
|
||||||
Id = "Bearer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new string[] {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called by the runtime. Use this method to configure the HTTP request pipeline.
|
|
||||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
|
||||||
{
|
|
||||||
// NOTE: Dev-related configuration can be done when env.IsDevelopment() evaluated to true
|
|
||||||
if (env.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.UseSwagger();
|
|
||||||
app.UseSwaggerUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseRouting();
|
|
||||||
app.UseAuthentication();
|
|
||||||
app.UseAuthorization();
|
|
||||||
app.UseEndpoints(endpoints =>
|
|
||||||
{
|
|
||||||
endpoints.MapControllers();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user