From aeecc524a4846a8edd0b3a073df59a0dfed3f28b Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 24 Mar 2024 16:53:12 +0000 Subject: [PATCH] WIP /search --- .vscode/tasks.json | 39 -- Makefile | 14 +- README.md | 10 + src/isn.abst/ApiConfig.cs | 5 +- src/isn.abst/Permalink.cs | 12 +- src/isn.abst/isn.abst.csproj | 2 +- src/isn/Program.cs | 43 +- src/isn/Settings.cs | 59 +- src/isn/commands/PushCommand.cs | 23 +- src/isn/commands/push.cs | 6 +- src/isn/commands/store-api-key.cs | 4 +- .../Packages/PackagesController.Catalog.cs | 8 +- .../Packages/PackagesController.GetPackage.cs | 33 +- .../PackagesController.GetVersions.cs | 3 +- .../Packages/PackagesController.Put.cs | 186 +----- .../Packages/PackagesController.Search.cs | 1 + src/isnd/Data/ApplicationDbContext.cs | 8 + src/isnd/Data/Catalog/DependencyGroup.cs | 6 - src/isnd/Data/Catalog/PackageDetails.cs | 14 +- src/isnd/Data/Packages/Dependency.cs | 31 + .../Data/Packages/PackageDependencyGroup.cs | 35 ++ src/isnd/Data/Packages/PackageVersion.cs | 7 + src/isnd/Interfaces/IPackageManager.cs | 7 +- .../20240318003218_dependencies.Designer.cs | 529 ++++++++++++++++++ .../Migrations/20240318003218_dependencies.cs | 74 +++ .../ApplicationDbContextModelSnapshot.cs | 79 ++- src/isnd/Services/InvalidPackageException.cs | 25 + src/isnd/Services/PackageManager.cs | 236 ++++++-- src/isnd/isnd.csproj | 27 +- test/data/test-isn/urls | 6 + test/isn.tests/PushTest.cs | 14 +- test/isn.tests/isn.tests.csproj | 13 +- test/isnd.tests/UnitTestWebHost.cs | 12 +- test/isnd.tests/isnd.tests.csproj | 8 +- 34 files changed, 1188 insertions(+), 391 deletions(-) delete mode 100644 src/isnd/Data/Catalog/DependencyGroup.cs create mode 100644 src/isnd/Data/Packages/Dependency.cs create mode 100644 src/isnd/Data/Packages/PackageDependencyGroup.cs create mode 100644 src/isnd/Migrations/20240318003218_dependencies.Designer.cs create mode 100644 src/isnd/Migrations/20240318003218_dependencies.cs create mode 100644 src/isnd/Services/InvalidPackageException.cs diff --git a/.vscode/tasks.json b/.vscode/tasks.json index eb08d94..61c42ba 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,19 +1,6 @@ { "version": "2.0.0", "tasks": [ - { - "label": "restore", - "command": "dotnet", - "type": "process", - "args": [ - "restore", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary", - "--ignore-failed-sources" - ], - "problemMatcher": "$msCompile", - "group": "build" - }, { "label": "build", "command": "dotnet", @@ -46,21 +33,6 @@ "dependsOn":["build"], "group": "test" }, - - { - "label": "buildcli", - "command": "msbuild", - "type": "process", - "args": [ - "src/isn", - "/p:Configuration=Debug", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary", - "/restore" - ], - "problemMatcher": "$msCompile", - "group": "build" - }, { "label": "publish", "command": "dotnet", @@ -79,17 +51,6 @@ }, "group": "none" }, - { - "label": "monopublish", - "command": "msbuild", - "type": "process", - "args": [ - "/t:publish", - "/p:TargetFramework=netcoreapp2.1;PublishDir=${workspaceFolder}/artiffacts;RuntimeIdentifier=linux-x64", - - ], - "problemMatcher": "$msCompile" - }, { "label": "test", "command": "dotnet", diff --git a/Makefile b/Makefile index 455bf11..156951c 100644 --- a/Makefile +++ b/Makefile @@ -24,9 +24,21 @@ packs: pack-isn pack-isnd pack-isn.abst clean: clean-isnd clean-isn clean-isn.abst server-update: - dotnet build -c Release + dotnet build -c Release src/isnd dotnet publish -c Release -f net7.0 src/isnd sudo systemctl stop isnd sudo cp -a src/isnd/bin/Release/net7.0/publish/* /srv/www/isnd sudo systemctl start isnd +client-update: + dotnet build -c Release src/isn + # MAJ du client + sudo cp -a src/isn/bin/Release/net7.0/* /usr/local/lib/isn + sudo chown -R root:root /usr/local/lib/isn + +src/isn.abst/bin/Release/isn.abst.1.0.24.nupkg: + dotnet pack src/isn.abst -c Release + +push-test: src/isn.abst/bin/Release/isn.abst.1.0.24.nupkg + isn push -s "http://localhost:3002/v3/index.json" src/isn.abst/bin/Release/isn.abst.1.0.24.nupkg + diff --git a/README.md b/README.md index 2059a57..9445c22 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,8 @@ sudo ln -s /usr/local/lib/isn/isn /usr/local/bin/isn ### Mises à jour +Dans le détail, la séquence serait du style : + ````bash # compiler tout dotnet build -c Release @@ -87,3 +89,11 @@ sudo systemctl start isnd sudo cp -a src/isn/bin/Release/net7.0/* /usr/local/lib/isn sudo chown -R root:root /usr/local/lib/isn ```` + +On pourra cibler "client-update" ou "server-update", à la construction : + + +````bash +make server-update +make client-update +```` diff --git a/src/isn.abst/ApiConfig.cs b/src/isn.abst/ApiConfig.cs index 38b11d7..e1edf18 100644 --- a/src/isn.abst/ApiConfig.cs +++ b/src/isn.abst/ApiConfig.cs @@ -1,3 +1,4 @@ +using System; using isn.abst; namespace isnd.Entities @@ -15,6 +16,8 @@ namespace isnd.Entities public const string Content = "/content"; public const string Nuget = "/nuget"; - public const string Find = "/index/FindPackagesById()"; // /FindPackagesById()?id='isn.abst'&semVerLevel=2.0.0 + [Obsolete("use the V3 search")] + + public const string V2Find = "/v2/FindPackagesById()"; // /FindPackagesById()??$filter=IsLatestVersion&$orderby=Version desc&$top=1&id='isn.abst' } } \ No newline at end of file diff --git a/src/isn.abst/Permalink.cs b/src/isn.abst/Permalink.cs index 56a6ee8..cbd1386 100644 --- a/src/isn.abst/Permalink.cs +++ b/src/isn.abst/Permalink.cs @@ -4,6 +4,11 @@ namespace isnd.Data.Catalog { public abstract class Permalink { + public Permalink(string id) + { + Type = GetType().Name; + this.id = id; + } public Permalink(string id, string type) { @@ -11,11 +16,6 @@ namespace isnd.Data.Catalog this.id = id; } - public Permalink(string id) - { - Type = GetType().Name; - this.id = id; - } [JsonProperty("@type")] public virtual string Type { get; set; } @@ -23,7 +23,7 @@ namespace isnd.Data.Catalog [JsonProperty("@id")] public string Id { get => id; } - private readonly string id; + protected string id; public string GetId() { return id; } diff --git a/src/isn.abst/isn.abst.csproj b/src/isn.abst/isn.abst.csproj index a1d69d1..07912d2 100644 --- a/src/isn.abst/isn.abst.csproj +++ b/src/isn.abst/isn.abst.csproj @@ -2,7 +2,7 @@ 1.0.1 1.0.7 - net7.0 + net7.0;net8.0 NETSDK1138 1.0.7.0 1.0.7.0 diff --git a/src/isn/Program.cs b/src/isn/Program.cs index baf4906..d47e8f0 100644 --- a/src/isn/Program.cs +++ b/src/isn/Program.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Security.Cryptography; +using System.Text; using Mono.Options; using Newtonsoft.Json; @@ -16,12 +18,18 @@ namespace isn if (cfgSettingIf.Exists) { var json = File.ReadAllText(cfgSettingIf.FullName); - settings = JsonConvert.DeserializeObject(json); - CurrentSource = settings.DefaultSourceKey; + Settings = JsonConvert.DeserializeObject(json); + CurrentSource = Settings.DefaultSourceKey; } + + if (Settings==null) + { + Settings= Settings.Create(); + } + rsa = RSA.Create(Settings.RSAParameters); } static readonly OptionSet storeoptions = new OptionSet { - { "s|source=", "use source", val => CurrentSource ??= val }, + { "s|source=", "use source", val => Settings.CurrentSourceKey ??= val }, { "h|help", "show this message and exit", h => shouldShowPushHelp = h != null }, }; @@ -38,11 +46,9 @@ namespace isn { "v|version", "show soft version info and exit", h => shouldShowVersion = h != null } }; - static string apiKey; - static readonly OptionSet pushoptions = new OptionSet { - { "k|api-key=", "use api key", val => apiKey = apiKey ?? val }, - { "s|source=", "use source", val => CurrentSource = CurrentSource ?? val }, + { "k|api-key=", "use api key", val => Settings.CurrentSource.SetApiKey(rsa, val)}, + { "s|source=", "use source", val => Settings.CurrentSourceKey = val }, { "h|help", "show this message and exit", h => shouldShowPushHelp = h != null }, }; static readonly OptionSet sourceoptions = new OptionSet { @@ -57,31 +63,21 @@ namespace isn private static bool shouldShowVersion; private static bool shouldShowSourceHelp; private static bool shouldShowPushHelp; - - static Settings settings = null; + public static RSA rsa; public static Settings Settings { - get - { - if (settings == null) - LoadConfig(); - if (settings == null) - { - settings = new Settings - { - DataProtectionTitle = "isn", - Sources = new Dictionary() - }; - } - return settings; - } + get; set; } + public static string CurrentSource { get => Settings.CurrentSourceKey; set => Settings.CurrentSourceKey = value; } static int Main(string[] args) { + + LoadConfig(); + var commandSet = new CommandSet("isn"); var srclst = new Command("list") { @@ -213,7 +209,6 @@ namespace isn Console.WriteLine("isn version " + GitVersionInformation.AssemblySemFileVer); } return commandSet.Run(args); - } } } diff --git a/src/isn/Settings.cs b/src/isn/Settings.cs index fa188f5..c8988c6 100644 --- a/src/isn/Settings.cs +++ b/src/isn/Settings.cs @@ -9,7 +9,6 @@ namespace isn { public class SourceSettings { - private RSA rsa; /// /// Protected API Key @@ -25,26 +24,38 @@ namespace isn public SourceSettings() { - rsa = RSA.Create(); } - public string GetClearApiKey() + public string GetClearApiKey(RSA rsa) { - var base64EncodedBytes = System.Convert.FromBase64String(ProtectedApiKey); - var decrypted = rsa.Decrypt(base64EncodedBytes, RSAEncryptionPadding.Pkcs1); - return Encoding.UTF8.GetString(decrypted); + var decrypted = rsa.Decrypt(System.Convert.FromBase64String(ProtectedApiKey), RSAEncryptionPadding.Pkcs1); + return Encoding.Default.GetString(decrypted); } - public void SetApiKey(string key) + public void SetApiKey(RSA rsa, string key) { - var crypted =rsa.Encrypt(Encoding.UTF8.GetBytes(key), RSAEncryptionPadding.Pkcs1); - ProtectedApiKey = System.Convert.ToBase64String(crypted); + var ciphered =rsa.Encrypt(Encoding.Default.GetBytes(key), RSAEncryptionPadding.Pkcs1); + ProtectedApiKey = System.Convert.ToBase64String(ciphered); } } public class Settings { - public string DataProtectionTitle { get; set; } + private Settings() + { + + } + + public static Settings Create() + { + var rsaParams = CreateCipheringParameters(); + return new Settings { + RSAParameters = rsaParams, + Sources = new Dictionary() + }; + } + + public RSAParameters RSAParameters { get; set; } public Dictionary Sources { get; set; } private string defSourceKey; @@ -58,30 +69,24 @@ namespace isn get => defSourceKey; set { - if (!Sources.ContainsKey(value)) - { - Sources[value]=new SourceSettings - { - Url = defSourceKey - }; - } defSourceKey = value; } } - string currentSourceKey; [JsonIgnore, NotMapped] - public string CurrentSourceKey + public string CurrentSourceKey {get; set;} + + private static RSAParameters CreateCipheringParameters() { - get { - return currentSourceKey; - } - set{ - if (!Sources.ContainsKey(value)) - throw new InvalidOperationException($"source is invalid ({value})"); - currentSourceKey = value; - } + var provider = new RSACryptoServiceProvider(2048); + return provider.ExportParameters(true); + } + + [JsonIgnore, NotMapped] + public SourceSettings CurrentSource + { + get => this.Sources[CurrentSourceKey]; } } } diff --git a/src/isn/commands/PushCommand.cs b/src/isn/commands/PushCommand.cs index 7d64f66..71a41a6 100644 --- a/src/isn/commands/PushCommand.cs +++ b/src/isn/commands/PushCommand.cs @@ -17,7 +17,7 @@ namespace isn this.settings = settings; } - public PushReport Run(string pkg, string source, string apikey) + public PushReport Run(string pkg, string source, string apiKey) { var resources = SourceHelpers.GetServerResources(source); @@ -33,25 +33,30 @@ namespace isn var report = new PushReport { PkgName = fi.Name, - Message = "Le fichier n'existe pas : " + fi.FullName + Message = "The package does not exist : " + fi.FullName }; return report; } - using (var client = new HttpClient()) + using (var client = new HttpClient( + new HttpClientHandler + { + AllowAutoRedirect = false + } + )) try { - return client.UploadFilesToServer(new Uri(pubRes.Id), fi, settings.Sources[source].GetClearApiKey()); + return client.UploadFilesToServer(new Uri(pubRes.Id), fi, settings.Sources[source].GetClearApiKey(Program.rsa)); } - catch (HttpRequestException hrex) + catch (HttpRequestException httpEx) { var report = new PushReport { PkgName = fi.Name, - Message = "HttpRequest: " + hrex.Message, - StackTrace = hrex.StackTrace, - StatusCode = hrex.HResult.ToString() + Message = "HttpRequest: " + httpEx.Message, + StackTrace = httpEx.StackTrace, + StatusCode = httpEx.HResult.ToString() }; - Console.Error.WriteLine(hrex.Message); + Console.Error.WriteLine(httpEx.Message); return report; } catch (Exception ex) diff --git a/src/isn/commands/push.cs b/src/isn/commands/push.cs index 5f40156..df1aed6 100644 --- a/src/isn/commands/push.cs +++ b/src/isn/commands/push.cs @@ -14,11 +14,11 @@ namespace isn List pushReports = new List(); var cmd = new PushCommand(Settings); - if (CurrentSource == null) throw new InvalidOperationException("source is null"); - + if (Settings.CurrentSource == null) throw new InvalidOperationException("source is null"); + var source = Settings.CurrentSource; foreach (string pkg in pkgs) { - var report = cmd.Run(pkg, CurrentSource, apiKey); + var report = cmd.Run(pkg, source.Url, source.GetClearApiKey(rsa)); pushReports.Add(report); } return pushReports; diff --git a/src/isn/commands/store-api-key.cs b/src/isn/commands/store-api-key.cs index 33231f6..778ce57 100644 --- a/src/isn/commands/store-api-key.cs +++ b/src/isn/commands/store-api-key.cs @@ -14,7 +14,7 @@ namespace isn var args = storeoptions.Parse(storeArgs); if (args.Count != 1) { - Console.Error.WriteLine("StoreApiKey command takse one and only one argument, the key."); + Console.Error.WriteLine("StoreApiKey command takes only one argument, the key."); shouldShowPushHelp=true; } if (shouldShowPushHelp) @@ -25,7 +25,7 @@ namespace isn } else { - Settings.Sources[Settings.CurrentSourceKey].SetApiKey(args[0]); + Settings.Sources[Settings.CurrentSourceKey].SetApiKey(Program.rsa, args[0]); SaveConfig(); } } diff --git a/src/isnd/Controllers/Packages/PackagesController.Catalog.cs b/src/isnd/Controllers/Packages/PackagesController.Catalog.cs index c9c2d17..628996f 100644 --- a/src/isnd/Controllers/Packages/PackagesController.Catalog.cs +++ b/src/isnd/Controllers/Packages/PackagesController.Catalog.cs @@ -1,13 +1,6 @@ -using System.Data.Common; -using System.Linq; using System.Threading.Tasks; -using isnd.Services; using isnd.Entities; using Microsoft.AspNetCore.Mvc; -using System.Collections.Generic; -using NuGet.Versioning; -using isnd.Data.Packages.Catalog; -using isnd.Data.Catalog; using isn.abst; namespace isnd.Controllers @@ -23,6 +16,7 @@ namespace isnd.Controllers } + [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Content + "/{id}/{version}.json")] [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Registration + "/{id}/{version}.json")] public async Task CatalogRegistration(string id, string version) { diff --git a/src/isnd/Controllers/Packages/PackagesController.GetPackage.cs b/src/isnd/Controllers/Packages/PackagesController.GetPackage.cs index e929239..40113df 100644 --- a/src/isnd/Controllers/Packages/PackagesController.GetPackage.cs +++ b/src/isnd/Controllers/Packages/PackagesController.GetPackage.cs @@ -7,52 +7,51 @@ using isn.abst; namespace isnd.Controllers { - // TODO /search GET {@id}?q={QUERY}&skip={SKIP}&take={TAKE}&prerelease={PRERELEASE}&semVerLevel={SEMVERLEVEL}&packageType={PACKAGETYPE} - public partial class PackagesController { // Web get the paquet - [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Nuget + "/{id}/{lower}/{idf}-{lowerf}." + [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Nuget + "/{id}/{lower}/{idf}-{lowerFromName}." + Constants.PacketFileExtension)] - [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Content + "/{id}/{lower}/{idf}-{lowerf}." + [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Content + "/{id}/{lower}/{idf}-{lowerFromName}." + Constants.PacketFileExtension)] public IActionResult GetPackage( [FromRoute][SafeName][Required] string id, [FromRoute][SafeName][Required] string lower, - [FromRoute] string idf, [FromRoute] string lowerf) + [FromRoute] string idf, [FromRoute] string lowerFromName) { - var pkgpath = Path.Combine(isndSettings.PackagesRootDir, + var pkgPath = Path.Combine(isndSettings.PackagesRootDir, id, lower, $"{id}-{lower}." + Constants.PacketFileExtension ); - FileInfo pkgfi = new FileInfo(pkgpath); + FileInfo pkgFileInfo = new FileInfo(pkgPath); - if (!pkgfi.Exists) + if (!pkgFileInfo.Exists) { - return BadRequest("!pkgfi.Exists"); + return BadRequest("!pkgFileInfo.Exists"); } - return File(pkgfi.OpenRead(), "application/zip; charset=binary"); + return File(pkgFileInfo.OpenRead(), "application/zip; charset=binary"); } // Web get spec - [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Nuspec + "/{id}/{lower}/{idf}-{lowerf}." + [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Nuspec + "/{id}/{lower}/{idf}-{lowerFromName}." + Constants.SpecFileExtension)] public IActionResult GetNuspec( [FromRoute][SafeName][Required] string id, [FromRoute][SafeName][Required] string lower, [FromRoute][SafeName][Required] string idf, - [FromRoute][SafeName][Required] string lowerf) + [FromRoute][SafeName][Required] string lowerFromName) { - var pkgpath = Path.Combine(isndSettings.PackagesRootDir, + var pkgPath = Path.Combine(isndSettings.PackagesRootDir, id, lower, $"{id}." + Constants.SpecFileExtension); - FileInfo pkgfi = new FileInfo(pkgpath); - if (!pkgfi.Exists) + FileInfo pkgFileInfo = new FileInfo(pkgPath); + if (!pkgFileInfo.Exists) { - return BadRequest("!pkgfi.Exists"); + return BadRequest("!pkgFileInfo.Exists"); } - return File(pkgfi.OpenRead(), "text/xml; charset=utf-8"); + return File(pkgFileInfo.OpenRead(), "text/xml; charset=utf-8"); } + } } \ No newline at end of file diff --git a/src/isnd/Controllers/Packages/PackagesController.GetVersions.cs b/src/isnd/Controllers/Packages/PackagesController.GetVersions.cs index e72144f..90550cd 100644 --- a/src/isnd/Controllers/Packages/PackagesController.GetVersions.cs +++ b/src/isnd/Controllers/Packages/PackagesController.GetVersions.cs @@ -1,13 +1,12 @@ using Microsoft.AspNetCore.Mvc; using NuGet.Versioning; using isnd.Entities; -using isn.abst; namespace isnd.Controllers { public partial class PackagesController { - [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Find)] + [HttpGet("~" + ApiConfig.V2Find)] public IActionResult GetVersions( string id, string lower, diff --git a/src/isnd/Controllers/Packages/PackagesController.Put.cs b/src/isnd/Controllers/Packages/PackagesController.Put.cs index 8b4a570..7aad99e 100644 --- a/src/isnd/Controllers/Packages/PackagesController.Put.cs +++ b/src/isnd/Controllers/Packages/PackagesController.Put.cs @@ -1,25 +1,13 @@ -using Microsoft.VisualBasic.CompilerServices; -using System.Linq.Expressions; - using System; using System.Collections.Generic; -using System.IO; -using System.IO.Compression; using System.Linq; -using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; -using NuGet.Packaging.Core; -using NuGet.Versioning; -using isnd.Data; -using isnd.Helpers; using isnd.Entities; using Microsoft.AspNetCore.Http; using isn.abst; -using isnd.Data.Packages; -using Microsoft.EntityFrameworkCore; namespace isnd.Controllers { @@ -38,184 +26,26 @@ namespace isnd.Controllers var files = new List(); ViewData["files"] = files; - var clearkey = protector.Unprotect(apiKey); - var apikey = dbContext.ApiKeys.SingleOrDefault(k => k.Id == clearkey); - if (apikey == null) + var clearKey = protector.Unprotect(apiKey); + var dbApiKey = dbContext.ApiKeys.SingleOrDefault(k => k.Id == clearKey); + if (dbApiKey == null) { logger.LogError("403 : no api-key"); return Unauthorized(); } - Commit commit = new Commit - { - Action = PackageAction.PublishPackage, - TimeStamp = DateTimeOffset.Now.ToUniversalTime() - }; - foreach (IFormFile file in Request.Form.Files) { - string initpath = Path.Combine(Environment.GetEnvironmentVariable("TEMP") ?? - Environment.GetEnvironmentVariable("TMP") ?? "/tmp", - $"isn-{Guid.NewGuid()}."+Constants.PacketFileExtension); - - using (FileStream fw = new FileStream(initpath, FileMode.Create)) - { - file.CopyTo(fw); - } - - using (FileStream fw = new FileStream(initpath, FileMode.Open)) - { - var archive = new ZipArchive(fw); - - var spec = archive.Entries.FirstOrDefault(e => e.FullName.EndsWith("." + Constants.SpecFileExtension)); - if (spec == null) return BadRequest(new { error = "no " + Constants.SpecFileExtension + " from archive" }); - string pkgpath; - NuGetVersion version; - string pkgid; - string fullpath; - - using (var specstr = spec.Open()) - { - NuspecCoreReader reader = new NuspecCoreReader(specstr); - - string pkgdesc = reader.GetDescription(); - var types = reader.GetPackageTypes(); - pkgid = reader.GetId(); - version = reader.GetVersion(); - - string pkgidpath = Path.Combine(isndSettings.PackagesRootDir, - pkgid); - pkgpath = Path.Combine(pkgidpath, version.ToFullString()); - string name = $"{pkgid}-{version}."+Constants.PacketFileExtension; - fullpath = Path.Combine(pkgpath, name); - - var destpkgiddir = new DirectoryInfo(pkgidpath); - Package pkg = dbContext.Packages.SingleOrDefault(p => p.Id == pkgid); - if (pkg != null) - { - if (pkg.OwnerId != apikey.UserId) - { - return new ForbidResult(); - } - pkg.Description = pkgdesc; - } - else - { - pkg = new Package - { - Id = pkgid, - Description = pkgdesc, - OwnerId = apikey.UserId, - LatestCommit = commit - }; - dbContext.Packages.Add(pkg); - } - if (!destpkgiddir.Exists) destpkgiddir.Create(); - - var source = new FileInfo(initpath); - var dest = new FileInfo(fullpath); - var destdir = new DirectoryInfo(dest.DirectoryName); - if (dest.Exists) - { - logger.LogWarning($"Existant package on disk : '{dest.FullName}'"); - // La version existe sur le disque, - // mais si elle ne l'est pas en base de donnéés, - // on remplace la version sur disque. - string exFullString = version.ToFullString(); - var pkgv = dbContext.PackageVersions. - Include(v=>v.LatestCommit) - .SingleOrDefault( - v => v.PackageId == pkg.Id && v.FullString == exFullString - ); - if (pkgv!=null && ! pkgv.IsDeleted) - { - string msg = $"existant : {pkg.Id}-{exFullString}"; - logger.LogWarning("400 : {msg}", msg); - ModelState.AddModelError("pkgversion", msg); - return BadRequest(this.CreateAPIKO("existant")); - } else dest.Delete(); - } - { - if (!destdir.Exists) destdir.Create(); - source.MoveTo(fullpath); - files.Add(name); - string fullstringversion = version.ToFullString(); - var pkgvers = dbContext.PackageVersions.Where - (v => v.PackageId == pkg.Id && v.FullString == fullstringversion); - if (pkgvers.Count() > 0) - { - foreach (var v in pkgvers.ToArray()) - dbContext.PackageVersions.Remove(v); - } - - // FIXME default type or null - if (types==null || types.Count==0) - dbContext.PackageVersions.Add - (new PackageVersion{ - - Package = pkg, - Major = version.Major, - Minor = version.Minor, - Patch = version.Patch, - Revision = version.Revision, - IsPrerelease = version.IsPrerelease, - FullString = version.ToFullString(), - Type = null, - LatestCommit = commit - }); - else - foreach (var type in types) - { - var pkgver = new PackageVersion - { - Package = pkg, - Major = version.Major, - Minor = version.Minor, - Patch = version.Patch, - IsPrerelease = version.IsPrerelease, - FullString = version.ToFullString(), - Type = type.Name, - LatestCommit = commit - }; - dbContext.PackageVersions.Add(pkgver); - } - - dbContext.Commits.Add(commit); - await dbContext.SaveChangesAsync(); - await packageManager.ÛpdateCatalogForAsync(commit); - - logger.LogInformation($"new paquet : {spec.Name}"); - } - } - using (var shacrypto = System.Security.Cryptography.SHA512.Create()) - { - using (var stream = System.IO.File.OpenRead(fullpath)) - { - var hash = shacrypto.ComputeHash(stream); - var shafullname = fullpath + ".sha512"; - var hashtext = Convert.ToBase64String(hash); - var hashtextbytes = Encoding.ASCII.GetBytes(hashtext); - - using (var shafile = System.IO.File.OpenWrite(shafullname)) - { - shafile.Write(hashtextbytes, 0, hashtextbytes.Length); - } - } - } - string nuspecfullpath = Path.Combine(pkgpath, pkgid + "." + Constants.SpecFileExtension); - FileInfo nfpi = new(nuspecfullpath); - - if (nfpi.Exists) - nfpi.Delete(); - spec.ExtractToFile(nuspecfullpath); - } + var version = await packageManager.PutPackageAsync(file.OpenReadStream(), dbApiKey.UserId); + logger.LogInformation($"new package : {version.PackageId} {version.NugetLink}"); } return Ok(); } catch (Exception ex) { - logger.LogError("PUT exception : " + ex.Message); + var message = $"PUT exception : {ex.Message} ({ex.GetType().Name})"; + logger.LogError(message); logger.LogError("Stack Trace : " + ex.StackTrace); - return new ObjectResult(new { ViewData, ex.Message }) + return new ObjectResult(new { ViewData, message }) { StatusCode = 500 }; } } diff --git a/src/isnd/Controllers/Packages/PackagesController.Search.cs b/src/isnd/Controllers/Packages/PackagesController.Search.cs index 30d275c..cc069db 100644 --- a/src/isnd/Controllers/Packages/PackagesController.Search.cs +++ b/src/isnd/Controllers/Packages/PackagesController.Search.cs @@ -13,6 +13,7 @@ namespace isnd.Controllers // Web get the paquet [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Search)] [HttpHead("~" + Constants.ApiVersionPrefix + ApiConfig.Search)] + [HttpHead("~" + ApiConfig.V2Find)] public async Task Search( string q=null, int skip=0, diff --git a/src/isnd/Data/ApplicationDbContext.cs b/src/isnd/Data/ApplicationDbContext.cs index 0b651f2..511b3d2 100644 --- a/src/isnd/Data/ApplicationDbContext.cs +++ b/src/isnd/Data/ApplicationDbContext.cs @@ -24,6 +24,11 @@ namespace isnd.Data .HasKey( v => new { v.PackageId, v.FullString } ); _ = builder.Entity() .HasOne(v => v.Package).WithMany(p => p.Versions).HasForeignKey(x => x.PackageId); + + + _ = builder.Entity().HasOne(g=>g.PackageVersion) + .WithMany(v => v.DependencyGroups).HasForeignKey(x => new { x.PackageId, x.PackageVersionFullString } ); + } @@ -50,5 +55,8 @@ namespace isnd.Data /// /// public DbSet Commits { get; set; } + public DbSet Dependencies { get; set; } + + public DbSet PackageDependencyGroups { get; set; } } } diff --git a/src/isnd/Data/Catalog/DependencyGroup.cs b/src/isnd/Data/Catalog/DependencyGroup.cs deleted file mode 100644 index 240d6a3..0000000 --- a/src/isnd/Data/Catalog/DependencyGroup.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace isnd.Data.Catalog -{ - public class DependencyGroup - { - } -} \ No newline at end of file diff --git a/src/isnd/Data/Catalog/PackageDetails.cs b/src/isnd/Data/Catalog/PackageDetails.cs index 2082e97..82baeb4 100644 --- a/src/isnd/Data/Catalog/PackageDetails.cs +++ b/src/isnd/Data/Catalog/PackageDetails.cs @@ -33,6 +33,14 @@ namespace isnd.Data.Catalog CommitId = pkg.CommitId; CommitTimeStamp = pkg.LatestCommit.CommitTimeStamp; IsListed = !pkg.IsDeleted && pkg.Package.Public; + if (pkg.DependencyGroups!=null) + { + if (pkg.DependencyGroups.Count>0) + { + dependencyGroups = pkg.DependencyGroups.ToArray(); + } + } + // TODO Licence Project Urls, Summary, Title, etc ... } @@ -56,7 +64,7 @@ namespace isnd.Data.Catalog /// The dependencies of the package, grouped by target framework /// /// array of objects - public DependencyGroup[] dependencyGroups { get; set; } = Array.Empty(); + public PackageDependencyGroup[] dependencyGroups { get; set; } /// /// The deprecation associated with the package @@ -127,8 +135,8 @@ namespace isnd.Data.Catalog [JsonProperty("id")] public string PackageId { get; set; } - public IEnumerable DependencySets { get; set; } - = Array.Empty(); + public IEnumerable DependencySets { get; set; } + = Array.Empty(); public long? DownloadCount { get; set; } diff --git a/src/isnd/Data/Packages/Dependency.cs b/src/isnd/Data/Packages/Dependency.cs new file mode 100644 index 0000000..3fa8daa --- /dev/null +++ b/src/isnd/Data/Packages/Dependency.cs @@ -0,0 +1,31 @@ +using System.ComponentModel.DataAnnotations; +using Newtonsoft.Json; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using System.ComponentModel.DataAnnotations.Schema; +using isnd.Data.Packages; + +namespace isnd.Data +{ + public class Dependency + { + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public string Id { get;set;} + + /// + /// Package Id + /// + /// + /// + /// + [Required] + [ForeignKey("Group")] + public string DependencyGroupId { set ; get ; } + + + public virtual PackageDependencyGroup Group{ get; set; } + + public string Version { get; set; } + public string Exclude { get; set; } + + } +} \ No newline at end of file diff --git a/src/isnd/Data/Packages/PackageDependencyGroup.cs b/src/isnd/Data/Packages/PackageDependencyGroup.cs new file mode 100644 index 0000000..0b0ac2c --- /dev/null +++ b/src/isnd/Data/Packages/PackageDependencyGroup.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.DotNet.Scaffolding.Shared.ProjectModel; +using Microsoft.Identity.Client; +using Newtonsoft.Json; +using NuGet.Frameworks; +using NuGet.Packaging; +using NuGet.Packaging.Core; +using NuGet.Versioning; + +namespace isnd.Data +{ + public class PackageDependencyGroup + { + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public string Id { get ; set;} + + [Required] + public string PackageId { get ; set;} + + [Required] + public string PackageVersionFullString { get ; set;} + + [JsonProperty("targetFramework")] + public string TargetFramework { get; set; } + + [JsonProperty("dependencies")] + [ForeignKey("DependencyGroupId")] + public virtual List Dependencies { get; set; } + + public virtual PackageVersion PackageVersion { get; set; } + } + +} \ No newline at end of file diff --git a/src/isnd/Data/Packages/PackageVersion.cs b/src/isnd/Data/Packages/PackageVersion.cs index 49df6b3..b4d1eba 100644 --- a/src/isnd/Data/Packages/PackageVersion.cs +++ b/src/isnd/Data/Packages/PackageVersion.cs @@ -11,6 +11,10 @@ using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using NuGet.Versioning; using System; +using NuGet.Packaging; +using System.Collections.Generic; +using Package = isnd.Data.Packages.Package; +using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace isnd.Data { @@ -60,6 +64,8 @@ namespace isnd.Data public string CommitId { get => CommitNId.ToString(); } public virtual Commit LatestCommit { get; set; } + + public virtual List DependencyGroups { get; set; } public string NugetLink => $"{ApiConfig.Nuget}/{PackageId}/{FullString}/{PackageId}-{FullString}." + Constants.PacketFileExtension; public string NuspecLink => $"{ApiConfig.Nuspec}/{PackageId}/{FullString}/{PackageId}-{FullString}." @@ -73,6 +79,7 @@ namespace isnd.Data return new Catalog.Package(apiBase, this.PackageId , FullString, new Catalog.PackageDetails(this, apiBase, apiBase + ApiConfig.Registration + "/" + this.PackageId + "/" + FullString + ".json")); } + public bool IsDeleted => LatestCommit?.Action == PackageAction.DeletePackage; } } \ No newline at end of file diff --git a/src/isnd/Interfaces/IPackageManager.cs b/src/isnd/Interfaces/IPackageManager.cs index 9c92f21..4f88cda 100644 --- a/src/isnd/Interfaces/IPackageManager.cs +++ b/src/isnd/Interfaces/IPackageManager.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Threading.Tasks; using isn.Abstract; using isnd.Data; @@ -13,11 +14,11 @@ namespace isnd.Interfaces public interface IPackageManager { string CatalogBaseUrl { get; } - AutoCompleteResult AutoComplete(string pkgid, int skip, int take, bool prerelease = false, string packageType = null); + AutoCompleteResult AutoComplete(string pkgid, int skip=0, int take=25, bool prerelease = false, string packageType = null); string[] GetVersions(string pkgid, NuGetVersion parsedVersion, bool prerelease = false, string packageType = null, int skip = 0, int take = 25); IEnumerable GetResources(); - Task ÛpdateCatalogForAsync(Commit commit); + Task UpdateCatalogForAsync(Commit commit); Task DeletePackageAsync(string pkgid, string version, string type); Task UserAskForPackageDeletionAsync(string userid, string pkgId, string lower, string type); Task GetPackageAsync(string pkgid, string version, string type); @@ -28,6 +29,8 @@ namespace isnd.Interfaces Task GetPackageRegistrationIndexAsync(PackageRegistrationQuery query); Task SearchPackageAsync(PackageRegistrationQuery query); + + Task PutPackageAsync(Stream packageStream, string ownerId); } } \ No newline at end of file diff --git a/src/isnd/Migrations/20240318003218_dependencies.Designer.cs b/src/isnd/Migrations/20240318003218_dependencies.Designer.cs new file mode 100644 index 0000000..4cda935 --- /dev/null +++ b/src/isnd/Migrations/20240318003218_dependencies.Designer.cs @@ -0,0 +1,529 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using isnd.Data; + +#nullable disable + +namespace isnd.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20240318003218_dependencies")] + partial class dependencies + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.Property("ValidityPeriodInDays") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("isnd.Data.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FullName") + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("isnd.Data.Dependency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("DependencyGroupId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Exclude") + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("DependencyGroupId"); + + b.ToTable("Depedencies"); + }); + + modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("PackageVersionFullString") + .HasColumnType("character varying(256)"); + + b.Property("PackageVersionId") + .IsRequired() + .HasColumnType("text"); + + b.Property("PackageVersionPackageId") + .HasColumnType("character varying(1024)"); + + b.Property("TargetFramework") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("PackageVersionPackageId", "PackageVersionFullString"); + + b.ToTable("PackageDependencyGroups"); + }); + + modelBuilder.Entity("isnd.Data.PackageVersion", b => + { + b.Property("PackageId") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("FullString") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("CommitNId") + .HasColumnType("bigint"); + + b.Property("IsPrerelease") + .HasColumnType("boolean"); + + b.Property("Major") + .HasColumnType("integer"); + + b.Property("Minor") + .HasColumnType("integer"); + + b.Property("Patch") + .HasColumnType("integer"); + + b.Property("Revision") + .HasColumnType("integer"); + + b.Property("Type") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("PackageId", "FullString"); + + b.HasIndex("CommitNId"); + + b.ToTable("PackageVersions"); + }); + + modelBuilder.Entity("isnd.Data.Packages.Commit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("integer"); + + b.Property("TimeStamp") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Commits"); + }); + + modelBuilder.Entity("isnd.Data.Packages.Package", b => + { + b.Property("Id") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("CommitNId") + .HasColumnType("bigint"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("OwnerId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Public") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("CommitNId"); + + b.HasIndex("OwnerId"); + + b.ToTable("Packages"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("isnd.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("isnd.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("isnd.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("isnd.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b => + { + b.HasOne("isnd.Data.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("isnd.Data.Dependency", b => + { + b.HasOne("isnd.Data.PackageDependencyGroup", "Group") + .WithMany("Dependencies") + .HasForeignKey("DependencyGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b => + { + b.HasOne("isnd.Data.PackageVersion", null) + .WithMany("DependencyGroups") + .HasForeignKey("PackageVersionPackageId", "PackageVersionFullString"); + }); + + modelBuilder.Entity("isnd.Data.PackageVersion", b => + { + b.HasOne("isnd.Data.Packages.Commit", "LatestCommit") + .WithMany("Versions") + .HasForeignKey("CommitNId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("isnd.Data.Packages.Package", "Package") + .WithMany("Versions") + .HasForeignKey("PackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LatestCommit"); + + b.Navigation("Package"); + }); + + modelBuilder.Entity("isnd.Data.Packages.Package", b => + { + b.HasOne("isnd.Data.Packages.Commit", "LatestCommit") + .WithMany() + .HasForeignKey("CommitNId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("isnd.Data.ApplicationUser", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LatestCommit"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b => + { + b.Navigation("Dependencies"); + }); + + modelBuilder.Entity("isnd.Data.PackageVersion", b => + { + b.Navigation("DependencyGroups"); + }); + + modelBuilder.Entity("isnd.Data.Packages.Commit", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("isnd.Data.Packages.Package", b => + { + b.Navigation("Versions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/isnd/Migrations/20240318003218_dependencies.cs b/src/isnd/Migrations/20240318003218_dependencies.cs new file mode 100644 index 0000000..e28ec25 --- /dev/null +++ b/src/isnd/Migrations/20240318003218_dependencies.cs @@ -0,0 +1,74 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace isnd.Migrations +{ + /// + public partial class dependencies : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "PackageDependencyGroups", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + PackageVersionId = table.Column(type: "text", nullable: false), + TargetFramework = table.Column(type: "text", nullable: true), + PackageVersionFullString = table.Column(type: "character varying(256)", nullable: true), + PackageVersionPackageId = table.Column(type: "character varying(1024)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_PackageDependencyGroups", x => x.Id); + table.ForeignKey( + name: "FK_PackageDependencyGroups_PackageVersions_PackageVersionPacka~", + columns: x => new { x.PackageVersionPackageId, x.PackageVersionFullString }, + principalTable: "PackageVersions", + principalColumns: new[] { "PackageId", "FullString" }); + }); + + migrationBuilder.CreateTable( + name: "Depedencies", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + DependencyGroupId = table.Column(type: "text", nullable: false), + Version = table.Column(type: "text", nullable: true), + Exclude = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Depedencies", x => x.Id); + table.ForeignKey( + name: "FK_Depedencies_PackageDependencyGroups_DependencyGroupId", + column: x => x.DependencyGroupId, + principalTable: "PackageDependencyGroups", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Depedencies_DependencyGroupId", + table: "Depedencies", + column: "DependencyGroupId"); + + migrationBuilder.CreateIndex( + name: "IX_PackageDependencyGroups_PackageVersionPackageId_PackageVers~", + table: "PackageDependencyGroups", + columns: new[] { "PackageVersionPackageId", "PackageVersionFullString" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Depedencies"); + + migrationBuilder.DropTable( + name: "PackageDependencyGroups"); + } + } +} diff --git a/src/isnd/Migrations/ApplicationDbContextModelSnapshot.cs b/src/isnd/Migrations/ApplicationDbContextModelSnapshot.cs index 9d2f708..21346d0 100644 --- a/src/isnd/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/src/isnd/Migrations/ApplicationDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace isnd.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "7.0.4") + .HasAnnotation("ProductVersion", "8.0.3") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -247,6 +247,55 @@ namespace isnd.Migrations b.ToTable("AspNetUsers", (string)null); }); + modelBuilder.Entity("isnd.Data.Dependency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("DependencyGroupId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Exclude") + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("DependencyGroupId"); + + b.ToTable("Depedencies"); + }); + + modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("PackageVersionFullString") + .HasColumnType("character varying(256)"); + + b.Property("PackageVersionId") + .IsRequired() + .HasColumnType("text"); + + b.Property("PackageVersionPackageId") + .HasColumnType("character varying(1024)"); + + b.Property("TargetFramework") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("PackageVersionPackageId", "PackageVersionFullString"); + + b.ToTable("PackageDependencyGroups"); + }); + modelBuilder.Entity("isnd.Data.PackageVersion", b => { b.Property("PackageId") @@ -396,6 +445,24 @@ namespace isnd.Migrations b.Navigation("User"); }); + modelBuilder.Entity("isnd.Data.Dependency", b => + { + b.HasOne("isnd.Data.PackageDependencyGroup", "Group") + .WithMany("Dependencies") + .HasForeignKey("DependencyGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b => + { + b.HasOne("isnd.Data.PackageVersion", null) + .WithMany("DependencyGroups") + .HasForeignKey("PackageVersionPackageId", "PackageVersionFullString"); + }); + modelBuilder.Entity("isnd.Data.PackageVersion", b => { b.HasOne("isnd.Data.Packages.Commit", "LatestCommit") @@ -434,6 +501,16 @@ namespace isnd.Migrations b.Navigation("Owner"); }); + modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b => + { + b.Navigation("Dependencies"); + }); + + modelBuilder.Entity("isnd.Data.PackageVersion", b => + { + b.Navigation("DependencyGroups"); + }); + modelBuilder.Entity("isnd.Data.Packages.Commit", b => { b.Navigation("Versions"); diff --git a/src/isnd/Services/InvalidPackageException.cs b/src/isnd/Services/InvalidPackageException.cs new file mode 100644 index 0000000..5b3328c --- /dev/null +++ b/src/isnd/Services/InvalidPackageException.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.Serialization; + +namespace isnd.Services +{ + [Serializable] + internal class InvalidPackageException : InvalidOperationException + { + public InvalidPackageException() + { + } + + public InvalidPackageException(string message) : base(message) + { + } + + public InvalidPackageException(string message, Exception innerException) : base(message, innerException) + { + } + + protected InvalidPackageException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/src/isnd/Services/PackageManager.cs b/src/isnd/Services/PackageManager.cs index 75ea63f..0f236f0 100644 --- a/src/isnd/Services/PackageManager.cs +++ b/src/isnd/Services/PackageManager.cs @@ -1,18 +1,26 @@ using System; using System.Collections.Generic; +using System.IO; +using System.IO.Compression; using System.Linq; +using System.Text; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; using isn.abst; using isn.Abstract; using isnd.Data; using isnd.Data.Catalog; using isnd.Data.Packages; using isnd.Entities; +using isnd.Helpers; using isnd.Interfaces; using isnd.ViewModels; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Options; +using NuGet.Packaging.Core; using NuGet.Versioning; +using System.Xml; +using System.Xml.Linq; +using System.Threading; namespace isnd.Services { @@ -31,7 +39,7 @@ namespace isnd.Services public IEnumerable GetResources() { - + var res = new List { new Resource(apiBase + ApiConfig.Package, @@ -46,7 +54,7 @@ namespace isnd.Services { Comment = "URI template used by NuGet Client to construct details URL for packages" }, - + new Resource(apiBase + ApiConfig.Content, "PackageBaseAddress/3.0.0") { @@ -61,11 +69,26 @@ namespace isnd.Services Comment = "Auto complete service" }, + new Resource(apiBase + ApiConfig.Search, + "SearchQueryService") + { + Comment = "Query endpoint of NuGet Search service (primary) used by RC clients" + }, + new Resource(apiBase + ApiConfig.Search, + "SearchQueryService/3.0.0-beta") + { + Comment = "Query endpoint of NuGet Search service (primary) used by RC clients" + }, new Resource(apiBase + ApiConfig.Search, "SearchQueryService/3.0.0-rc") { Comment = "Query endpoint of NuGet Search service (primary) used by RC clients" }, + new Resource(apiBase + ApiConfig.Search, + "SearchQueryService/3.5.0") + { + Comment = "Query endpoint of NuGet Search service (primary) used by RC clients" + }, new Resource(apiBase + ApiConfig.Registration, "RegistrationsBaseUrl/Versioned") @@ -107,7 +130,7 @@ namespace isnd.Services v => v.PackageId == id && (prerelease || !v.IsPrerelease) && (packageType == null || v.Type == packageType) - && (parsedVersion==null || parsedVersion.CompareTo + && (parsedVersion == null || parsedVersion.CompareTo (new SemanticVersion(v.Major, v.Minor, v.Patch)) < 0) ) .OrderBy(v => v.NugetVersion) @@ -115,8 +138,6 @@ namespace isnd.Services .Skip(skip).Take(take).ToArray(); } - - public string CatalogBaseUrl => apiBase; private IsndSettings isndSettings; @@ -124,17 +145,17 @@ namespace isnd.Services public virtual async Task GetCatalogIndexAsync() { - return await ÛpdateCatalogForAsync(null); + return await UpdateCatalogForAsync(null); } - public async Task ÛpdateCatalogForAsync + public async Task UpdateCatalogForAsync (Commit reason = null) { int i = 0; - string baseid = apiBase + ApiConfig.Catalog; - string bidreg = $"{apiBase}{ApiConfig.Registration}"; - PackageRegistration index = new PackageRegistration(baseid); + string baseId = apiBase + ApiConfig.Catalog; + string baseRegistrationId = $"{apiBase}{ApiConfig.Registration}"; + PackageRegistration index = new PackageRegistration(baseId); var scope = await dbContext.Commits.OrderBy(c => c.TimeStamp).ToArrayAsync(); @@ -149,21 +170,21 @@ namespace isnd.Services .Include(pkg => pkg.LatestCommit) .ToArrayAsync()) .GroupBy((q) => q.Id); - - foreach (var pkgid in validPkgs) + + foreach (var pkgIdGroup in validPkgs) { CatalogPage page = index.Items.FirstOrDefault - (p => p.GetPackageId() == pkgid.Key); + (p => p.GetPackageId() == pkgIdGroup.Key); if (page == null) { - page = new CatalogPage(pkgid.Key, apiBase); + page = new CatalogPage(pkgIdGroup.Key, apiBase); index.Items.Add(page); } - foreach (var pkgv in pkgid) + foreach (var package in pkgIdGroup) { - page.AddVersionRange(pkgv.Versions); + page.AddVersionRange(package.Versions); } } reason = commit; @@ -173,7 +194,7 @@ namespace isnd.Services } public async Task DeletePackageAsync - (string pkgid, string version, string type) + (string pkgId, string version, string type) { // TODO deletion on disk var commit = new Commit @@ -183,7 +204,7 @@ namespace isnd.Services }; dbContext.Commits.Add(commit); var pkg = await dbContext.PackageVersions.SingleOrDefaultAsync( - v => v.PackageId == pkgid && + v => v.PackageId == pkgId && v.FullString == version && v.Type == type ); @@ -193,15 +214,15 @@ namespace isnd.Services } dbContext.PackageVersions.Remove(pkg); await dbContext.SaveChangesAsync(); - await ÛpdateCatalogForAsync(commit); + await UpdateCatalogForAsync(commit); return new PackageDeletionReport { Deleted = true, DeletedVersion = pkg }; } public async Task GetPackageAsync - (string pkgid, string version, string type) + (string pkgId, string version, string type) { return await dbContext.PackageVersions.SingleOrDefaultAsync( - v => v.PackageId == pkgid && + v => v.PackageId == pkgId && v.FullString == version && v.Type == type ); @@ -215,9 +236,9 @@ namespace isnd.Services .Include(v => v.Package.LatestCommit) .Include(v => v.Package.Owner) .Include(v => v.LatestCommit) - .Where(v => v.PackageId == pkgId - && v.FullString == semver - && v.LatestCommit !=null + .Where(v => v.PackageId == pkgId + && v.FullString == semver + && v.LatestCommit != null ).SingleOrDefaultAsync()).ToPackage( apiBase); } @@ -238,12 +259,13 @@ namespace isnd.Services public IEnumerable SearchCatalogEntriesById (string pkgId, string semver, string pkgType, bool preRelease) { - + // PackageDependency return dbContext.PackageVersions .Include(v => v.Package) .Include(v => v.Package.Owner) .Include(v => v.Package.LatestCommit) .Include(v => v.LatestCommit) + .Include(v => v.DependencyGroups) .Where(v => v.PackageId == pkgId && semver == v.FullString && (pkgType == null || pkgType == v.Type) && (preRelease || !v.IsPrerelease)) @@ -271,21 +293,21 @@ namespace isnd.Services .Include(p => p.Owner) .Include(p => p.LatestCommit) .SingleOrDefaultAsync(p => p.Id.ToLower() == query.Query); - if (scope==null) return null; - if (scope.Versions.Count==0) return null; + if (scope == null) return null; + if (scope.Versions.Count == 0) return null; string bid = $"{apiBase}{ApiConfig.Registration}"; foreach (var version in scope.Versions) - version.LatestCommit = dbContext.Commits.Single(c=>c.Id == version.CommitNId); + version.LatestCommit = dbContext.Commits.Single(c => c.Id == version.CommitNId); return new PackageRegistration(apiBase, scope); } - + public async Task SearchPackageAsync(PackageRegistrationQuery query) { string bid = $"{apiBase}{ApiConfig.Registration}"; - if (string.IsNullOrWhiteSpace(query.Query)) - query.Query=""; - var scope = dbContext.Packages + if (string.IsNullOrWhiteSpace(query.Query)) + query.Query = ""; + var scope = dbContext.Packages .Include(p => p.Owner) .Include(p => p.Versions) .Include(p => p.LatestCommit) @@ -293,11 +315,155 @@ namespace isnd.Services .Where(p => p.Id.StartsWith(query.Query) && p.LatestCommit != null && (query.Prerelease || p.Versions.Any(p => !p.IsPrerelease)) - && p.Versions.Count()>0) + && p.Versions.Count() > 0) .OrderBy(p => p.CommitNId); return new PackageSearchResult(await scope.Skip(query.Skip).Take(query.Take) .ToListAsync(), apiBase, scope.Count()); } + + public async Task PutPackageAsync(Stream packageStream, string ownerId) + { + PackageVersion version = null; + using (packageStream) + { + using (var archive = new ZipArchive(packageStream)) + { + var spec = archive.Entries.FirstOrDefault(e => e.FullName.EndsWith("." + Constants.SpecFileExtension)); + if (spec == null) throw new InvalidPackageException("no " + Constants.SpecFileExtension + " from archive"); + string pkgPath; + NuGetVersion nugetVersion; + string pkgId; + string fullPath; + + using var specificationStream = spec.Open(); + + using XmlReader xmlReader = XmlReader.Create(specificationStream); + + var xMeta = XElement.Load(xmlReader, LoadOptions.None).Descendants().First(); + + string packageDescription = xMeta.Descendants().FirstOrDefault(x => x.Name.LocalName == "description")?.Value; + + var frameWorks = xMeta + .Descendants().FirstOrDefault(x => x.Name.LocalName =="frameworkReferences") + .Descendants().Where(x => x.Name.LocalName =="group") + .Select(x=> x.Attribute("targetFramework").Value).ToArray(); + var types = "Package"; + + pkgId = xMeta.Descendants().FirstOrDefault(x => x.Name.LocalName =="id")?.Value; + string pkgVersion = xMeta.Descendants().FirstOrDefault(x => x.Name.LocalName =="version")?.Value; + + if (!NuGetVersion.TryParse(pkgVersion, out nugetVersion)) + throw new InvalidPackageException("metadata/version"); + + var frameworkReferences = frameWorks.Select(g => new PackageDependencyGroup + { + TargetFramework = g + } + ).ToList(); + + string packageIdPath = Path.Combine(isndSettings.PackagesRootDir, + pkgId); + pkgPath = Path.Combine(packageIdPath, nugetVersion.ToFullString()); + string name = $"{pkgId}-{nugetVersion}." + Constants.PacketFileExtension; + fullPath = Path.Combine(pkgPath, name); + + var packageIdPathInfo = new DirectoryInfo(packageIdPath); + Data.Packages.Package pkg = dbContext.Packages.SingleOrDefault(p => p.Id == pkgId); + Commit commit = new Commit + { + Action = PackageAction.PublishPackage, + TimeStamp = DateTimeOffset.Now.ToUniversalTime() + }; + if (pkg != null) + { + // Update + pkg.Description = packageDescription; + pkg.LatestCommit = commit; + } + else + { + // First version + pkg = new Data.Packages.Package + { + Id = pkgId, + Description = packageDescription, + OwnerId = ownerId, + LatestCommit = commit + }; + dbContext.Packages.Add(pkg); + } + + // here, the package is or new, or owned by the key owner + if (!packageIdPathInfo.Exists) packageIdPathInfo.Create(); + + var dest = new FileInfo(fullPath); + var destDir = new DirectoryInfo(dest.DirectoryName); + if (dest.Exists) dest.Delete(); + if (!destDir.Exists) destDir.Create(); + + packageStream.Seek(0, SeekOrigin.Begin); + using (var fileStream = File.Create(fullPath)) + { + await packageStream.CopyToAsync(fileStream); + } + + string fullStringVersion = nugetVersion.ToFullString(); + var pkgVersions = dbContext.PackageVersions.Where + (v => v.PackageId == pkg.Id && v.FullString == fullStringVersion); + if (pkgVersions.Count() > 0) + { + foreach (var v in pkgVersions.ToArray()) + dbContext.PackageVersions.Remove(v); + } + + // FIXME default type or null + dbContext.PackageVersions.Add + (version = new PackageVersion + { + + Package = pkg, + Major = nugetVersion.Major, + Minor = nugetVersion.Minor, + Patch = nugetVersion.Patch, + Revision = nugetVersion.Revision, + IsPrerelease = nugetVersion.IsPrerelease, + FullString = nugetVersion.ToFullString(), + Type =types, + LatestCommit = commit + }); + + dbContext.Commits.Add(commit); + + await dbContext.SaveChangesAsync(); + version.DependencyGroups = frameworkReferences; + await UpdateCatalogForAsync(commit); + + + using (var shaCrypto = System.Security.Cryptography.SHA512.Create()) + { + using (var stream = System.IO.File.OpenRead(fullPath)) + { + var hash = shaCrypto.ComputeHash(stream); + var shaFullName = fullPath + ".sha512"; + var hashText = Convert.ToBase64String(hash); + var hashTextBytes = Encoding.ASCII.GetBytes(hashText); + + using (var shaFile = System.IO.File.OpenWrite(shaFullName)) + { + shaFile.Write(hashTextBytes, 0, hashTextBytes.Length); + } + } + } + string nugetSpecificationFullPath = Path.Combine(pkgPath, pkgId + "." + Constants.SpecFileExtension); + FileInfo nugetSpecificationFullPathInfo = new(nugetSpecificationFullPath); + + if (nugetSpecificationFullPathInfo.Exists) + nugetSpecificationFullPathInfo.Delete(); + spec.ExtractToFile(nugetSpecificationFullPath); + } + } + return version; + } } } \ No newline at end of file diff --git a/src/isnd/isnd.csproj b/src/isnd/isnd.csproj index 9f90aa9..f239c1c 100644 --- a/src/isnd/isnd.csproj +++ b/src/isnd/isnd.csproj @@ -1,6 +1,6 @@  - net7.0 + net8.0 85fd766d-5d23-4476-aed1-463b2942e86a true WTFPL @@ -13,31 +13,30 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + - - - - + + + + - - - + + All - + diff --git a/test/data/test-isn/urls b/test/data/test-isn/urls index d9c31a5..3d692c0 100644 --- a/test/data/test-isn/urls +++ b/test/data/test-isn/urls @@ -2,3 +2,9 @@ https://api.nuget.org/v3/registration5-gz-semver2/yavsc.abstract/index.json https://api.nuget.org/v3/catalog0/data/2019.09.17.10.18.17/yavsc.abstract.1.0.6-rc07.json http://localhost:5000/v3/index http://localhost:5000/v3/registration/isn.abst/index.json +https://isn.pschneider.fr/v3/registration5-gz-semver2/isn.abst/index.json +https://isn.pschneider.fr/v3/content/isn.abst/index.json +http://localhost:5000/v3/registration5-gz-semver2/isn.abst/index.json +http://localhost:5000/v3/registration/isn.abst/index.json +http://localhost:5000/v3/content/isn.abst/index.json + diff --git a/test/isn.tests/PushTest.cs b/test/isn.tests/PushTest.cs index 0d2838a..b8e310c 100644 --- a/test/isn.tests/PushTest.cs +++ b/test/isn.tests/PushTest.cs @@ -1,12 +1,12 @@ using System; using System.Net.Http; - using System.Threading.Tasks; using Newtonsoft.Json; using isn.Abstract; using System.Linq; using Xunit; using isn.abst; +using System.Security.Cryptography; namespace isn.tests { @@ -42,6 +42,18 @@ namespace isn.tests var pub = model.Resources.FirstOrDefault((r) => r.Type.StartsWith("PackagePublish/")); Assert.True(pub != null); } + [Fact] + public void TestSetApiKey() + { + string source = "http://localhost:3002/v3/index.json"; + + var setting = Settings.Create(); + setting.Sources[source] = new SourceSettings{ Url=source }; + string testingKey = "CfDJ8LF3SbIJ4FJAgs7uIQKhdCAYCNVXRwU6TEoaXOo1_ZpG2u8TCGFP2z13hw9xR0LC0gdbr1QGwNndiXUl4DI74nxyBi-T1oC33PWtE-5vgiJWeCH223PYtoSEdzDiWovwJZWJbQON0WqoG8vSfbrBXTmicD6oxF4ghwXXexY0RiRR"; + var rsa = RSA.Create(setting.RSAParameters); + setting.Sources[source].SetApiKey(rsa,testingKey); + Assert.Equal(testingKey, setting.Sources[source].GetClearApiKey(rsa)); + } } } \ No newline at end of file diff --git a/test/isn.tests/isn.tests.csproj b/test/isn.tests/isn.tests.csproj index 0c09b72..34f6b0a 100644 --- a/test/isn.tests/isn.tests.csproj +++ b/test/isn.tests/isn.tests.csproj @@ -1,6 +1,6 @@  - net7.0 + net8.0 false NETSDK1138 1.0.7.0 @@ -9,12 +9,13 @@ 1.0.7 - - + + - - - + + + + diff --git a/test/isnd.tests/UnitTestWebHost.cs b/test/isnd.tests/UnitTestWebHost.cs index 7343446..6881211 100644 --- a/test/isnd.tests/UnitTestWebHost.cs +++ b/test/isnd.tests/UnitTestWebHost.cs @@ -151,10 +151,9 @@ namespace isnd.host.tests { ILogger logger = new TestLogger(); CancellationToken cancellationToken = CancellationToken.None; - SourceRepository repository = Repository.Factory.GetCoreV3(SPIIndexURI); repository.PackageSource.AllowInsecureConnections=true; - + PackageSearchResource resource = await repository.GetResourceAsync(); SearchFilter searchFilter = new SearchFilter(includePrerelease: true); @@ -184,6 +183,15 @@ namespace isnd.host.tests await pushRes.Push(new List{ "../../../../../src/isnd/bin/Release/isnd.1.1.4.nupkg" }, null, 5000, false, GetApiKey, GetSymbolsApiKey, false, false, symbolPackageResource, logger); } + + [Fact] + public void TestDepedency() + { + PackageDependencyGroup g = new PackageDependencyGroup + { + TargetFramework="net7.0" + }; + } private string GetSymbolsApiKey(string apiUrl) { diff --git a/test/isnd.tests/isnd.tests.csproj b/test/isnd.tests/isnd.tests.csproj index 29c5b3d..35e64e5 100644 --- a/test/isnd.tests/isnd.tests.csproj +++ b/test/isnd.tests/isnd.tests.csproj @@ -1,6 +1,6 @@  - net7.0 + net8.0 false d7144e46-4e63-4391-ba86-64b61f6e7be4 NETSDK1138 @@ -12,10 +12,10 @@ - + - - + +