No release yet

main
Paul Schneider 1 year ago
parent 3b7e286a5b
commit 58d1f26701
380 changed files with 69597 additions and 20486 deletions

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<project name="Isn" default="clean" basedir=".">
<description>The Hello World of build files.</description>
<property name="debug" value="true" overwrite="false" />
<target name="clean" description="remove all generated files">
<delete dir="src/isn.abst/bin/" failonerror="false" />
<delete dir="src/isn.abst/obj/" failonerror="false" />
<delete dir="src/isn/bin/" failonerror="false" />
<delete dir="src/isn/obj/" failonerror="false" />
<delete dir="src/isnd/bin/" failonerror="false" />
<delete dir="src/isnd/obj/" failonerror="false" />
<delete dir="test/isn.tests/bin/" failonerror="false" />
<delete dir="test/isn.tests/obj/" failonerror="false" />
<delete dir="test/isnd.tests/bin/" failonerror="false" />
<delete dir="test/isnd.tests/obj/" failonerror="false" />
</target>
<target name="build" description="build all">
<exec program="dotnet" commandline="build" />
</target>
<target name="test" description="test all">
<exec program="dotnet" commandline="test" />
</target>
</project>

27
.gitignore vendored

@ -1,3 +1,26 @@
.sass-cache/
/src/isnd/bin/
/src/isnd/obj/
/src/isn/obj
/src/isn/bin
/src/isn/.vscode/
/test/isnd.tests/obj/
/test/isnd.tests/bin/
/packages/
/bin/
/obj/
bower_components/
/test/isn.tests/bin
/test/isn.tests/obj/
appsettings.Testing.json
appsettings.Development.json
/wwwroot/.sass-cache/
/src/isnd/wwwroot/.sass-cache/
/src/isn.abst/bin
/src/isn.abst/obj
/src/isnd/packages/
/test/data/test-isn/bin/
/test/data/test-isn/obj
.fake
/artifacts/
/.vs/
/.vscode/

@ -0,0 +1,66 @@
# You can override the included template(s) by including variable overrides
# See https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
# Note that environment variables can be set in several places
# See https://docs.gitlab.com/ee/ci/variables/#priority-of-environment-variables
image: busybox:latest
before_script:
- dotnet restore
- dotnet nuget remove source gitlab || true
nonreg:
tags:
- dotnet
stage: test
environment: Development
script:
- |
echo "setting : $ISND_TESTING_SETTINGS"
dotnet build
cat $ISND_TESTING_SETTINGS > test/isnd.tests/appsettings.json
dotnet test
publish:
tags:
- dotnet
stage: deploy
dependencies:
- nonreg
artifacts:
paths:
- src/isnd/bin/Release/netcoreapp2.1/publish/
when: always
script:
- dotnet publish --configuration Release
deploy-to-gitlab:
tags:
- dotnet
stage: deploy
dependencies:
- nonreg
artifacts:
paths:
- src/*/bin/Release/*.nupkg
when: always
script:
- dotnet pack -c Release
- dotnet nuget add source --name gitlab --username gitlab+deploy-token-2 --password
$CI_JOB_TOKEN --store-password-in-clear-text "$CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/packages/nuget/index.json"
- dotnet nuget push src/*/bin/Release/*.nupkg -s gitlab
deploy-to-isn:
stage: deploy
tags:
- dotnet
artifacts:
paths:
- src/*/bin/Release/*.nupkg
when: always
script:
- dotnet pack --configuration Release --no-restore
- cd src/isn
- find -name "*.nupkg" -exec dotnet run push -s $ISNSOURCE -k $ISNAPIKEY {} \;
environment:
name: production
url: $ISNSOURCE
dependencies:
- nonreg
stages:
- test
- deploy

@ -1,29 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/bin/Debug/netcoreapp2.0/nuget-host.dll",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"OS-COMMENT5": "Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser",
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\\\bNow listening on:\\\\s+(https?://\\\\S+)"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Views"
}
}
]
}

96
.vscode/tasks.json vendored

@ -1,50 +1,126 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "restore",
"command": "dotnet",
"type": "process",
"args": [
"restore",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"--ignore-failed-sources"
],
"problemMatcher": "$msCompile"
},
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/nuget-host.csproj",
"/p:Configuration=Debug",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"label": "db-upgrade",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/nuget-host.csproj",
"ef",
"database",
"update"
],
"problemMatcher": "$msCompile",
"options": {
"cwd": "${workspaceFolder}/src/isnd",
"env": {
"ASPNETCORE_ENV": "Development"
}
}
},
{
"label": "buildcli",
"command": "msbuild",
"type": "process",
"args": [
"src/isn",
"/p:Configuration=Debug",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
"/consoleloggerparameters:NoSummary",
"/restore"
],
"problemMatcher": "$msCompile"
},
{
"label": "launch-dotnet",
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"${workspaceFolder}/bin/Debug/netcoreapp2.0/nuget-host.dll"
"publish",
"/p:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"/p:TargetFramework=netcoreapp2.1",
"/p:RuntimeIdentifier=linux-x64",
"/p:PublishDir=${workspaceFolder}/artifacts"
],
"problemMatcher": "$msCompile",
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "monopublish",
"command": "msbuild",
"type": "process",
"args": [
"/t:publish",
"/p:TargetFramework=netcoreapp2.1;PublishDir=${workspaceFolder}/artiffacts;RuntimeIdentifier=linux-x64",
],
"problemMatcher": "$msCompile"
},
{
"label": "copyTestConfig",
"command": "dotnet",
"type": "process",
"args": [ "build", "/t:CopyTestConfig" ]
},
{
"label": "test",
"command": "dotnet",
"type": "process",
"options": {
"env": {
"ASPNETCORE_ENVIRONMENT": "Testing"
}
},
"args": [
"test",
"/property:GenerateFullPaths=true",
"--logger:xunit"
],
"problemMatcher": "$msCompile",
"dependsOn": [ "build", "copyTestConfig"]
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"bin/Debug/netcoreapp2.0/nuget-host.dll",
"/property:GenerateFullPaths=true"
"bin/Debug/netcoreapp2.1/isnd.dll",
"/property:GenerateFullPaths=true",
"/restore"
],
"options": {
"env": {
"ASPNETCORE_ENV": "Development"
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"problemMatcher": "$msCompile"

@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using nuget_host.Models;
namespace nuget_host.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
}
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
return View();
}
public IActionResult Test()
{
ViewData["Message"] = "Your contact page.";
return Ok(ViewData);
}
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}

@ -1,113 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using NuGet.Packaging;
namespace nuget_host.Controllers
{
public class PackagesController : Controller
{
private ILogger<PackagesController> logger;
public PackagesController(ILoggerFactory loggerFactory)
{
logger = loggerFactory.CreateLogger<PackagesController>();
}
[HttpPut("packages/{*spec}")]
public IActionResult Put(string spec)
{
string path = null;
if (string.IsNullOrEmpty(spec))
{
var clientVersionId = Request.Headers["X-NuGet-Client-Version"];
ViewData["nuget client "] = "nuget {clientVersionId}";
foreach (var file in Request.Form.Files)
{
string initpath = "package.nupkg";
using (FileStream fw = new FileStream(initpath, FileMode.Create))
{
file.CopyTo(fw);
}
using (FileStream fw = new FileStream(initpath, FileMode.Open))
{
var archive = new System.IO.Compression.ZipArchive(fw);
foreach (var filename in archive.GetFiles())
{
if (filename.EndsWith(".nuspec"))
{
// var entry = archive.GetEntry(filename);
var specstr = archive.OpenFile(filename);
NuspecReader reader = new NuspecReader(specstr);
string pkgdesc = reader.GetDescription();
string pkgid = reader.GetId();
var version = reader.GetVersion();
path = Path.Combine(Startup.SourceDir,
Path.Combine(pkgid,
Path.Combine(version.ToFullString(),
$"{pkgid}-{version}.nupkg")));
var source = new FileInfo(initpath);
var dest = new FileInfo(path);
var destdir = new DirectoryInfo(dest.DirectoryName);
if (dest.Exists)
return BadRequest(new {error = "existant"});
if (!destdir.Exists) destdir.Create();
source.MoveTo(path);
}
}
}
}
}
else
{
ViewData["spec"] = spec;
// TODO Assert valid sem ver spec
var filelst = new DirectoryInfo(Startup.SourceDir);
var fi = new FileInfo(spec);
var lst = filelst.GetFiles(fi.Name + "*.nupkg");
ViewData["lst"] = lst.Select(entry => entry.Name);
}
return Ok(ViewData);
}
[HttpGet("Packages/{spec}")]
public IActionResult Index(string spec)
{
if (string.IsNullOrEmpty(spec))
{
ViewData["warn"] = "no spec";
/*
usr/lib/mono/msbuild/Current/bin/NuGet.targets(128,5): error : Failed to retrieve information about 'Microsoft.VisualStudio.Web.CodeGeneration.Tools' from remote source 'http://localhost:5000/Packages/FindPackagesById()?id='Microsoft.VisualStudio.Web.CodeGeneration.Tools'&semVerLevel=2.0.0'. [/home/paul/workspace/nuget-host/nuget-host.csproj]
*/
}
else
{
ViewData["spec"] = spec;
// TODO Assert valid sem ver spec
var filelst = new DirectoryInfo(Startup.SourceDir);
var fi = new FileInfo(spec);
var lst = filelst.GetDirectories(spec);
ViewData["lst"] = lst.Select(entry => entry.Name);
}
return Ok(ViewData);
}
}
}

@ -0,0 +1,5 @@
mode: Mainline
branches: {}
ignore:
sha: []
merge-message-formats: {}

@ -0,0 +1,14 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

@ -0,0 +1,25 @@
CONFIGURATION=Debug
TARGETFV=net7.0
VERSION=1.0.24
all: build-isn build-isnd
build-%: src/%
dotnet build -p:Configuration=$(CONFIGURATION) $^
pack-%: src/%
dotnet pack $^
watch:
dotnet watch --project=src/isnd
push-%: src/%
isn push $^/bin/$(CONFIGURATION)/$^.$(VERSION).nupkg
clean-%: src/%
rm -rf $^/bin $^/obj
clean: clean-isnd clean-isn clean-isn.abst

@ -1,11 +0,0 @@
using System;
namespace nuget_host.Models
{
public class ErrorViewModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}

@ -1,9 +1,89 @@
# Usage
# ISN
En cours de developement, le détail du paquet n'est toujours pas fourni en API.
## Usage
````sh
nuget sources remove -Name dev
nuget sources add -Name dev -Source Http://localhost:5000/packages
nuget push your-versionned.nupkg -ApiKey 15d0dda1-4028-4896-9f1a-188817da23f4 -Source http://localhost:5000/packages
dotnet user-secrets set ConnectionStrings:DefaultConnection "Server=<lame-pgserver>;Port=<lame-pgport>;Database=<lame-dbname>;Username=<lame-dbusername>;Password=<lame-dbpass>;"
isnd&
# get an api-key from <http://localhost:5000/ApkKeys>
isn push -k <lame-api-key> -s http://localhost:5000/index.json your-lame-versionned.nupkg
wget http://localhost:5000/package/index.json?q=your&prerelease=true&semVerLevel=2.0.0
````
## Installation
### Compilation
Depuis le dossier de la solution, compiler la solution :
````bash
dotnet build /restore -c Release
dotnet publish -c Release
````
### Déploiement du serveur
Commençont par la livraison initiale, aujourd'hui :
````bash
sudo mkdir -p /srv/www/isnd
sudo cp -a src/isnd/bin/Release/net7.0/publish/* /srv/www/isnd
sudo cp contrib/isnd.service /etc/systemd/system
sudo systemctl daemon-reload
````
Une base de donées Postgresql est requise, avec, pour faire simple,
son utilisateur, et le droit de créer des tables (ce dernier droit pourrait expirer, mais gare aux mises à jour).
Il faudra éditer la configuration pour indiquer :
* la connextion à une base de donnée Postresgql, sous la forme :
`"Server=<pgserver>;Port=<pgport>;Database=<dbname>;Username=<dbusername>;Password=<dbpass>;"`
* la connection au serveur de messagerie,
* l'URL du ou des sites à propulser,
* Les autres détails.
Pour faire ceci, vous pourrez éditer une copie du fichier `appsettings.json` vers `appsettings.Production.json`,
pour renseigner toutes les valeurs spécifiées.
* Démarrer le serveur :
````bash
sudo systemctl start isnd
````
* Activation du serveur :
````bash
sudo systemctl enable isnd
````
### Installation du client
````bash
sudo mkdir /usr/local/lib/isn
sudo cp -a src/isn/bin/Release/net6.0/* /usr/local/lib/isn
sudo chown -R root.root /usr/local/lib/isn
sudo ln -s /usr/local/lib/isn/isn /usr/local/bin/isn
````
### Mises à jour
````bash
# compiler tout
dotnet build -c Release
dotnet publish -c Release -f net7.0 src/isnd
# MAJ du serveur
sudo systemctl stop isnd
sudo cp -a src/isnd/bin/Release/net7.0/publish/* /srv/www/isnd
sudo systemctl start isnd
# 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
````

@ -1,54 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace nuget_host
{
public class Startup
{
public Startup(IHostingEnvironment env, IConfiguration config)
{
Configuration = config;
}
public IConfiguration Configuration { get; }
public static string ExternalUrl { get; private set; }
public static string SourceDir { get; private set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
ExternalUrl = Configuration["NuGet:ExternalUrl"];
SourceDir = Configuration["NuGet:SourceDir"];
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}

@ -1,106 +0,0 @@
@{
ViewData["Title"] = "Home Page";
}
<div id="myCarousel" class="carousel slide" data-ride="carousel" data-interval="6000">
<ol class="carousel-indicators">
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
<li data-target="#myCarousel" data-slide-to="1"></li>
<li data-target="#myCarousel" data-slide-to="2"></li>
<li data-target="#myCarousel" data-slide-to="3"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="item active">
<img src="~/images/banner1.svg" alt="ASP.NET" class="img-responsive" />
<div class="carousel-caption" role="option">
<p>
Learn how to build ASP.NET apps that can run anywhere.
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525028&clcid=0x409">
Learn More
</a>
</p>
</div>
</div>
<div class="item">
<img src="~/images/banner2.svg" alt="Visual Studio" class="img-responsive" />
<div class="carousel-caption" role="option">
<p>
There are powerful new features in Visual Studio for building modern web apps.
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525030&clcid=0x409">
Learn More
</a>
</p>
</div>
</div>
<div class="item">
<img src="~/images/banner3.svg" alt="Package Management" class="img-responsive" />
<div class="carousel-caption" role="option">
<p>
Bring in libraries from NuGet and npm, and automate tasks using Grunt or Gulp.
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525029&clcid=0x409">
Learn More
</a>
</p>
</div>
</div>
<div class="item">
<img src="~/images/banner4.svg" alt="Microsoft Azure" class="img-responsive" />
<div class="carousel-caption" role="option">
<p>
Learn how Microsoft's Azure cloud platform allows you to build, deploy, and scale web apps.
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525027&clcid=0x409">
Learn More
</a>
</p>
</div>
</div>
</div>
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
<div class="row">
<div class="col-md-3">
<h2>Application uses</h2>
<ul>
<li>Sample pages using ASP.NET Core MVC</li>
<li>Theming using <a href="https://go.microsoft.com/fwlink/?LinkID=398939">Bootstrap</a></li>
</ul>
</div>
<div class="col-md-3">
<h2>How to</h2>
<ul>
<li><a href="https://go.microsoft.com/fwlink/?LinkID=398600">Add a Controller and View</a></li>
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699315">Manage User Secrets using Secret Manager.</a></li>
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699316">Use logging to log a message.</a></li>
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699317">Add packages using NuGet.</a></li>
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699319">Target development, staging or production environment.</a></li>
</ul>
</div>
<div class="col-md-3">
<h2>Overview</h2>
<ul>
<li><a href="https://go.microsoft.com/fwlink/?LinkId=518008">Conceptual overview of what is ASP.NET Core</a></li>
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699320">Fundamentals of ASP.NET Core such as Startup and middleware.</a></li>
<li><a href="https://go.microsoft.com/fwlink/?LinkId=398602">Working with Data</a></li>
<li><a href="https://go.microsoft.com/fwlink/?LinkId=398603">Security</a></li>
<li><a href="https://go.microsoft.com/fwlink/?LinkID=699321">Client side development</a></li>
<li><a href="https://go.microsoft.com/fwlink/?LinkID=699322">Develop on different platforms</a></li>
<li><a href="https://go.microsoft.com/fwlink/?LinkID=699323">Read more on the documentation site</a></li>
</ul>
</div>
<div class="col-md-3">
<h2>Run &amp; Deploy</h2>
<ul>
<li><a href="https://go.microsoft.com/fwlink/?LinkID=517851">Run your app</a></li>
<li><a href="https://go.microsoft.com/fwlink/?LinkID=517853">Run tools such as EF migrations and more</a></li>
<li><a href="https://go.microsoft.com/fwlink/?LinkID=398609">Publish to Microsoft Azure Web Apps</a></li>
</ul>
</div>
</div>

@ -1,22 +0,0 @@
@model ErrorViewModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>Development environment should not be enabled in deployed applications</strong>, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.
</p>

@ -1,71 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - nuget_host</title>
<environment include="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</environment>
<environment exclude="Development">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">nuget_host</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
</ul>
</div>
</div>
</nav>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>&copy; 2018 - nuget_host</p>
</footer>
</div>
<environment include="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
<environment exclude="Development">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery"
crossorigin="anonymous"
integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQsfRV2a+AfHIi9k8z8l9ggpc8X+Ytst4yBo/hH+8Fk">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
crossorigin="anonymous"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa">
</script>
<script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>
@RenderSection("Scripts", required: false)
</body>
</html>

@ -1,3 +0,0 @@
@using nuget_host
@using nuget_host.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@ -1,6 +0,0 @@
{
"NuGet": {
"ExternalUrl" : "<http://localhost:5000/Packages",
"SourceDir" : "packages"
}
}

@ -1,12 +0,0 @@
{
"NuGet": {
"ExternalUrl" : "<http://your-external.url",
"SourceDir" : "<your-Source-dir>"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}

@ -0,0 +1,28 @@
[Unit]
Description=isnd - a Nuget package repository daemon
After=syslog.target
After=network.target
Wants=postgresql.service
After=postgresql.service
[Service]
RestartSec=5s
Type=simple
User=isn
Group=isn
WorkingDirectory=/srv/www/isnd/
# If using Unix socket: tells systemd to create the /run/gitea folder, which will contain the gitea.sock file
# (manually creating /run/gitea doesn't work, because it would not persist across reboots)
#RuntimeDirectory=gitea
ExecStart=/srv/www/isnd/isnd
Restart=always
Environment=HOME=/srv/www/isnd
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<apikeys>
</apikeys>
<packageSources>
<add key="myIsnDev" value="http://localhost:5000/index.json" protocolVersion="3" />
</packageSources>
</configuration>

@ -0,0 +1,2 @@
nuget install -Verbosity detailed -Source http://localhost:5000/index.json -Prerelease Yavsc.Abstract
nuget locals all -clear

@ -0,0 +1,4 @@
= URL's
<http://localhost:5000/v3.4.0/registration/yavsc.abstract/index.json>

@ -0,0 +1,30 @@
{
"version": 1,
"isRoot": true,
"tools": {
"codecov.tool": {
"version": "1.13.0",
"commands": [
"codecov"
]
},
"gitversion.tool": {
"version": "5.10.1",
"commands": [
"dotnet-gitversion"
]
},
"gitreleasemanager.tool": {
"version": "0.13.0",
"commands": [
"dotnet-gitreleasemanager"
]
},
"Wyam2.Tool": {
"version": "3.0.0-rc3",
"commands": [
"wyam2"
]
}
}
}

@ -0,0 +1,101 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.6.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{3C312E42-9A47-4BED-8265-A405FCA6AFFF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "isnd.tests", "test\isnd.tests\isnd.tests.csproj", "{9D758F00-17FF-433D-B088-F9C2D97C9BD1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E8A2DF68-847A-4D88-B002-64FB666F696C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "isnd", "src\isnd\isnd.csproj", "{468DB0E4-6221-4E01-BEFF-F452865E59C1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "isn", "src\isn\isn.csproj", "{910E800A-59AE-46C4-B7C7-879986179246}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "isn.tests", "test\isn.tests\isn.tests.csproj", "{305F640E-11BA-44F9-95E0-C6882E9CD151}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "isn.abst", "src\isn.abst\isn.abst.csproj", "{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9D758F00-17FF-433D-B088-F9C2D97C9BD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D758F00-17FF-433D-B088-F9C2D97C9BD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D758F00-17FF-433D-B088-F9C2D97C9BD1}.Debug|x64.ActiveCfg = Debug|Any CPU
{9D758F00-17FF-433D-B088-F9C2D97C9BD1}.Debug|x64.Build.0 = Debug|Any CPU
{9D758F00-17FF-433D-B088-F9C2D97C9BD1}.Debug|x86.ActiveCfg = Debug|Any CPU
{9D758F00-17FF-433D-B088-F9C2D97C9BD1}.Debug|x86.Build.0 = Debug|Any CPU
{9D758F00-17FF-433D-B088-F9C2D97C9BD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D758F00-17FF-433D-B088-F9C2D97C9BD1}.Release|Any CPU.Build.0 = Release|Any CPU
{9D758F00-17FF-433D-B088-F9C2D97C9BD1}.Release|x64.ActiveCfg = Release|Any CPU
{9D758F00-17FF-433D-B088-F9C2D97C9BD1}.Release|x64.Build.0 = Release|Any CPU
{9D758F00-17FF-433D-B088-F9C2D97C9BD1}.Release|x86.ActiveCfg = Release|Any CPU
{9D758F00-17FF-433D-B088-F9C2D97C9BD1}.Release|x86.Build.0 = Release|Any CPU
{468DB0E4-6221-4E01-BEFF-F452865E59C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{468DB0E4-6221-4E01-BEFF-F452865E59C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{468DB0E4-6221-4E01-BEFF-F452865E59C1}.Debug|x64.ActiveCfg = Debug|Any CPU
{468DB0E4-6221-4E01-BEFF-F452865E59C1}.Debug|x64.Build.0 = Debug|Any CPU
{468DB0E4-6221-4E01-BEFF-F452865E59C1}.Debug|x86.ActiveCfg = Debug|Any CPU
{468DB0E4-6221-4E01-BEFF-F452865E59C1}.Debug|x86.Build.0 = Debug|Any CPU
{468DB0E4-6221-4E01-BEFF-F452865E59C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{468DB0E4-6221-4E01-BEFF-F452865E59C1}.Release|Any CPU.Build.0 = Release|Any CPU
{468DB0E4-6221-4E01-BEFF-F452865E59C1}.Release|x64.ActiveCfg = Release|Any CPU
{468DB0E4-6221-4E01-BEFF-F452865E59C1}.Release|x64.Build.0 = Release|Any CPU
{468DB0E4-6221-4E01-BEFF-F452865E59C1}.Release|x86.ActiveCfg = Release|Any CPU
{468DB0E4-6221-4E01-BEFF-F452865E59C1}.Release|x86.Build.0 = Release|Any CPU
{910E800A-59AE-46C4-B7C7-879986179246}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{910E800A-59AE-46C4-B7C7-879986179246}.Debug|Any CPU.Build.0 = Debug|Any CPU
{910E800A-59AE-46C4-B7C7-879986179246}.Debug|x64.ActiveCfg = Debug|Any CPU
{910E800A-59AE-46C4-B7C7-879986179246}.Debug|x64.Build.0 = Debug|Any CPU
{910E800A-59AE-46C4-B7C7-879986179246}.Debug|x86.ActiveCfg = Debug|Any CPU
{910E800A-59AE-46C4-B7C7-879986179246}.Debug|x86.Build.0 = Debug|Any CPU
{910E800A-59AE-46C4-B7C7-879986179246}.Release|Any CPU.ActiveCfg = Release|Any CPU
{910E800A-59AE-46C4-B7C7-879986179246}.Release|Any CPU.Build.0 = Release|Any CPU
{910E800A-59AE-46C4-B7C7-879986179246}.Release|x64.ActiveCfg = Release|Any CPU
{910E800A-59AE-46C4-B7C7-879986179246}.Release|x64.Build.0 = Release|Any CPU
{910E800A-59AE-46C4-B7C7-879986179246}.Release|x86.ActiveCfg = Release|Any CPU
{910E800A-59AE-46C4-B7C7-879986179246}.Release|x86.Build.0 = Release|Any CPU
{305F640E-11BA-44F9-95E0-C6882E9CD151}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{305F640E-11BA-44F9-95E0-C6882E9CD151}.Debug|Any CPU.Build.0 = Debug|Any CPU
{305F640E-11BA-44F9-95E0-C6882E9CD151}.Debug|x64.ActiveCfg = Debug|Any CPU
{305F640E-11BA-44F9-95E0-C6882E9CD151}.Debug|x64.Build.0 = Debug|Any CPU
{305F640E-11BA-44F9-95E0-C6882E9CD151}.Debug|x86.ActiveCfg = Debug|Any CPU
{305F640E-11BA-44F9-95E0-C6882E9CD151}.Debug|x86.Build.0 = Debug|Any CPU
{305F640E-11BA-44F9-95E0-C6882E9CD151}.Release|Any CPU.ActiveCfg = Release|Any CPU
{305F640E-11BA-44F9-95E0-C6882E9CD151}.Release|Any CPU.Build.0 = Release|Any CPU
{305F640E-11BA-44F9-95E0-C6882E9CD151}.Release|x64.ActiveCfg = Release|Any CPU
{305F640E-11BA-44F9-95E0-C6882E9CD151}.Release|x64.Build.0 = Release|Any CPU
{305F640E-11BA-44F9-95E0-C6882E9CD151}.Release|x86.ActiveCfg = Release|Any CPU
{305F640E-11BA-44F9-95E0-C6882E9CD151}.Release|x86.Build.0 = Release|Any CPU
{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7}.Debug|x64.ActiveCfg = Debug|Any CPU
{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7}.Debug|x64.Build.0 = Debug|Any CPU
{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7}.Debug|x86.ActiveCfg = Debug|Any CPU
{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7}.Debug|x86.Build.0 = Debug|Any CPU
{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7}.Release|Any CPU.Build.0 = Release|Any CPU
{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7}.Release|x64.ActiveCfg = Release|Any CPU
{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7}.Release|x64.Build.0 = Release|Any CPU
{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7}.Release|x86.ActiveCfg = Release|Any CPU
{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9D758F00-17FF-433D-B088-F9C2D97C9BD1} = {3C312E42-9A47-4BED-8265-A405FCA6AFFF}
{468DB0E4-6221-4E01-BEFF-F452865E59C1} = {E8A2DF68-847A-4D88-B002-64FB666F696C}
{910E800A-59AE-46C4-B7C7-879986179246} = {E8A2DF68-847A-4D88-B002-64FB666F696C}
{305F640E-11BA-44F9-95E0-C6882E9CD151} = {3C312E42-9A47-4BED-8265-A405FCA6AFFF}
{4EFA7D3E-8B31-4BF7-96D1-B9F2867735C7} = {E8A2DF68-847A-4D88-B002-64FB666F696C}
EndGlobalSection
EndGlobal

@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<UserSecretsId>85fd766d-5d23-4476-aed1-463b2942e86a</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Common" Version="1.0.0-alpha2-final" />
<PackageReference Include="NuGet.Packaging.Core" Version="5.9.0" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
</ItemGroup>
</Project>

@ -0,0 +1,22 @@
{
"dotnet": {
"enabled": false
},
"msbuild": {
"enabled": true
},
"Dnx": {
"enabled": false
},
"Script": {
"enabled": false
},
"fileOptions": {
"systemExcludeSearchPatterns": [
"**/bin/**/*",
"**/obj/**/*",
"**/node_modules/**/*"
],
"userExcludeSearchPatterns": []
}
}

@ -0,0 +1,16 @@
using isn.abst;
namespace isnd.Entities
{
public static class ApiConfig
{
public const string Catalog = "/catalog";
public const string Package = "/package";
public const string Search = "/search";
public const string AutoComplete = "/autocomplete";
public const string Registration = "/registration";
public const string Nuspec = "/nuspec";
public const string Nuget = "/nuget";
}
}

@ -0,0 +1,21 @@
using isnd.Data.Catalog;
using Newtonsoft.Json;
namespace isn.Abstract
{
public class ApiIndexViewModel : HappyIdOwner
{
public ApiIndexViewModel(string id) : base(id)
{
}
[JsonProperty("@id")]
public string Id { get => GetId(); }
[JsonProperty("version")]
public string Version { get; set; }
[JsonProperty("resources")]
public Resource[] Resources { get; set; }
}
}

@ -0,0 +1,9 @@
namespace isn.abst
{
public static class Constants
{
public const string PaquetFileEstension = "nupkg";
public const string SpecFileEstension = "nuspec";
public const string ApiVersion = "/v3";
}
}

@ -0,0 +1,35 @@
using Newtonsoft.Json;
namespace isnd.Data.Catalog
{
public class HappyIdOwner
{
public HappyIdOwner(string id)
{
this.id = id;
}
private string id;
public string GetId() { return id; }
public override bool Equals(object obj)
{
if (obj!=null)
{
if (GetType().IsAssignableFrom(obj.GetType()))
{
var rpobj = (HappyIdOwner) obj;
return this.id == rpobj.id;
}
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return id.GetHashCode();
}
}
}

@ -0,0 +1,24 @@
using isnd.Data.Catalog;
using Newtonsoft.Json;
namespace isn.Abstract
{
public class Resource : HappyIdOwner
{
public Resource(string id, string typename) : base(id)
{
Type = typename;
Id = id;
}
[JsonProperty("@id")]
public string Id {get; set; }
[JsonProperty("@type")]
public string Type {get; set; }
[JsonProperty("comment")]
public string Comment {get; set; }
}
}

@ -0,0 +1,20 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace isnd.Attributes
{
public class SafeNameAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
if (!(value is string))
return false;
string str = value as string;
if (str.Length>126) return false;
if (str.Any(c => !char.IsLetterOrDigit(c)
&& !"-_.".Contains(c))) return false;
return true;
}
}
}

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageVersion>1.0.1</PackageVersion>
<Version>1.0.7</Version>
<TargetFrameworks>net7.0</TargetFrameworks>
<NoWarn>NETSDK1138</NoWarn>
<AssemblyVersion>1.0.7.0</AssemblyVersion>
<FileVersion>1.0.7.0</FileVersion>
<InformationalVersion>1.0.7+Branch.main.Sha.3695c1742965d93eba0ad851656cfaa3e44ba327</InformationalVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
</ItemGroup>
</Project>

@ -0,0 +1,7 @@
namespace isn
{
internal static class Constants
{
internal const string ClientVersion = "isn v1.0";
}
}

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace isn
{
public interface IDataProtector
{
string Protect(string data);
string UnProtect(string data);
}
public class DefaultDataProtector : IDataProtector
{
private byte delta = 145;
public DefaultDataProtector()
{
}
public string Protect(string data)
{
List<Byte> protd = new List<byte>();
StringBuilder sb = new StringBuilder();
foreach (byte c in Encoding.UTF8.GetBytes(data))
{
protd.Add((byte) (c ^ delta));
}
return System.Convert.ToBase64String(protd.ToArray());
}
public string UnProtect(string data)
{
if (data==null) return null;
StringBuilder sb = new StringBuilder();
List<byte> unps = new List<byte>();
foreach (byte c in System.Convert.FromBase64CharArray(data.ToCharArray(),0,data.Length))
{
unps.Add((byte) (c ^ delta));
}
return Encoding.UTF8.GetString(unps.ToArray());
}
}
}

@ -0,0 +1,9 @@
namespace isn
{
public class IsnSourceSettings
{
internal string Source { get; set; }
internal string[] Keys { get; set; }
}
}

@ -0,0 +1,8 @@
namespace isn
{
public class IsndErrorMessage
{
public int ecode { get; set; }
public string msg { get; set; }
}
}

@ -0,0 +1,224 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mono.Options;
using Newtonsoft.Json;
namespace isn
{
public partial class Program
{
public static void LoadConfig()
{
FileInfo cfgSettingIf = new FileInfo(_configFileName);
if (cfgSettingIf.Exists)
{
var json = File.ReadAllText(cfgSettingIf.FullName);
settings = JsonConvert.DeserializeObject<Settings>(json);
if (settings.DefaultSourceKey == null)
{
Settings.DefaultSourceKey = settings.Sources.Keys.FirstOrDefault();
}
CurrentSource = settings.DefaultSourceKey;
}
}
static readonly OptionSet storeoptions = new OptionSet {
{ "s|source=", "use source", val => CurrentSource = CurrentSource ?? val },
{ "h|help", "show this message and exit", h => shouldShowPushHelp = h != null },
};
private static readonly string _configFileName =
Path.Combine(
Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.UserProfile), ".isn"),
"config.json")
;
public const string push = "push";
static readonly OptionSet options = new OptionSet {
{ "h|help", "show this message and exit", h => shouldShowHelp = h != null },
{ "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 },
{ "p|store-api-key", "store used api key", val => storApiKey = val != null },
{ "s|source=", "use source", val => CurrentSource = CurrentSource ?? val },
{ "h|help", "show this message and exit", h => shouldShowPushHelp = h != null },
};
static readonly OptionSet sourceoptions = new OptionSet {
{ "h|help", "show this message and exit", h => shouldShowSourceHelp = h != null },
};
static readonly OptionSet showOptions = new OptionSet {
{ "h|help", "show this message and exit", h => shouldShowSourceHelp = h != null },
};
private static bool shouldShowHelp;
private static bool shouldShowVersion;
private static bool shouldShowSourceHelp;
private static bool shouldShowPushHelp;
private static string currentSource = null;
private static bool storApiKey = false;
static Settings settings = null;
public static Settings Settings
{
get
{
if (settings == null)
LoadConfig();
if (settings == null)
{
settings = new Settings
{
DataProtectionTitle = "isn",
Sources = new Dictionary<string, SourceSettings>()
};
}
return settings;
}
}
public static string CurrentSource { get => currentSource; set => currentSource = value; }
static int Main(string[] args)
{
var commandSet = new CommandSet("isn");
var srclst = new Command("list")
{
Run = sargs => SourceList(sargs)
};
var showconfig = new Command("config")
{
Run = sargs => ShowConfig()
};
var srcadd = new Command("add")
{
Run = sargs => SourceAdd(sargs)
};
var srcsetdef = new Command("set-default")
{
Run = sargs => SetDefaultSource(sargs?.FirstOrDefault())
};
var showCommand = new Command("show")
{
Run = sargs =>
{
var showCommandSet = new CommandSet("show")
{
showconfig
};
var pargs = showOptions.Parse(sargs);
if (shouldShowSourceHelp)
{
// output the options
Console.WriteLine("Sources Options:");
showOptions.WriteOptionDescriptions(Console.Out);
return;
}
showCommandSet.Run(pargs);
}
};
var srcCmd = new Command("sources")
{
Run = sargs =>
{
var sourcesCmdSet = new CommandSet("sources")
{
srclst,
srcadd,
srcsetdef
};
var pargs = sourceoptions.Parse(sargs);
if (shouldShowSourceHelp)
{
// output the options
Console.WriteLine("Sources Options:");
sourceoptions.WriteOptionDescriptions(Console.Out);
return;
}
sourcesCmdSet.Run(pargs);
}
};
var add = new Command("add")
{
Run = sargs => Add(sargs)
};
commandSet.Add(add);
var pushCmd = new Command(push)
{
Run = sargs =>
{
var pargs = pushoptions.Parse(sargs);
if (args.Count()==0) shouldShowPushHelp=true;
if (shouldShowPushHelp)
{
// output the options
Console.Error.WriteLine("Push Options:");
pushoptions.WriteOptionDescriptions(Console.Out);
return;
}
List<PushReport> reports = PushPkg(pargs);
}
};
var setapikey = new Command("set-api-key")
{
Run = sargs => StoreApiKey(sargs)
};
commandSet.Add(pushCmd);
commandSet.Add(setapikey);
commandSet.Add(srcCmd);
commandSet.Add(showCommand);
List<string> extra;
try
{
// parse the command line
extra = options.Parse(args);
}
catch (OptionException e)
{
Console.Error.Write("isn: ");
Console.Error.WriteLine(e.Message);
Console.Error.WriteLine("Try `isn --help' for more information.");
return 2;
}
if (shouldShowHelp)
{
// output the options
Console.WriteLine("Options:");
options.WriteOptionDescriptions(Console.Out);
return 1;
}
if (shouldShowVersion)
{
Console.WriteLine("isn version " + GitVersionInformation.AssemblySemFileVer);
}
return commandSet.Run(args);
}
}
}

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace isn
{
public class SourceSettings
{
public string ApiKey { get; set; }
public string Alias { get; set; }
public string GetClearApiKey()
{
return Protector.UnProtect(ApiKey);
}
public void SetApiKey(string key)
{
ApiKey = Protector.Protect(key);
}
public static IDataProtector Protector { get; set; } = new DefaultDataProtector();
}
public class Settings
{
public string DataProtectionTitle { get; set; }
public Dictionary<string, SourceSettings> Sources { get; set; }
public bool AutoUpdateApiKey { get; set; } = false;
private string defSourceKey;
/// <summary>
/// Default source by its alias
/// </summary>
/// <value></value>
public string DefaultSourceKey
{
get => defSourceKey;
set
{
if (!Sources.ContainsKey(value))
{
Sources[value]=new SourceSettings
{
Alias = defSourceKey
};
}
defSourceKey = value;
}
}
}
}

@ -0,0 +1,27 @@
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using isn.Abstract;
namespace isn
{
public static class SourceHelpers
{
public static ApiIndexViewModel GetServerResources(string url)
{
HttpClient client = new HttpClient();
ApiIndexViewModel result = null;
// var json = await client.GetStringAsync(new System.Uri(url));
Task.Run(async ()=> {
var response = await client.GetStringAsync(url);
result = JsonConvert.DeserializeObject<ApiIndexViewModel>(response);
}).Wait();
return result;
}
}
}

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace isn
{
public static class UploadFilesToServerUsingHttpClient
{
public static PushReport UploadFilesToServer(this HttpClient client, Uri uri, FileInfo fi,
string apikey)
{
return UploadFilesToServerAsync(client, uri, fi, apikey).Result;
}
public static async Task<PushReport> UploadFilesToServerAsync(this HttpClient client, Uri uri, FileInfo fi,
string apikey)
{
client.DefaultRequestHeaders.Add("X-NuGet-Client-Version", Constants.ClientVersion);
client.DefaultRequestHeaders.Add("X-NuGet-ApiKey", apikey);
using (var multipartFormDataContent = new MultipartFormDataContent())
{
/* var values = new[]
{
new KeyValuePair<string, string>("Id", Guid.NewGuid().ToString()),
new KeyValuePair<string, string>("Key", "awesome"),
new KeyValuePair<string, string>("From", "khalid@home.com")
//other values
};foreach (var keyValuePair in values)
{
multipartFormDataContent.Add(new StringContent(keyValuePair.Value),
String.Format("\"{0}\"", keyValuePair.Key));
} */
multipartFormDataContent.Add(new ByteArrayContent(File.ReadAllBytes(fi.FullName)),
'"' + "File" + '"',
'"' + fi.Name + '"');
var result = await client.PutAsync(uri, multipartFormDataContent);
if (result.IsSuccessStatusCode)
{
string report = await result.Content.ReadAsStringAsync();
Console.WriteLine(report);
}
else
{
string ereport = await result.Content.ReadAsStringAsync();
Console.WriteLine(ereport);
}
return new PushReport();
}
}
}
}

@ -0,0 +1,68 @@
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace isn
{
public static class PushCommand
{
static public PushReport Run(string pkg, string source, string apikey)
{
if (source == null) source = Program.Settings.DefaultSourceKey;
if (source == null) throw new InvalidOperationException("source is null");
if (Program.Settings.Sources.Values.Any(s=>s.Alias==source))
source = Program.Settings.Sources.First(s=>s.Value.Alias==source).Key;
if (source==null) throw new InvalidOperationException("source is invalid");
var resources = SourceHelpers.GetServerResources(source);
if (resources.Resources == null)
throw new InvalidOperationException("source gave no resource");
if (!resources.Resources.Any(res => res.Type == "PackagePublish/2.0.0"))
throw new InvalidOperationException("Source won't serve the expected push command");
var pubRes = resources.Resources.First(res => res.Type == "PackagePublish/2.0.0");
FileInfo fi = new FileInfo(pkg);
if (!fi.Exists)
{
var report = new PushReport
{
PkgName = fi.Name,
Message = "Le fichier n'existe pas"
};
return report;
}
using (var client = new HttpClient())
try
{
Console.WriteLine("Connecting to "+ pubRes.Id);
return client.UploadFilesToServer(new Uri(pubRes.Id), fi, apikey);
}
catch (HttpRequestException hrex)
{
var report = new PushReport
{
PkgName = fi.Name,
Message = "HttpRequest: " + hrex.Message,
StackTrace = hrex.StackTrace,
StatusCode = hrex.HResult.ToString()
};
Console.Error.WriteLine(hrex.Message);
return report;
}
catch (Exception ex)
{
var report = new PushReport
{
PkgName = fi.Name,
Message = ex.Message,
StackTrace = ex.StackTrace
};
Console.Error.WriteLine(ex.Message);
return report;
}
}
}
}

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace isn
{
partial class Program
{
public static List<PushReport> PushPkg(IEnumerable<string> pkgs)
{
List<PushReport> pushReports = new List<PushReport>();
foreach (string pkg in pkgs)
{
var report = PushCommand.Run(pkg, CurrentSource, apiKey);
Console.WriteLine(report.ToDoc());
pushReports.Add(report);
}
if (storApiKey)
{
EnsureKeyStored();
}
return pushReports;
}
private static object Add(IEnumerable<string> str)
{
throw new NotImplementedException();
}
}
}

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
namespace isn
{
partial class Program
{
private static void StoreApiKey(IEnumerable<string> storeArgs)
{
var args = storeoptions.Parse(storeArgs);
if (shouldShowPushHelp)
{
// output the options
Console.Error.WriteLine("Push Options:");
storeoptions.WriteOptionDescriptions(Console.Out);
}
else
{
apiKey = args[0];
EnsureKeyStored();
}
}
public static void EnsureKeyStored()
{
if (CurrentSource == null)
{
if (Settings.DefaultSourceKey == null)
return;
CurrentSource = Settings.DefaultSourceKey;
}
if (Settings.Sources.ContainsKey(CurrentSource))
{
if (apiKey == null)
{
// Une suppression
Settings.Sources.Remove(CurrentSource);
if (Settings.DefaultSourceKey == CurrentSource) Settings.DefaultSourceKey = null;
}
else
{
// Une mise À jour
Settings.Sources[CurrentSource].SetApiKey(apiKey);
if (Settings.DefaultSourceKey == null) Settings.DefaultSourceKey = CurrentSource;
}
}
else if (apiKey != null)
{
// une addition
var setting = new SourceSettings ();
setting.SetApiKey(apiKey);
Settings.Sources.Add(CurrentSource, setting);
}
SaveConfig();
}
public static void SaveConfig()
{
FileInfo cfgSettingIf = new FileInfo(_configFileName);
if (!cfgSettingIf.Directory.Exists) cfgSettingIf.Directory.Create();
File.WriteAllText(
cfgSettingIf.FullName,
JsonConvert.SerializeObject(
Settings,
Formatting.Indented
));
}
}
}

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace isn
{
partial class Program
{
private static void ShowConfig()
{
Console.WriteLine(JsonConvert.SerializeObject(Settings, Formatting.Indented));
}
}
}

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace isn
{
partial class Program
{
private static void SourceAdd(IEnumerable<string> str)
{
foreach (string arg in str)
{
if (Settings.Sources.ContainsKey(arg))
{
SourceSettings setting = Settings.Sources[arg];
throw new InvalidOperationException
(setting.Alias);
}
throw new NotImplementedException();
}
}
}
}

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
namespace isn
{
partial class Program
{
private static void SourceList(IEnumerable<string> sargs)
{
IEnumerable<string> spec = sargs.Count()>0 ? sargs : Settings.Sources.Keys;
foreach (string arg in spec)
{
SourceSettings setting = Settings.Sources[arg];
Console.WriteLine(JsonConvert.SerializeObject(setting));
}
}
}
}

@ -0,0 +1,21 @@
using System;
using System.Linq;
namespace isn
{
partial class Program
{
private static void SetDefaultSource(string arg)
{
SourceSettings settings =
Settings.Sources.ContainsKey(arg) ?
Settings.Sources[arg] :
Settings.Sources.Values.FirstOrDefault((s)=> s.Alias == arg) ;
if (settings==null) throw new InvalidOperationException(arg);
Settings.DefaultSourceKey = arg;
SaveConfig();
}
}
}

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net7.0</TargetFrameworks>
<RootNamespace>nuget_cli</RootNamespace>
<UserSecretsId>45b74c62-05bc-4603-95b4-3e80ae2fdf50</UserSecretsId>
<Version>1.0.7</Version>
<PackageVersion>1.0.1</PackageVersion>
<IsPackable>true</IsPackable>
<PackageLicenseExpression>WTFPL</PackageLicenseExpression>
<IsTool>true</IsTool>
<NoWarn>NETSDK1138</NoWarn>
<AssemblyVersion>1.0.7.0</AssemblyVersion>
<FileVersion>1.0.7.0</FileVersion>
<InformationalVersion>1.0.7+Branch.main.Sha.3695c1742965d93eba0ad851656cfaa3e44ba327</InformationalVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mono.Options" Version="5.3.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="unleash.client" Version="1.6.1" />
<PackageReference Include="GitVersion.MsBuild" Version="5.6.10*" />
<ProjectReference Include="../isn.abst/isn.abst.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,30 @@
using System.Net;
using System.Text;
namespace isn
{
public class PushReport
{
public string PkgName { get; set; }
public bool Executed { get; internal set; }
public bool OK { get; internal set; }
public bool AlreadyPresent { get; internal set; }
public string Message { get; internal set; }
public string StatusCode { get; internal set; }
public string StackTrace { get; internal set; }
public string ToDoc()
{
StringBuilder sb = new StringBuilder($"= Pushing {PkgName}\n\n");
if (Executed) sb.AppendLine("* Executed");
if (OK) sb.AppendLine("* OK");
if (!string.IsNullOrWhiteSpace(Message))
sb.AppendLine(Message);
if (!string.IsNullOrWhiteSpace(StatusCode))
sb.AppendLine($"* Status Code : ");
if (!string.IsNullOrWhiteSpace(StackTrace))
sb.AppendLine($"* StackTrace : ");
return sb.ToString();
}
}
}

@ -0,0 +1,8 @@
using Microsoft.AspNetCore.Authorization;
namespace isnd.Authorization
{
internal class ValidApiKeyRequirement : IAuthorizationRequirement
{
}
}

@ -0,0 +1,13 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
namespace isnd.Authorization
{
internal class ValidApiKeyRequirementHandler : AuthorizationHandler<ValidApiKeyRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ValidApiKeyRequirement requirement)
{
throw new System.NotImplementedException();
}
}
}

@ -0,0 +1,9 @@
namespace isnd
{
public static class IsndConstants
{
public const string AdministratorRoleName = "Admin";
public const string RequireAdminPolicyName = "RequireAdministratorRole";
public const string RequireValidApiKey = "RequireValideApiKey";
}
}

@ -0,0 +1,258 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using isnd.Data;
using isnd.Data.Roles;
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace isnd.Controllers
{
[AllowAnonymous]
public class AccountController : Controller
{
private readonly IAuthenticationSchemeProvider _schemeProvider;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
private readonly AdminStartupList _startupAdminList;
public AccountController(
IAuthenticationSchemeProvider schemeProvider,
SignInManager<ApplicationUser> signInManager,
UserManager<ApplicationUser> userManager,
IOptions<AdminStartupList> startupAdminListConfig )
{
_schemeProvider = schemeProvider;
_signInManager = signInManager;
_userManager = userManager;
_startupAdminList = startupAdminListConfig.Value;
}
/// <summary>
/// Entry point into the login workflow
/// </summary>
[HttpGet]
public async Task<IActionResult> Login(string returnUrl)
{
// build a model so we know what to show on the login page
var vm = await BuildLoginViewModelAsync(returnUrl);
if (vm.IsExternalLoginOnly)
{
// we only have one option for logging in and it's an external provider
return RedirectToAction("Challenge", "External", new { scheme = vm.ExternalLoginScheme, returnUrl });
}
return View(vm);
}
/// <summary>
/// Handle postback from username/password login
/// </summary>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginInputModel model, string button)
{
// the user clicked the "cancel" button
if (button != "login")
{
// since we don't have a valid context, then we just go back to the home page
return Redirect("~/");
}
if (ModelState.IsValid)
{
// validate username/password
var user = await _userManager.FindByNameAsync(model.Username);
var signResult = await _signInManager.CheckPasswordSignInAsync(user, model.Password, true);
if (signResult.Succeeded)
{
// only set explicit expiration here if user chooses "remember me".
// otherwise we rely upon expiration configured in cookie middleware.
AuthenticationProperties props = null;
if (AccountOptions.AllowRememberLogin && model.RememberLogin)
{
props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
};
};
await _signInManager.SignInAsync(user, model.RememberLogin && AccountOptions.AllowRememberLogin);
if (Url.IsLocalUrl(model.ReturnUrl))
{
return Redirect(model.ReturnUrl);
}
else if (string.IsNullOrEmpty(model.ReturnUrl))
{
return Redirect("~/");
}
else
{
// user might have clicked on a malicious link - should be logged
throw new Exception("invalid return URL");
}
}
ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
}
// something went wrong, show form with error
var vm = await BuildLoginViewModelAsync(model);
return View(vm);
}
/// <summary>
/// Show logout page
/// </summary>
[HttpGet]
public async Task<IActionResult> Logout(string logoutId)
{
// build a model so the logout page knows what to display
var vm = BuildLogoutViewModel(logoutId);
if (vm.ShowLogoutPrompt == false)
{
// if the request for logout was properly authenticated from IdentityServer, then
// we don't need to show the prompt and can just log the user out directly.
return await Logout(vm);
}
return View(vm);
}
/// <summary>
/// Handle logout page postback
/// </summary>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout(LogoutInputModel model)
{
// build a model so the logged out page knows what to display
var vm = BuildLoggedOutViewModel(model.LogoutId);
if (User?.Identity.IsAuthenticated == true)
{
// delete local authentication cookie
await HttpContext.SignOutAsync();
}
// check if we need to trigger sign-out at an upstream identity provider
if (vm.TriggerExternalSignout)
{
// build a return URL so the upstream provider will redirect back
// to us after the user has logged out. this allows us to then
// complete our single sign-out processing.
string url = Url.Action("Logout", new { logoutId = vm.LogoutId });
// this triggers a redirect to the external provider for sign-out
return SignOut(new AuthenticationProperties { RedirectUri = url }, vm.ExternalAuthenticationScheme);
}
return View("LoggedOut", vm);
}
[HttpGet]
public IActionResult AccessDenied()
{
return new BadRequestObjectResult(403);
}
/*****************************************/
/* helper APIs for the AccountController */
/*****************************************/
private async Task<LoginViewModel> BuildLoginViewModelAsync(string returnUrl)
{
var schemes = await _schemeProvider.GetAllSchemesAsync();
var providers = schemes
.Where(x => x.DisplayName != null)
.Select(x => new ExternalProvider
{
DisplayName = x.DisplayName ?? x.Name,
AuthenticationScheme = x.Name
}).ToList();
var allowLocal = true;
return new LoginViewModel
{
AllowRememberLogin = AccountOptions.AllowRememberLogin,
EnableLocalLogin = allowLocal && AccountOptions.AllowLocalLogin,
ReturnUrl = returnUrl,
ExternalProviders = providers.ToArray()
};
}
private async Task<LoginViewModel> BuildLoginViewModelAsync(LoginInputModel model)
{
var vm = await BuildLoginViewModelAsync(model.ReturnUrl);
vm.Username = model.Username;
vm.RememberLogin = model.RememberLogin;
return vm;
}
private LogoutViewModel BuildLogoutViewModel(string logoutId)
{
var vm = new LogoutViewModel { LogoutId = logoutId, ShowLogoutPrompt = AccountOptions.ShowLogoutPrompt };
if (User?.Identity.IsAuthenticated != true)
{
// if the user is not authenticated, then just show logged out page
vm.ShowLogoutPrompt = false;
return vm;
}
// show the logout prompt. this prevents attacks where the user
// is automatically signed out by another malicious web page.
return vm;
}
private LoggedOutViewModel BuildLoggedOutViewModel(string logoutId)
{
var vm = new LoggedOutViewModel
{
AutomaticRedirectAfterSignOut = AccountOptions.AutomaticRedirectAfterSignOut,
LogoutId = logoutId
};
return vm;
}
[Authorize]
public async Task<IActionResult> GetAdminrole()
{
string username = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (_startupAdminList.Users.Contains(username))
{
var user = await _userManager.FindByNameAsync(username);
var roles = await _userManager.GetRolesAsync(user);
if (!roles.Contains(IsndConstants.AdministratorRoleName))
{
await _userManager.AddToRoleAsync(user, IsndConstants.AdministratorRoleName);
}
return Ok();
}
return BadRequest();
}
}
}

@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using isnd.Data;
using isnd.Entities;
using isnd.Data.ApiKeys;
namespace isnd.Controllers
{
[Authorize]
public class ApiKeysController : Controller
{
private readonly ApplicationDbContext dbContext;
private readonly IsndSettings isndSettings;
private readonly UserManager<ApplicationUser> _userManager;
private readonly IDataProtector protector;
public ApiKeysController(ApplicationDbContext dbContext,
IOptions<IsndSettings> isndSettingsOptions,
IDataProtectionProvider provider,
UserManager<ApplicationUser> userManager)
{
this.dbContext = dbContext;
this.isndSettings = isndSettingsOptions.Value;
protector = provider.CreateProtector(isndSettings.ProtectionTitle);
_userManager = userManager;
}
[HttpGet]
public async Task<ActionResult> Index()
{
List<ApiKey> index = await GetUserKeys().ToListAsync();
IndexModel model = new IndexModel { ApiKey = index };
ViewData["Title"] = "Index";
return View("Index", model);
}
[HttpGet]
public async Task<ActionResult> Create()
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var user = await _userManager.FindByIdAsync(userId);
ViewBag.UserId = new SelectList(new List<ApplicationUser> { user });
return View(new CreateModel{ });
}
[HttpPost]
public async Task<ActionResult> Create(CreateModel model)
{
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
IQueryable<ApiKey> userKeys = GetUserKeys();
if (userKeys.Count() >= isndSettings.MaxUserKeyCount)
{
ModelState.AddModelError(null, "Maximum key count reached");
return View();
}
ApiKey newKey = new ApiKey { UserId = userid, Name = model.Name,
CreationDate = DateTime.Now };
_ = dbContext.ApiKeys.Add(newKey);
_ = await dbContext.SaveChangesAsync();
return View("Details", new DetailModel { Name = newKey.Name,
ProtectedValue = protector.Protect(newKey.Id),
ApiKey = newKey });
}
[HttpGet]
public async Task<ActionResult> Delete(string id)
{
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
ApiKey key = await dbContext.ApiKeys.FirstOrDefaultAsync(k => k.Id == id && k.UserId == userid);
return View(new DeleteModel { ApiKey = key });
}
[HttpPost]
public async Task<ActionResult> Delete(DeleteModel model)
{
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
ApiKey key = dbContext.ApiKeys.FirstOrDefault(k => k.Id == model.ApiKey.Id && k.UserId == userid);
if (key == null)
{
ModelState.AddModelError(null, "Key not found");
return View();
}
_ = dbContext.ApiKeys.Remove(key);
_ = await dbContext.SaveChangesAsync();
return View("Index", new IndexModel { ApiKey = GetUserKeys().ToList() } );
}
public async Task<ActionResult> Details(string id)
{
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
ApiKey key = await dbContext.ApiKeys.FirstOrDefaultAsync(k => k.Id == id && k.UserId == userid);
if (key == null)
{
ModelState.AddModelError(null, "Key not found");
return View();
}
return View("Details", new DetailModel { ApiKey = key, Name = key.Name, ProtectedValue = protector.Protect(key.Id)});
}
public async Task<ActionResult> Edit(string id)
{
EditModel edit = new EditModel();
string userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var user = await _userManager.FindByIdAsync(userId);
edit.ApiKey = await GetUserKeys().SingleOrDefaultAsync(k =>
k.UserId == userId && k.Id == id);
ViewBag.UserId = new SelectList(new List<ApplicationUser> { user });
return View(edit);
}
[HttpPost]
public async Task<ActionResult> Edit(EditModel model)
{
string userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var apiKey = await dbContext.ApiKeys.SingleOrDefaultAsync(k => k.UserId == userId && k.Id == model.ApiKey.Id);
apiKey.Name = model.ApiKey.Name;
apiKey.ValidityPeriodInDays = model.ApiKey.ValidityPeriodInDays;
await dbContext.SaveChangesAsync();
return View("Details", new DetailModel { ApiKey = apiKey });
}
public IQueryable<ApiKey> GetUserKeys()
{
return dbContext.ApiKeys.Include(k => k.User).Where(k => k.User.UserName == User.Identity.Name);
}
}
}

@ -0,0 +1,78 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using isnd.Data;
using System.Linq;
using isnd.ViewModels;
using Unleash;
using System.Reflection;
using Microsoft.EntityFrameworkCore;
namespace isnd.Controllers
{
/// <summary>
/// Home Controller
/// </summary>
public class HomeController : Controller
{
private readonly ApplicationDbContext _dbContext;
private readonly IUnleash _unleashĈlient;
/// <summary>
/// Home controller ctor
/// </summary>
/// <param name="dbContext"></param>
/// <param name="unleashĈlient"></param>
public HomeController(
ApplicationDbContext dbContext,
IUnleash unleashĈlient)
{
_dbContext = dbContext;
_unleashĈlient = unleashĈlient;
}
public IActionResult Index()
{
return View(new HomeIndexViewModel{
PkgCount = _dbContext.Packages
.Where(p => p.Versions.Count > 0)
.Count(),
UnleashClient = _unleashĈlient
});
}
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
}
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
var ass = typeof(isn.Abstract.Resource).GetType().Assembly;
var attrs = ass.GetCustomAttributes(true);
// ass.GetCustomAttributes(true);
System.Reflection.AssemblyFileVersionAttribute v = (AssemblyFileVersionAttribute)
GetType().Assembly.GetCustomAttribute(typeof(AssemblyFileVersionAttribute));
return View();
}
public IActionResult Privacy()
{
ViewData["Message"] = "Your Privacy page.";
return View(ViewData);
}
public IActionResult Error()
{
return View();
}
}
}

@ -0,0 +1,18 @@
using System;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using isnd.Data;
namespace isnd.Controllers
{
// TODO Web hook CI
public class NewUpdateController : Controller
{
[Authorize(Policy = IsndConstants.RequireAdminPolicyName)]
public IActionResult NewRelease(NewReleaseInfo release)
{
throw new NotImplementedException("web hook");
}
}
}

@ -0,0 +1,54 @@
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using isnd.Data;
using isnd.ViewModels;
using isnd.Helpers;
using isnd.Interfaces;
namespace isnd
{
[AllowAnonymous]
public class PackageVersionController : Controller
{
private readonly ApplicationDbContext _context;
private readonly IPackageManager _pm;
public PackageVersionController(ApplicationDbContext context,
IPackageManager pm)
{
_context = context;
_pm = pm;
}
// GET: PackageVersion
public async Task<IActionResult> Index(PackageVersionIndexViewModel model)
{
var applicationDbContext = _context.PackageVersions.Include(p => p.Package)
.Include(p => p.Package.Owner)
.Include(p => p.Package.Versions)
.Where(
p => (model.Prerelease || !p.IsPrerelease)
&& ((model.PackageId == null) || p.PackageId.StartsWith(model.PackageId)));
model.Versions = await applicationDbContext.ToArrayAsync();
return View(model);
}
[Authorize]
public async Task<IActionResult> Mines(PackageVersionIndexViewModel model)
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var applicationDbContext = _context.PackageVersions
.Include(p => p.Package).Where(
p => (string.IsNullOrEmpty(model.PackageId) || p.PackageId.StartsWith(model.PackageId))
&& p.Package.OwnerId == userId);
model.Versions = await applicationDbContext.ToArrayAsync();
return View("Index", model);
}
}
}

@ -0,0 +1,43 @@
using Microsoft.AspNetCore.Mvc;
using isnd.Entities;
using isnd.Services;
using isn.Abstract;
using isn.abst;
using isnd.Interfaces;
using Unleash;
using System.Linq;
namespace isnd.Controllers
{
/// <summary>
/// Api Controller
/// </summary>
public class ApiController : Controller
{
private readonly IPackageManager packageManager;
private readonly Resource[] resources;
/// <summary>
/// Api Controller Constructor
/// </summary>
/// <param name="pm"></param>
/// <param name="unleashĈlient"></param>
public ApiController(IPackageManager pm, IUnleash unleashĈlient)
{
packageManager = pm;
resources = packageManager.GetResources(unleashĈlient).ToArray();
}
/// <summary>
/// API index
/// </summary>
/// <returns></returns>
[HttpGet("~" + Constants.ApiVersion + "/index")]
public IActionResult ApiIndex()
{
return Ok(new ApiIndexViewModel(packageManager.CatalogBaseUrl){ Version = PackageManager.BASE_API_LEVEL, Resources = resources });
}
}
}

@ -0,0 +1,34 @@
using isnd.Services;
using isnd.Entities;
using Microsoft.AspNetCore.Mvc;
using isn.abst;
namespace isnd.Controllers
{
public partial class PackagesController
{
// GET /autocomplete?id=isn.protocol&prerelease=true
[HttpGet("~" + Constants.ApiVersion + ApiConfig.AutoComplete)]
public IActionResult AutoComplete(
string id,
string semVerLevel,
bool prerelease = false,
string packageType = null,
int skip = 0,
int take = 25)
{
if (take > maxTake)
{
ModelState.AddModelError("take", "Maximum exceeded");
}
if (semVerLevel != PackageManager.BASE_API_LEVEL)
{
ModelState.AddModelError("semVerLevel", PackageManager.BASE_API_LEVEL + " expected");
}
if (ModelState.ErrorCount > 0) return BadRequest(ModelState);
return Ok(packageManager.AutoComplete(id,skip,take,prerelease,packageType));
}
}
}

@ -0,0 +1,51 @@
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
{
public partial class PackagesController
{
// https://docs.microsoft.com/en-us/nuget/api/catalog-resource#versioning
[HttpGet("~" + Constants.ApiVersion + ApiConfig.Catalog)]
public async Task<IActionResult> CatalogIndex()
{
return Ok(await packageManager.GetCatalogIndexAsync());
}
[HttpGet("~" + Constants.ApiVersion + ApiConfig.Registration + "/{id}/{version?}")]
public async Task<IActionResult> CatalogRegistration(string id, string version)
{
if (string.IsNullOrWhiteSpace(version))
{
var query = new Data.Catalog.RegistrationPageIndexQuery
{
Query = id,
Prerelease = true
};
var index = await packageManager.GetPackageRegistrationIndexAsync(query);
if (index == null) return NotFound();
// query.TotalHits = result.Items.Select(i=>i.Items.Length).Aggregate((a,b)=>a+b);
return Ok(index);
}
// return a Package
var leaf = await packageManager.GetCatalogEntryAsync(id, version, null);
if (null == leaf) return NotFound(new { id, version });
return Ok(leaf);
}
}
}

@ -0,0 +1,25 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using isnd.Helpers;
using isnd.Entities;
using System.ComponentModel.DataAnnotations;
using isnd.Attributes;
using System.Security.Claims;
using isn.abst;
namespace isnd.Controllers
{
public partial class PackagesController
{
[HttpDelete("~" + Constants.ApiVersion + ApiConfig.Package + "/{id}/{lower?}/{type?}")]
public async Task<IActionResult> ApiDelete(
[FromRoute][SafeName][Required] string id,
[FromRoute][SafeName][Required] string lower,
[FromRoute] string type)
{
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
var report = await packageManager.UserAskForPackageDeletionAsync(uid, id, lower, type);
return Ok(report);
}
}
}

@ -0,0 +1,55 @@
using System.ComponentModel.DataAnnotations;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using isnd.Attributes;
using isnd.Entities;
using isn.abst;
namespace isnd.Controllers
{
public partial class PackagesController
{
// Web get the paquet
[HttpGet("~" + Constants.ApiVersion + ApiConfig.Package + "/{id}/{lower}/{idf}-{lowerf}."
+ Constants.PaquetFileEstension)]
public IActionResult GetPackage(
[FromRoute][SafeName][Required] string id,
[FromRoute][SafeName][Required] string lower,
[FromRoute] string idf, [FromRoute] string lowerf)
{
var pkgpath = Path.Combine(isndSettings.PackagesRootDir,
id, lower, $"{id}-{lower}." + Constants.PaquetFileEstension
);
FileInfo pkgfi = new FileInfo(pkgpath);
if (!pkgfi.Exists)
{
return BadRequest("!pkgfi.Exists");
}
return File(pkgfi.OpenRead(), "application/zip; charset=binary");
}
// Web get spec
[HttpGet("~" + Constants.ApiVersion + Constants.SpecFileEstension + "/{id}/{lower}/{idf}-{lowerf}."
+ Constants.SpecFileEstension)]
public IActionResult GetNuspec(
[FromRoute][SafeName][Required] string id,
[FromRoute][SafeName][Required] string lower,
[FromRoute][SafeName][Required] string idf,
[FromRoute][SafeName][Required] string lowerf)
{
var pkgpath = Path.Combine(isndSettings.PackagesRootDir,
id, lower, $"{id}." + Constants.SpecFileEstension);
FileInfo pkgfi = new FileInfo(pkgpath);
if (!pkgfi.Exists)
{
return BadRequest("!pkgfi.Exists");
}
return File(pkgfi.OpenRead(), "text/xml; charset=utf-8");
}
}
}

@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Mvc;
using NuGet.Versioning;
using isnd.Entities;
using isn.abst;
namespace isnd.Controllers
{
public partial class PackagesController
{
public IActionResult GetVersions(
string id,
string lower,
bool prerelease = false,
string packageType = null,
int skip = 0,
int take = 25)
{
if (take > maxTake)
{
ModelState.AddModelError("take", "Maximum exceeded");
}
// NugetVersion
if (!NuGetVersion.TryParse(lower, out NuGetVersion parsedVersion))
{
ModelState.AddModelError("lower", "invalid version string");
}
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
return Ok(new
{
versions = packageManager.GetVersions(
id, parsedVersion, prerelease, packageType, skip, take)
});
}
}
}

@ -0,0 +1,221 @@
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.AspNetCore.Authorization;
namespace isnd.Controllers
{
public partial class PackagesController
{
// TODO [Authorize(Policy = IsndConstants.RequireValidApiKey)]
[HttpPut("~" + Constants.ApiVersion + ApiConfig.Package)]
public async Task<IActionResult> Put()
{
try
{
var clientVersionId = Request.Headers["X-NuGet-Client-Version"];
string apiKey = Request.Headers["X-NuGet-ApiKey"][0];
ViewData["versionId"] = typeof(PackagesController).Assembly.FullName;
var files = new List<string>();
ViewData["files"] = files;
var clearkey = protector.Unprotect(apiKey);
var apikey = dbContext.ApiKeys.SingleOrDefault(k => k.Id == clearkey);
if (apikey == null)
{
logger.LogError("403 : no api-key");
return Unauthorized();
}
Commit commit = new Commit
{
Action = PackageAction.PublishPackage,
TimeStamp = DateTime.Now
};
dbContext.Commits.Add(commit);
foreach (IFormFile file in Request.Form.Files)
{
string initpath = Path.Combine(Environment.GetEnvironmentVariable("TEMP") ??
Environment.GetEnvironmentVariable("TMP") ?? "/tmp",
$"isn-{Guid.NewGuid()}."+Constants.PaquetFileEstension);
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.SpecFileEstension));
if (spec == null) return BadRequest(new { error = "no " + Constants.SpecFileEstension + " 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.PaquetFileEstension;
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,
LatestVersion = 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)
{
// La version existe sur le disque,
// mais si elle ne l'est pas en base de donnéés,
// on remplace la version sur disque.
var pkgv = dbContext.PackageVersions.Where(
v => v.PackageId == pkg.Id
);
if (pkgv !=null && pkgv.Count()==0)
{
dest.Delete();
}
else {
logger.LogWarning("400 : pkgversion:existant");
ModelState.AddModelError("pkgversion", "existant" );
return BadRequest(ModelState);
}
}
{
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);
}
await dbContext.SaveChangesAsync();
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.SpecFileEstension);
FileInfo nfpi = new FileInfo(nuspecfullpath);
if (nfpi.Exists)
nfpi.Delete();
spec.ExtractToFile(nuspecfullpath);
}
}
return Ok(ViewData);
}
catch (Exception ex)
{
logger.LogError(ex.Message);
logger.LogError("Stack Trace: " + ex.StackTrace);
return new ObjectResult(new { ViewData, ex.Message })
{ StatusCode = 500 };
}
}
}
}

@ -0,0 +1,28 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using isnd.Entities;
using isn.abst;
namespace isnd.Controllers
{
public partial class PackagesController
{
// GET {@id}?q={QUERY}&skip={SKIP}&take={TAKE}&prerelease={PRERELEASE}&semVerLevel={SEMVERLEVEL}&packageType={PACKAGETYPE}
[HttpGet("~" + Constants.ApiVersion + ApiConfig.Search)]
public IActionResult Search(
string q,
int skip = 0,
int take = 25,
bool prerelease = false,
string semVerLevel = null,
string packageType = null
)
{
throw new NotImplementedException();
}
}
}

@ -0,0 +1,92 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using isnd.Data;
using isnd.Data.Catalog;
using isnd.Helpers;
using isnd.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace isnd.Controllers
{
public partial class PackagesController
{
// Web search
public async Task<IActionResult> Index(RegistrationPageIndexQuery model)
{
return View(new RegistrationPageIndexQueryAndResult{Query = model,
Result = await packageManager.SearchPackageAsync(model)});
}
public async Task<IActionResult> Details(string pkgid)
{
if (pkgid == null)
{
return NotFound();
}
var packageVersion = dbContext.PackageVersions
.Include(p => p.Package)
.Where(m => m.PackageId == pkgid)
.OrderByDescending(p => p)
;
if (packageVersion.Count() == 0)
{
return NotFound();
}
bool results = await packageVersion.AnyAsync();
var latest = await packageVersion.FirstAsync();
return View("Details", new PackageDetailViewModel
{
ExternalUrl = isndSettings.ExternalUrl,
latest = latest,
pkgid = pkgid,
totalHits = packageVersion.Count(),
data = packageVersion.Take(MAX_PKG_VERSION_LIST).ToArray()
});
}
const int MAX_PKG_VERSION_LIST = 50;
[Authorize]
public async Task<IActionResult> Delete(string pkgid, string version, string pkgtype)
{
if (pkgid == null || version == null)
{
return NotFound();
}
// var report = await packageManager.DeletePackageAsync(id, lower, type);
var packageVersion = await dbContext.PackageVersions.Include(p => p.Package)
.FirstOrDefaultAsync(m => m.PackageId == pkgid
&& m.FullString == version && m.Type == pkgtype);
if (packageVersion == null) return NotFound();
if (!User.IsOwner(packageVersion)) return Unauthorized();
var pkg = await packageManager.GetPackageAsync(pkgid, version, pkgtype);
return View(pkg);
}
// POST: PackageVersion/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(string PackageId, string FullString,
string Type)
{
PackageVersion packageVersion = await dbContext.PackageVersions
.Include(pv => pv.Package)
.FirstOrDefaultAsync(m => m.PackageId == PackageId
&& m.FullString == FullString && m.Type == Type);
if (packageVersion == null) return NotFound();
if (!User.IsOwner(packageVersion)) return Unauthorized();
await packageManager.DeletePackageAsync(PackageId, FullString, Type);
return RedirectToAction(nameof(Index));
}
}
}

@ -0,0 +1,52 @@
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NuGet.Versioning;
using isnd.Data;
using isnd.Entities;
using Unleash;
using isnd.Services;
using isnd.ViewModels;
using System.Threading.Tasks;
using isnd.Interfaces;
using isn.Abstract;
namespace isnd.Controllers
{
[AllowAnonymous]
public partial class PackagesController : Controller
{
const int maxTake = 100;
private readonly Resource[] resources;
private readonly ILogger<PackagesController> logger;
private readonly IDataProtector protector;
private readonly IsndSettings isndSettings;
readonly ApplicationDbContext dbContext;
private readonly IPackageManager packageManager;
private readonly IUnleash unleashĈlient;
public PackagesController(
ILoggerFactory loggerFactory,
IDataProtectionProvider provider,
IOptions<IsndSettings> isndOptions,
IUnleash unleashĈlient,
ApplicationDbContext dbContext,
IPackageManager pm)
{
logger = loggerFactory.CreateLogger<PackagesController>();
isndSettings = isndOptions.Value;
protector = provider.CreateProtector(isndSettings.ProtectionTitle);
this.dbContext = dbContext;
packageManager = pm;
this.unleashĈlient = unleashĈlient;
resources = packageManager.GetResources(unleashĈlient).ToArray();
}
}
}

@ -0,0 +1,20 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using System;
namespace isnd.Data
{
public class AccountOptions
{
public static bool AllowLocalLogin = true;
public static bool AllowRememberLogin = true;
public static TimeSpan RememberMeLoginDuration = TimeSpan.FromDays(30);
public static bool ShowLogoutPrompt = true;
public static bool AutomaticRedirectAfterSignOut = false;
public static string InvalidCredentialsErrorMessage = "Invalid username or password";
}
}

@ -0,0 +1,12 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace isnd.Data
{
public class ExternalProvider
{
public string DisplayName { get; set; }
public string AuthenticationScheme { get; set; }
}
}

@ -0,0 +1,19 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace isnd.Data
{
public class LoggedOutViewModel
{
public string PostLogoutRedirectUri { get; set; }
public string ClientName { get; set; }
public string SignOutIframeUrl { get; set; }
public bool AutomaticRedirectAfterSignOut { get; set; }
public string LogoutId { get; set; }
public bool TriggerExternalSignout => ExternalAuthenticationScheme != null;
public string ExternalAuthenticationScheme { get; set; }
}
}

@ -0,0 +1,18 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using System.ComponentModel.DataAnnotations;
namespace isnd.Data
{
public class LoginInputModel
{
[Required]
public string Username { get; set; }
[Required]
public string Password { get; set; }
public bool RememberLogin { get; set; }
public string ReturnUrl { get; set; }
}
}

@ -0,0 +1,22 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
namespace isnd.Data
{
public class LoginViewModel : LoginInputModel
{
public bool AllowRememberLogin { get; set; } = true;
public bool EnableLocalLogin { get; set; } = true;
public IEnumerable<ExternalProvider> ExternalProviders { get; set; } = Enumerable.Empty<ExternalProvider>();
public IEnumerable<ExternalProvider> VisibleExternalProviders => ExternalProviders.Where(x => !String.IsNullOrWhiteSpace(x.DisplayName));
public bool IsExternalLoginOnly => EnableLocalLogin == false && ExternalProviders?.Count() == 1;
public string ExternalLoginScheme => IsExternalLoginOnly ? ExternalProviders?.SingleOrDefault()?.AuthenticationScheme : null;
}
}

@ -0,0 +1,11 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace isnd.Data
{
public class LogoutInputModel
{
public string LogoutId { get; set; }
}
}

@ -0,0 +1,11 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace isnd.Data
{
public class LogoutViewModel : LogoutInputModel
{
public bool ShowLogoutPrompt { get; set; } = true;
}
}

@ -0,0 +1,12 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace isnd.Data
{
public class RedirectViewModel
{
public string RedirectUrl { get; set; }
}
}

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace isnd.Data
{
public class RegisterViewModel
{
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 2)]
[Display(Name = "FullName")]
public string FullName { get; set; }
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
}

@ -0,0 +1,25 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace isnd.Data.ApiKeys
{
public class ApiKey
{
[Required][Key][DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
[Required][ForeignKey("User")]
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
public string Name { get; set; }
public int ValidityPeriodInDays{ get; set; }
public DateTime CreationDate { get; set; }
public bool IsValid => CreationDate.AddDays(ValidityPeriodInDays) > DateTime.Now;
}
}

@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
namespace isnd.Data.ApiKeys
{
public class ApiKeyViewModel
{
[Display(Name = "Key Name")]
public string Name { get; set; }
[Display(Name = "Key Value")]
public string ProtectedValue { get; set; }
}
}

@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
namespace isnd.Data.ApiKeys
{
public class CreateModel
{
[Required][StringLength(255)]
[Display(Name = "Key Name")]
public string Name { get; set; }
public string UserId { get; set; }
}
}

@ -0,0 +1,7 @@
namespace isnd.Data.ApiKeys
{
public class DeleteModel
{
public ApiKey ApiKey { get; set; }
}
}

@ -0,0 +1,8 @@
namespace isnd.Data.ApiKeys
{
public class DetailModel : ApiKeyViewModel
{
public ApiKey ApiKey { get; set; }
}
}

@ -0,0 +1,12 @@
namespace isnd.Data.ApiKeys
{
public class EditModel
{
public EditModel()
{
if (ApiKey==null) ApiKey = new ApiKey();
}
public ApiKey ApiKey { get; set; }
}
}

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace isnd.Data.ApiKeys
{
public class IndexModel
{
public List<ApiKey> ApiKey { get; set; }
}
}

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using isnd.Data;
using isnd.Data.ApiKeys;
using isnd.Data.Packages;
namespace isnd.Data
{
/// <summary>
/// Application Db Context
/// </summary>
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
/// <summary>
/// db context ctor
/// </summary>
/// <param name="options"></param>
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options) { }
/// <summary>
/// User API keys
/// </summary>
/// <value></value>
public DbSet<ApiKey> ApiKeys { get; set; }
/// <summary>
/// Packages
/// </summary>
/// <value></value>
public DbSet<Package> Packages { get; set; }
/// <summary>
/// Package Versions
/// </summary>
/// <value></value>
public DbSet<PackageVersion> PackageVersions { get; set; }
/// <summary>
/// Commits
/// </summary>
/// <value></value>
public DbSet<Commit> Commits { get; set; }
}
}

@ -0,0 +1,10 @@
using Microsoft.AspNetCore.Identity;
namespace isnd.Data
{
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
public string FullName { get; set; }
}
}

@ -0,0 +1,11 @@
using NuGet.Versioning;
namespace isnd.Data.Catalog
{
public class AlternatePackage
{
public string id { get ; set; }
public VersionRange range { get ; set; }
}
}

@ -0,0 +1,119 @@
using System.Net.Sockets;
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using isnd.Data.Packages;
using NuGet.Versioning;
using System.Collections.Generic;
using System;
using isnd.Interfaces;
namespace isnd.Data.Catalog
{
public class CatalogEntry : HappyIdOwner , IObject// , IPackageDetails
{
/// <summary>
/// Creates a catalog entry
/// </summary>
/// <param name="id">package details url</param>
/// <returns></returns>
public CatalogEntry(string id): base(id)
{
}
/// <summary>
/// The ID of the package
/// </summary>
/// <value></value>
[JsonProperty("id")]
public string Id { get; set; }
/// <summary>
/// The Package details url
/// </summary>
/// <returns></returns>
[JsonProperty("@id")]
public string refid { get => GetId(); }
[JsonProperty("@type")]
public string[] RefType { get; protected set; } = new string[] { "PackageDetail" };
[JsonProperty("commitId")]
public string CommitId { get; set; }
[JsonProperty("commitTimeStamp")]
public DateTime CommitTimeStamp { get; set; }
/// <summary>
/// Authors
/// </summary>
/// <value>string or array of strings</value>
public string authors { get; set; }
/// <summary>
/// The dependencies of the package, grouped by target framework
/// </summary>
/// <value>array of objects</value>
public DependencyGroup[] dependencyGroups { get; set; }
/// <summary>
/// The deprecation associated with the package
/// </summary>
/// <value></value>
public Deprecation deprecation { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
public string iconUrl { get; set; }
public string language { get; set; }
public string licenseUrl { get; set; }
public string licenseExpression { get; set; }
/// <summary>
/// Should be considered as listed if absent
/// </summary>
/// <value></value>
public bool listed { get; set; }
public string minClientVersion { get; set; }
public string projectUrl { get; set; }
public bool requireLicenseAcceptance { get; set; }
public string summary { get; set; }
/// <summary>
/// The tags
/// </summary>
/// <value></value>
public string tags { get; set; }
public string title { get; set; }
/// <summary>
/// The security vulnerabilities of the package
/// </summary>
/// <value></value>
public Vulnerabilitie[] vulnerabilities { get; set; }
public string packageContent { get; set; }
/// <summary>
/// A string containing a ISO 8601 timestamp of when the package was published
/// </summary>
/// <value></value>
[JsonProperty("published")]
public DateTime Published { get; set; }
/// <summary>
/// The full version string after normalization
/// </summary>
/// <value></value>
[Required,JsonRequired]
[JsonProperty("version")]
public string Version { get; set; }
}
}

@ -0,0 +1,6 @@
namespace isnd.Data.Catalog
{
public class DependencyGroup
{
}
}

@ -0,0 +1,14 @@
namespace isnd.Data.Catalog
{
public class Deprecation
{
/*
Legacy The package is no longer maintained
CriticalBugs The package has bugs which make it unsuitable for usage
Other The package is deprecated due to a reason not on this list
*/
public string[] reasons { get; set; } // array of strings yes The reasons why the package was deprecated
public string message { get; set; } // The additional details about this deprecation
public AlternatePackage alternatePackage { get; set; } // object no The alternate package that should be used instead
}
}

@ -0,0 +1,40 @@
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
namespace isnd.Data.Catalog
{
/// <summary>
/// Hosts a catalog entry,
/// the atomic content reference
/// </summary>
public class RegistrationLeaf
{
/*
@id string yes
catalogEntry object yes
packageContent string yes
*/
/// <summary>
/// The URL to the registration leaf
/// </summary>
/// <value></value>
[JsonProperty("@id")]
[Key][Required]
[StringLength(1024)]
public string Id { get; set; }
/// <summary>
/// The catalog entry containing the package metadata
/// </summary>
/// <value></value>
[JsonProperty("catalogEntry")]
public CatalogEntry Entry { get; set; }
/// <summary>
/// The URL to the package content (.nupkg)
/// </summary>
/// <value></value>
[JsonProperty("packageContent")]
public string PackageContent { get; set; }
}
}

@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Linq;
using isnd.Data.Packages;
using Newtonsoft.Json;
using NuGet.Versioning;
namespace isnd.Data.Catalog
{
public class RegistrationPage : HappyIdOwner
{
[JsonProperty("@id")]
public string Id { get => GetId(); }
private readonly string pkgid;
private readonly List<PackageVersion> items;
protected string Bid { get ; private set; }
protected string ExternalUrl { get; }
public RegistrationPage (string bid, string pkgid, string extUrl) : base(bid + "/" + pkgid + "/index.json")
{
Bid = bid;
Parent = Bid + $"/{pkgid}/index.json";
ExternalUrl = extUrl;
this.items = new List<PackageVersion>();
this.pkgid = pkgid;
}
public RegistrationPage(string bid, string pkgid, string extUrl, List<PackageVersion> versions) : this(bid, pkgid, extUrl)
{
AddVersionRange(versions);
}
public string GetPackageId()
{
return pkgid;
}
/// <summary>
/// The array of registration leaves and their associate metadata
/// </summary>
/// <value></value>
[JsonProperty("items")]
public CatalogEntry[] Items { get => items.Select((p) => p.ToLeave(Bid, ExternalUrl)).ToArray(); }
public void AddVersionRange(IEnumerable<PackageVersion> vitems)
{
if (vitems.Count() == 0) return;
NuGetVersion upper = null;
NuGetVersion lower = null;
if (Lower!=null) lower = new NuGetVersion(Lower);
if (Upper!=null) upper = new NuGetVersion(Upper);
// Assert.True(items.All(p=>p.Id == id));
long commitMax = 0;
foreach (var p in vitems)
{
if (items.Contains(p)) continue;
if (upper == null) upper = p.NugetVersion;
else if ( upper < p.NugetVersion) upper = p.NugetVersion;
if (lower == null) lower = p.NugetVersion;
else if (lower > p.NugetVersion) lower = p.NugetVersion;
if (p.CommitNId > commitMax) commitMax = p.CommitNId;
items.Add(p);
}
Upper = upper.ToFullString();
Lower = lower.ToFullString();
CommitId = commitMax.ToString();
}
/// <summary>
/// The highest SemVer 2.0.0 version in the page (inclusive)
/// </summary>
/// <value></value>
[JsonProperty("upper"), JsonRequired]
public string Upper { get; private set; }
/// <summary>
/// The lowest SemVer 2.0.0 version in the page (inclusive)
/// </summary>
/// <value></value>
[JsonProperty("lower"), JsonRequired]
public string Lower { get; private set; }
/// <summary>
/// The URL to the registration index
/// </summary>
/// <value></value>
[JsonProperty("parent")]
public string Parent { get; set; }
[JsonProperty("count")]
public int Count { get => items.Count; }
public string CommitId { get; internal set; }
public DateTime CommitTimeStamp { get; internal set; }
}
}

@ -0,0 +1,53 @@
using isnd.Data.Packages;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
namespace isnd.Data.Catalog
{
public class RegistrationPageIndex : HappyIdOwner
{
public RegistrationPageIndex(string url) : base(url)
{
Items = new List<RegistrationPage>();
}
public RegistrationPageIndex(string bid, string id, string extUrl, IEnumerable<Package> pkgs) : base(bid + $"/{id}/index.json")
{
Items = new List<RegistrationPage>();
long cnid = 0;
var pkgsGroups = pkgs.GroupBy(l => l.Id);
// Pour tous les groupes par Id
foreach (var gsp in pkgsGroups)
{
var pkgsbi = gsp.ToArray();
List<PackageVersion> versions = new List<PackageVersion>();
foreach(var l in pkgsbi.Select(p => p.Versions))
{
versions.AddRange(l);
foreach (var pv in l)
{
if (pv.CommitNId> cnid)
{
cnid = pv.CommitNId;
}
}
}
Items.Add(new RegistrationPage(bid, gsp.Key, extUrl, versions));
}
CommitId = cnid.ToString();
}
[JsonProperty("count")]
public int Count { get => Items.Count; }
[JsonProperty("items")]
public List<RegistrationPage> Items { get; set; }
public string CommitId { get; set; }
public DateTime CommitTimeStamp { get; internal set; }
}
}

@ -0,0 +1,25 @@
using System.Collections.Generic;
using isnd.Data.Packages;
using Newtonsoft.Json;
namespace isnd.Data.Catalog
{
public class RegistrationPageIndexQuery
{
public RegistrationPageIndexQuery()
{
}
[JsonProperty("query")]
public string Query { get; set; }
[JsonProperty("prerelease")]
public bool Prerelease { get; set; } = true;
[JsonProperty("skip")]
public int Skip { get; set; } = 0;
[JsonProperty("take")]
public int Take { get; set; } = 25;
}
}

@ -0,0 +1,9 @@
namespace isnd.Data.Catalog
{
public class Vulnerabilitie
{
public string advisoryUrl { get; set; } // string yes Location of security advisory for the package
public string severity { get; set; } // string yes Severity of advisory: "0" = Low, "1" = Moderate, "2" = High, "3" = Critical
}
}

@ -0,0 +1,31 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using isnd.Data.Packages;
using isnd.Data.Packages.Catalog;
namespace isnd.Data.Historic
{
public class PackageVersionCommit
{
public long CommitId { get; set; }
[StringLength(1024)]
public string PackageId { get; set; }
[StringLength(256)]
public string FullString { get; set; }
[StringLength(256)]
public string PackageType { get; set; }
[ForeignKey("CommitId")]
public virtual Commit Commit { get; set; }
[ForeignKey("PackageId")]
public virtual Package Package { get; set; }
[ForeignKey("PackageId,FullString,PackageType")]
public virtual PackageVersion PackageVersion { get; set; }
}
}

@ -0,0 +1,18 @@
using System;
using Newtonsoft.Json;
namespace isnd.Interfaces
{
public interface IObject
{
[JsonProperty("@type")]
public string Type { get => GetType().Name; }
[JsonProperty("commitId")]
string CommitId { get; }
[JsonProperty("commitTimeStamp")]
DateTime CommitTimeStamp { get; }
}
}

@ -0,0 +1,52 @@
using System;
using System.ComponentModel.DataAnnotations.Schema;
using isnd.Interfaces;
using Newtonsoft.Json;
namespace isnd.Data.Packages.Catalog
{
/// <summary>
/// An presence of package in a catalog,
/// for availability, or deletion,
///
/// </summary>
public class PackageRef : IObject
{
[JsonProperty("@id")]
public string RefId { get; set; }
/// <summary>
/// Reference type :
/// nuget:PackageDetails vs nuget:PackageDelete
/// </summary>
/// <value></value>
[JsonProperty("@type")]
public string RefType { get; set; }
/// <summary>
/// The NuGet Id
/// </summary>
/// <value></value>
[JsonProperty("nuget:id")]
public string Id { get; set; }
/// <summary>
/// The NuGet version
/// </summary>
/// <value></value>
[JsonProperty("nuget:version")]
public string Version { get; set; }
[JsonProperty("commitId")]
public string CommitId { get; set; }
[ForeignKey("CommitId"), JsonIgnore]
public virtual Commit LastCommit { get; set; }
[JsonProperty("commitTimeStamp")]
public DateTime CommitTimeStamp { get; set; }
}
}

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using isnd.Interfaces;
using Newtonsoft.Json;
namespace isnd.Data.Packages.Catalog
{
public class Page : IObject
{
[JsonProperty("@id")]
public string Id { get; set; }
[JsonProperty("parent")]
public string Parent { get; set; }
[JsonProperty("items")]
public virtual List<PackageRef> Items { get; set; }
public string CommitId { get; set; }
public DateTime CommitTimeStamp { get; set; }
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…