Compare commits

..

38 Commits

Author SHA1 Message Date
Paul Schneider 7ca465d4a9 JQuery version bump 2 months ago
Paul Schneider 8532b81638 WIP package resolution 2 months ago
Paul Schneider 01405abdf2 Package deletion and types 5 months ago
Paul Schneider 62a8bf27cb Error Page 5 months ago
Paul Schneider 9c9ee6cc4c trying with isn.abst 5 months ago
Paul Schneider 3af05fc034 dependencies 5 months ago
Paul Schneider 04a467dd83 registration and detail url's 6 months ago
Paul Schneider 96f91c3ba0 net-8, localization, privacy, and js ref's 6 months ago
Paul Schneider aeecc524a4 WIP /search 6 months ago
Paul Schneider e229439174 Fixes the registration page index 6 months ago
Paul Schneider c6c52a48c4 some details 6 months ago
Paul Schneider 8656bce151 fixes the catalog page 6 months ago
Paul Schneider d6180aa154 REORG 6 months ago
Paul Schneider 89e1b5a235 Testing the push method (TODO coherence between return code a physical result) 6 months ago
Paul Schneider e69462999e Cx strings contains user secrets ... 6 months ago
Paul Schneider e1a012e15b orthograph 7 months ago
Paul Schneider 16258d1c33 version bumps 7 months ago
Paul Schneider 019d858ac2 fixes the chown 7 months ago
Paul Schneider 72839e8251 Release ! 1 year ago
Paul Schneider 7987fa04a0 update 1 year ago
Paul Schneider 9e79edc624 Trying and find a package from API 1 year ago
Paul Schneider 06b0115405 Commit Id and TimerStamps 1 year ago
Paul Schneider cea05fe8ff Package Version constraints 1 year ago
Paul Schneider fa6272ac28 cleaner code 1 year ago
Paul Schneider 77a16c5551 avoid a null ref 1 year ago
Paul Schneider e2775dedaf Searching deleted package 1 year ago
Paul Schneider e5932a11c2 cleanup 1 year ago
Paul Schneider 4de566ee41 Cleanup 1 year ago
Paul Schneider d3b96088ab a better result 1 year ago
Paul Schneider 56e4b6c526 gives the store-api-key some options 1 year ago
Paul Schneider b20e822427 ignore current source setting, at serialisation 1 year ago
Paul Schneider 9fc3f7ea4a MAssive attack 1 year ago
Paul Schneider 9363cd756b makes "store-api-ey" a command 1 year ago
Paul Schneider 9e2cebde2e This "push" is only for testing purposes 1 year ago
Paul Schneider a2e22c357a Get a failed path 1 year ago
Paul Schneider ee636a29ac db upgrade 1 year ago
Paul Schneider d3f49a3c01 make packs 1 year ago
Paul Schneider 58d1f26701 No release yet 1 year ago
207 changed files with 9893 additions and 18916 deletions

@ -18,7 +18,7 @@
<target name="build" description="build all">
<exec program="dotnet" commandline="build" />
</target>
<target name="test" description="build all">
<target name="test" description="test all">
<exec program="dotnet" commandline="test" />
</target>
</project>

12
.gitignore vendored

@ -6,18 +6,16 @@
/src/isn/.vscode/
/test/isnd.tests/obj/
/test/isnd.tests/bin/
/packages/
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/
/artifacts/
/.vs/
/.vscode/
appsettings.Development.json

@ -1,29 +0,0 @@
<Properties StartupConfiguration="{9D758F00-17FF-433D-B088-F9C2D97C9BD1}|Default">
<MonoDevelop.Ide.Workbench ActiveDocument="src/isnd/isnd.csproj">
<Files>
<File FileName="src/isn/Program.cs" Line="55" Column="48" />
<File FileName="src/isnd/isnd.csproj" Line="15" Column="56" />
</Files>
<Pads>
<Pad Id="ProjectPad">
<State name="__root__">
<Node name="isn" expanded="True">
<Node name="src" expanded="True">
<Node name="isnd" selected="True" />
</Node>
<Node name="test" expanded="True" />
</Node>
</State>
</Pad>
</Pads>
</MonoDevelop.Ide.Workbench>
<MonoDevelop.Ide.ItemProperties.src.isnd PreferredExecutionTarget="MonoDevelop.Default" />
<MonoDevelop.Ide.DebuggingService.PinnedWatches />
<MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" />
<MonoDevelop.Ide.ItemProperties.test.isnd.tests PreferredExecutionTarget="MonoDevelop.Default" />
<MonoDevelop.Ide.DebuggingService.Breakpoints>
<BreakpointStore />
</MonoDevelop.Ide.DebuggingService.Breakpoints>
<MultiItemStartupConfigurations />
<MonoDevelop.Ide.ItemProperties.src.isn PreferredExecutionTarget="MonoDevelop.Default" />
</Properties>

@ -1,48 +0,0 @@
{
// Utilisez IntelliSense pour en savoir plus sur les attributs possibles.
// Pointez pour afficher la description des attributs existants.
// Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
},
{
"name": "push",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/src/isn/bin/Debug/netcoreapp2.1/isn.dll",
"requireExactSource": false,
"args": [
"push", "/home/paul/Nupkgs/Yavsc.Abstract.1.0.8.nupkg"
],
"cwd": "${workspaceFolder}/src/isn",
"stopAtEntry": false,
"console": "internalConsole"
},
{
"name": "web",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/src/isnd/bin/Debug/netcoreapp2.1/isnd.dll",
"args": [],
"cwd": "${workspaceFolder}/src/isnd",
"stopAtEntry": false,
"requireExactSource": false,
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Views"
}
}
]
}

@ -1,52 +0,0 @@
{
"omnisharp.msbuild": true,
"dotnet-test-explorer.testProjectPath": "**/*tests.csproj",
"dotnet-test-explorer.runInParallel": false,
"dotnet-test-explorer.showCodeLens": true,
"dotnet-test-explorer.testArguments": "",
"nxunitExplorer.modules": [
"test/i*/bin/Debug/*/*.tests.dll"
],
"nxunitExplorer.skippattern": "",
"dotnetCoreExplorer.runEnvVars": {
"ASPNETCORE_ENVIRONMENT": "Testing"
},
"dotnetCoreExplorer.searchpatterns": "test/**/bin/**/*.tests.{dll,exe}",
"sqltools.connections": [
{
"previewLimit": 50,
"server": "localhost",
"port": 5432,
"driver": "PostgreSQL",
"name": "isndev",
"group": "isn",
"database": "dotnetmvc",
"username": "dotnetmvc",
"password": "RvJa=y#b/tfg"
},
{
"previewLimit": 50,
"server": "localhost",
"port": 5432,
"askForPassword": true,
"driver": "PostgreSQL",
"name": "isnd",
"group": "isn",
"database": "webid",
"username": "webid"
},
{
"previewLimit": 50,
"server": "localhost",
"port": 5432,
"askForPassword": true,
"driver": "PostgreSQL",
"name": "isnddev",
"group": "isn",
"database": "isnd",
"username": "paul"
}
],
"omnisharp.disableMSBuildDiagnosticWarning": true,
"omnisharp.enableRoslynAnalyzers": false
}

@ -1,8 +0,0 @@
using System;
namespace {{namespace}}
{
public class {{name}}
{
}
}

@ -1,3 +0,0 @@
export class {{name}} {
}

@ -1,9 +0,0 @@
Imports System
Namespace {{namespace}}
Public Class {{name}}
End Class
End Namespace

@ -1,3 +0,0 @@
export default {{name}} {
}

@ -1,8 +0,0 @@
using System;
namespace {{namespace}}
{
public enum {{name}}
{
}
}

@ -1,8 +0,0 @@
using System;
namespace {{namespace}}
{
public interface {{name}}
{
}
}

@ -1,3 +0,0 @@
export interface {{name}} {
}

@ -1,46 +0,0 @@
{
"templates": [
{
"name": "Class",
"extension": "cs",
"file": "./class.cs-template",
"parameters": "./template-parameters.js"
},
{
"name": "Interface",
"extension": "cs",
"file": "./interface.cs-template",
"parameters": "./template-parameters.js"
},
{
"name": "Enum",
"extension": "cs",
"file": "./enum.cs-template",
"parameters": "./template-parameters.js"
},
{
"name": "Class",
"extension": "ts",
"file": "./class.ts-template",
"parameters": "./template-parameters.js"
},
{
"name": "Interface",
"extension": "ts",
"file": "./interface.ts-template",
"parameters": "./template-parameters.js"
},
{
"name": "Default",
"extension": "ts",
"file": "./default.ts-template",
"parameters": "./template-parameters.js"
},
{
"name": "Class",
"extension": "vb",
"file": "./class.vb-template",
"parameters": "./template-parameters.js"
}
]
}

@ -1,17 +0,0 @@
var path = require("path");
module.exports = function(filename, projectPath, folderPath) {
var namespace = "Unknown";
if (projectPath) {
namespace = path.basename(projectPath, path.extname(projectPath));
if (folderPath) {
namespace += "." + folderPath.replace(path.dirname(projectPath), "").substring(1).replace(/[\\\/]/g, ".");
}
namespace = namespace.replace(/[\\\-]/g, "_");
}
return {
namespace: namespace,
name: path.basename(filename, path.extname(filename))
}
};

66
.vscode/tasks.json vendored

@ -1,18 +1,6 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "restore",
"command": "dotnet",
"type": "process",
"args": [
"restore",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"--ignore-failed-sources"
],
"problemMatcher": "$msCompile"
},
{
"label": "build",
"command": "dotnet",
@ -21,10 +9,10 @@
"build",
"/p:Configuration=Debug",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"--ignore-failed-sources"
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
"problemMatcher": "$msCompile",
"group": "build"
},
{
"label": "db-upgrade",
@ -41,23 +29,9 @@
"env": {
"ASPNETCORE_ENV": "Development"
}
}
},
{
"label": "buildcli",
"command": "msbuild",
"type": "process",
"args": [
"src/isn",
"/p:Configuration=Debug",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"/restore"
],
"problemMatcher": "$msCompile"
},
"dependsOn":["build"],
"group": "test"
},
{
"label": "publish",
@ -74,24 +48,8 @@
"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" ]
},
"group": "none"
},
{
"label": "test",
@ -99,7 +57,7 @@
"type": "process",
"options": {
"env": {
"ASPNETCORE_ENVIRONMENT": "Testing"
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"args": [
@ -108,7 +66,8 @@
"--logger:xunit"
],
"problemMatcher": "$msCompile",
"dependsOn": [ "build", "copyTestConfig"]
"dependsOn": [ "build"],
"group": "test"
},
{
"label": "watch",
@ -124,7 +83,8 @@
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"problemMatcher": "$msCompile"
"problemMatcher": "$msCompile",
"group": "test"
}
]
}

@ -0,0 +1,46 @@
CONFIGURATION=Debug
TARGETFV=net7.0
all: build-isn build-isnd
build-%: src/%
dotnet build -p:Configuration=$(CONFIGURATION) $^
pack-%: src/%
dotnet pack $^
watch:
dotnet watch --project=src/isnd
test-push:
isn push src/isn/bin/Debug/isn.*.nupkg
clean-%: src/%
rm -rf $^/bin $^/obj
packs: pack-isn pack-isnd pack-isn.abst
clean: clean-isnd clean-isn clean-isn.abst
TARGETFRAMEWORK=net8.0
server-update:
dotnet build -c Release src/isnd
dotnet publish -c Release -f $(TARGETFRAMEWORK) src/isnd
sudo systemctl stop isnd
sudo cp -a src/isnd/bin/Release/$(TARGETFRAMEWORK)/publish/* /srv/www/isnd
sudo systemctl start isnd
client-update:
dotnet build -c Release src/isn
# MAJ du client
sudo cp -a src/isn/bin/Release/$(TARGETFRAMEWORK)/* /usr/local/lib/isn
sudo chown -R root:root /usr/local/lib/isn
src/isn.abst/bin/Release/isn.abst.1.0.24.nupkg:
dotnet pack src/isn.abst -c Release
push-test: src/isn.abst/bin/Release/isn.abst.1.0.24.nupkg
isn push -s "http://localhost:3002/v3/index.json" src/isn.abst/bin/Release/isn.abst.1.0.24.nupkg

@ -1,6 +1,6 @@
# ISN
[![pipeline status](http://gitlab.pschneider.fr/Paul/nuget-host/badges/main/pipeline.svg)](http://gitlab.pschneider.fr/Paul/nuget-host/-/commits/main)
En cours de developement, le détail du paquet n'est toujours pas fourni en API.
## Usage
@ -18,26 +18,41 @@ wget http://localhost:5000/package/index.json?q=your&prerelease=true&semVerLevel
## Installation
Depuis le dossier de la solution, compiler la solution :
### Compilation
Dans le dossier de la solution, compiler la solution :
````bash
dotnet build /restore -c Release
dotnet publish -c Release
dotnet publish -c Release src/isnd
````
### Déploiement
### Déploiement du serveur
La livraison initiale, aujourd'hui :
````bash
sudo mkdir -p /srv/www/isnd
sudo cp -a src/isnd/bin/Release/netcoreapp2.1/publish/* /srv/www/isnd
sudo cp contrib/isnd /etc/init.d/isnd
sudo chmod +x /etc/init.d/isnd
sudo chown -R www-data.www-data /srv/www/isnd
sudo cp -a src/isnd/bin/Release/net8.0/publish/* /srv/www/isnd
sudo cp contrib/isnd.service /etc/systemd/system
chown -R isn:isn /srv/www/isnd/
sudo systemctl daemon-reload
````
* Créer une base de donées Postgresql,
* ajuster un fichier de configuration `/srv/www/isnd/appsettings.Production.json`
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 :
* dans /etc/systemd/system/isnd.service , la connextion à une base de donnée Postresgql, sous la forme :
`"Server=<pgserver>;Port=<pgport>;Database=<dbname>;Username=<dbusername>;Password=<dbpass>;"`
* dans /srv/www/isnd/appsettings.Production.json, la connection au serveur de messagerie,
* l'URL externe du ou des sites à propulser, et à utiliser dans la description de service,
* et 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
@ -50,76 +65,36 @@ sudo systemctl start isnd
sudo systemctl enable isnd
````
### Installation du client
````bash
sudo mkdir /usr/local/lib/isn
sudo cp -a src/isn/bin/Release/netcoreapp2.1/* /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
Dans le détail, la séquence serait du style :
````bash
# compiler tout
dotnet build -c Release
dotnet publish -c Release -f netcoreapp2.1 src/isnd
dotnet publish -c Release -f net8.0 src/isnd
# MAJ du serveur
sudo systemctl stop isnd
sudo cp -a src/isnd/bin/Release/netcoreapp2.1/publish/* /srv/www/isnd
sudo cp -a src/isnd/bin/Release/net8.0/publish/* /srv/www/isnd
sudo systemctl start isnd
# MAJ du client
sudo cp -a src/isn/bin/Release/netcoreapp2.1/* /usr/local/lib/isn
sudo chown -R root.root /usr/local/lib/isn
sudo cp -a src/isn/bin/Release/net8.0/* /usr/local/lib/isn
sudo chown -R root:root /usr/local/lib/isn
````
## TODO
```json
{
"@id": "https://api.nuget.org/v3/registration5-semver1/",
"@type": "RegistrationsBaseUrl",
"comment": "Base URL of Azure storage where NuGet package registration info is stored"
},
{
On pourra cibler "client-update" ou "server-update", à la construction :
"@id": "https://api.nuget.org/v3-flatcontainer/",
"@type": "PackageBaseAddress/3.0.0",
"comment": "Base URL of where NuGet packages are stored, in the format https://api.nuget.org/v3-flatcontainer/{id-lower}/{version-lower}/{id-lower}.{version-lower}.nupkg"
},
{
"@id": "https://api.nuget.org/v3/registration5-semver1/",
"@type": "RegistrationsBaseUrl/3.0.0-rc",
"comment": "Base URL of Azure storage where NuGet package registration info is stored used by RC clients. This base URL does not include SemVer 2.0.0 packages."
},
{
"@id": "https://api.nuget.org/v3/registration5-semver1/",
"@type": "RegistrationsBaseUrl/3.0.0-beta",
"comment": "Base URL of Azure storage where NuGet package registration info is stored used by Beta clients. This base URL does not include SemVer 2.0.0 packages."
},
{
"@id": "https://www.nuget.org/packages/{id}/{version}?_src=template",
"@type": "PackageDetailsUriTemplate/5.1.0",
"comment": "URI template used by NuGet Client to construct details URL for packages"
},
{
"@id": "https://api.nuget.org/v3/registration5-gz-semver2/",
"@type": "RegistrationsBaseUrl/3.6.0",
"comment": "Base URL of Azure storage where NuGet package registration info is stored in GZIP format. This base URL includes SemVer 2.0.0 packages."
},
````bash
make server-update
make client-update
````

@ -1,3 +0,0 @@
#!/bin/bash
/usr/bin/mono /usr/local/lib/isn/isn.exe $*

@ -1,110 +0,0 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: isnd
# Required-Start: $local_fs $network $named $time $syslog $postgresql
# Required-Stop: $local_fs $network $named $time $syslog $postgresql
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: Script to run asp.net 5 application in background
### END INIT INFO
# Author: Ivan Derevianko aka druss <drussilla7@gmail.com>
# Modified by: Paul Schneider <redienhcs.luap@gmail.com>
. /lib/init/vars.sh
. /lib/lsb/init-functions
NAME=isnd
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
TMP_SAVE_runlevel_VAR=$runlevel
unset runlevel
running() {
if [ -f $PIDFILE ]
then
PID=$(cat $PIDFILE)
if kill -0 $PID 2>/dev/null
then
return 0
fi
fi
return 1
}
export WWW_USER=www-data
export ROOT=/srv/www/${NAME}
export DESC="$NAME"
export PIDFILE=/var/run/kestrel-${NAME}.pid
export LOGDIR=/var/log
export DOTNET_CLI_HOME=$ROOT
export ASPDOTNETCORE_ENVIRONMENT=Production
export ASPDOTNETCORE_LOGLEVEL=Information
status() {
if running;
then
echo "Service running $DESC ($NAME; pid: $PID)"
else
echo "Service stopped $DESC ($NAME)"
fi
echo WWW_USER: $WWW_USER ROOT:$ROOT DESC: $DESC NAME: $NAME PIDFILE: $PIDFILE LOGDIR=$LOGDIR
}
start() {
if running; then
echo "Service already running $DESC" "$NAME"
log_end_msg 0
else
cd $ROOT
log_daemon_msg "Starting service $NAME for user $WWW_USER"
if ! start-stop-daemon -SbmCv -u $WWW_USER -p $PIDFILE -d $ROOT -g www-data -x /usr/bin/dotnet isnd.dll run > "${LOGDIR}/kestrel-${NAME}.log"
then
log_daemon_msg "Could not start $NAME : $?, see ${LOGDIR}/kestrel-${NAME}.log"
log_end_msg 2
else
log_daemon_msg "Service $DESC started ($NAME), logs: ${LOGDIR}/kestrel-${NAME}.log"
log_end_msg 0
fi
fi
}
stop() {
if running
then
log_daemon_msg "Stopping service $NAME"
start-stop-daemon -K -p "$PIDFILE"
log_daemon_msg "$DESC stopped"
log_end_msg 0
else
log_daemon_msg "$DESC Service not running"
log_end_msg 1
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
*)
echo "Usage: $0 {start|stop|restart}"
esac
export runlevel=$TMP_SAVE_runlevel_VAR

@ -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/
ExecStart=/srv/www/isnd/isnd
Restart=always
Environment="HOME=/srv/www/isnd"
Environment="ASPNETCORE_ENVIRONMENT=Production"
Environment="ASPNETCORE_ConnectionStrings__DefaultConnection=Server=localhost;Port=5432;Database=isnd;Username=paul;Password=RvJa=y#b/tfg;"
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=isnd
[Install]
WantedBy=multi-user.target

@ -1,13 +0,0 @@
#!/bin/bash
set -e
# compiler tout
dotnet build -c Release
dotnet publish -c Release -f netcoreapp2.1 src/isnd
# MAJ du serveur
sudo systemctl stop isnd
sudo cp -a src/isnd/bin/Release/netcoreapp2.1/publish/* /srv/www/isnd
sudo systemctl start isnd
# MAJ du client
sudo cp -a src/isn/bin/Release/netcoreapp2.1/* /usr/local/lib/isn
sudo chown -R root.root /usr/local/lib/isn

@ -1,30 +1,41 @@
{
"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"
]
}
"version": 1,
"isRoot": true,
"tools": {
"codecov.tool": {
"version": "1.13.0",
"commands": [
"codecov"
],
"rollForward": false
},
"gitversion.tool": {
"version": "5.10.1",
"commands": [
"dotnet-gitversion"
],
"rollForward": false
},
"gitreleasemanager.tool": {
"version": "0.13.0",
"commands": [
"dotnet-gitreleasemanager"
],
"rollForward": false
},
"Wyam2.Tool": {
"version": "3.0.0-rc3",
"commands": [
"wyam2"
],
"rollForward": false
},
"dotnet-ef": {
"version": "8.0.7",
"commands": [
"dotnet-ef"
],
"rollForward": false
}
}
}
}

@ -0,0 +1,12 @@
drop table "AspNetRoleClaims" ;
drop table "AspNetUserRoles" ;
drop table "AspNetRoles" ;
drop table "AspNetUserClaims" ;
drop table "AspNetUserTokens" ;
drop table "PackageVersions" ;
drop table "Packages" ;
drop table "Commits" ;
drop table "ApiKeys" ;
drop table "AspNetUserLogins" ;
drop table "AspNetUsers" ;
drop table "__EFMigrationsHistory" ;

@ -1,9 +1,9 @@
{
"dotnet": {
"enabled": false
"enabled": true
},
"msbuild": {
"enabled": true
"enabled": false
},
"Dnx": {
"enabled": false

@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace isn
{
public class APIKO
{
public string Context { get; set; }
public Dictionary<string, string[]> Errors { get; set; }
}
}

@ -1,21 +1,23 @@
using System;
using isn.abst;
namespace isnd.Entities
{
public static class ApiConfig
{
public const string Publish = "put";
public const string Index = "index";
public const string IndexDotJson = Index + ".json";
public const string Catalog = "catalog";
public const string CatalogPage = "catalog-page";
public const string GetPackage = Constants.PaquetFileEstension;
public const string GetVersion = "version";
public const string Search = "search";
public const string AutoComplete = "autocomplete";
public const string CatalogLeaf = "catalog-leaf";
public const string Delete = "delete";
public const string Registration = "registration";
internal const string GetNuspec = Constants.SpecFileEstension;
public const string Index = "/index.json";
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 Content = "/content";
public const string Nuget = "/nuget";
[Obsolete("use the V3 search")]
public const string V2Find = "/v2/FindPackagesById()"; // /FindPackagesById()??$filter=IsLatestVersion&$orderby=Version desc&$top=1&id='isn.abst'
}
}

@ -1,9 +1,14 @@
using isnd.Data.Catalog;
using Newtonsoft.Json;
namespace isn.Abstract
{
public class ApiIndexViewModel
public class ApiIndexViewModel : Permalink
{
public ApiIndexViewModel(string id) : base(id, "ApiIndex")
{
}
[JsonProperty("version")]
public string Version { get; set; }

@ -2,8 +2,8 @@ namespace isn.abst
{
public static class Constants
{
public const string PaquetFileEstension = "nupkg";
public const string SpecFileEstension = "nuspec";
public const string JsonFileEstension = "json";
public const string PacketFileExtension = "nupkg";
public const string SpecFileExtension = "nuspec";
public const string ApiVersionPrefix = "/v3";
}
}

@ -0,0 +1,48 @@
using Newtonsoft.Json;
namespace isnd.Data.Catalog
{
public abstract class Permalink
{
public Permalink(string id)
{
Type = GetType().Name;
this.id = id;
}
public Permalink(string id, string type)
{
Type = type;
this.id = id;
}
[JsonProperty("@type")]
public virtual string Type { get; set; }
[JsonProperty("@id")]
public string Id { get => id; }
protected string id;
public string GetId() { return id; }
public override bool Equals(object obj)
{
if (obj!=null)
{
if (GetType().IsAssignableFrom(obj.GetType()))
{
var rpobj = (Permalink) obj;
return this.id == rpobj.id;
}
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return id.GetHashCode();
}
}
}

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

@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageVersion>1.0.1</PackageVersion>
<Version>1.0.5</Version>
<TargetFrameworks>netcoreapp2.1</TargetFrameworks>
<Version>1.0.7</Version>
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
<NoWarn>NETSDK1138</NoWarn>
<AssemblyVersion>1.0.5.0</AssemblyVersion>
<FileVersion>1.0.5.0</FileVersion>
<InformationalVersion>1.0.5+Branch.main.Sha.14206ac477d0f07566d5e8125dc52cbd7f474ca2</InformationalVersion>
<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" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>

@ -1,46 +0,0 @@
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)
{
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());
}
}
}

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

@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Mono.Options;
using Newtonsoft.Json;
@ -16,15 +18,22 @@ namespace isn
if (cfgSettingIf.Exists)
{
var json = File.ReadAllText(cfgSettingIf.FullName);
settings = JsonConvert.DeserializeObject<Settings>(json);
currentSource = settings.DefaultSource;
Settings = JsonConvert.DeserializeObject<Settings>(json);
CurrentSource = Settings.DefaultSourceKey;
}
if (Settings==null)
{
Settings= Settings.Create();
}
rsa = RSA.Create(Settings.RSAParameters);
}
static OptionSet storeoptions = new OptionSet {
{ "s|source=", "use source", val => currentSource = currentSource ?? val },
static readonly OptionSet storeoptions = new OptionSet {
{ "s|source=", "use source", val => Settings.CurrentSourceKey ??= val },
{ "h|help", "show this message and exit", h => shouldShowPushHelp = h != null },
};
private static string _configFileName =
private static readonly string _configFileName =
Path.Combine(
Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.UserProfile), ".isn"),
@ -32,54 +41,43 @@ namespace isn
;
public const string push = "push";
static OptionSet options = new OptionSet {
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 OptionSet pushoptions = new OptionSet {
{ "k|api-key=", "use api key", val => apiKey = apiKey ?? val },
{ "p|store-api-key", "store used api key (=<true|false>)", val => storApiKey = val != null },
{ "s|source=", "use source", val => currentSource = currentSource ?? val },
static readonly OptionSet pushoptions = new OptionSet {
{ "k|api-key=", "use api key", val => Settings.CurrentSource.SetApiKey(rsa, val)},
{ "s|source=", "use source", val => Settings.CurrentSourceKey = val },
{ "h|help", "show this message and exit", h => shouldShowPushHelp = h != null },
};
static OptionSet sourceoptions = new OptionSet {
static readonly OptionSet sourceoptions = new OptionSet {
{ "h|help", "show this message and exit", h => shouldShowSourceHelp = h != null },
};
static OptionSet showOptions = new OptionSet {
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 apiKey = null;
private static string currentSource = null;
private static int pushKO = 0;
private static bool storApiKey = false;
public static IDataProtector Protector { get; set; } = new DefaultDataProtector();
static Settings settings = null;
public static RSA rsa;
public static Settings Settings
{
get
{
if (settings == null)
LoadConfig();
if (settings == null)
settings = new Settings
{
DataProtectionTitle = "isn",
Sources = new Dictionary<string, SourceSettings>()
};
return settings;
}
get; set;
}
public static string CurrentSource { get => Settings.CurrentSourceKey; set => Settings.CurrentSourceKey = value; }
static int Main(string[] args)
{
LoadConfig();
var commandSet = new CommandSet("isn");
var srclst = new Command("list")
{
@ -150,13 +148,15 @@ namespace isn
{
Run = sargs => Add(sargs)
};
commandSet.Add(add);
var pushCmd = new Command(push)
{
Run = async sargs =>
Run = sargs =>
{
var pargs = pushoptions.Parse(sargs);
if (args.Count()==0) shouldShowPushHelp=true;
if (shouldShowPushHelp)
{
// output the options
@ -165,17 +165,19 @@ namespace isn
return;
}
List<PushReport> reports = PushPkg(pargs);
Console.WriteLine(JsonConvert.SerializeObject(reports));
pushKO = reports.Count(r => !r.OK && !r.AlreadyPresent);
}
};
var setapikey = new Command("set-api-key")
var setapikey = new Command("store-api-key", "Store this API key")
{
Run = sargs => StoreApiKey(sargs)
};
commandSet.Add(pushCmd);
setapikey.Options = pushoptions;
commandSet.Add(setapikey);
commandSet.Add(pushCmd);
commandSet.Add(srcCmd);
commandSet.Add(showCommand);
@ -202,9 +204,11 @@ namespace isn
return 1;
}
int runCode = commandSet.Run(args);
return (runCode == 0 && pushKO > 0) ? 500 : runCode;
if (shouldShowVersion)
{
Console.WriteLine("isn version " + GitVersionInformation.AssemblySemFileVer);
}
return commandSet.Run(args);
}
}
}

@ -1,19 +1,92 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json;
namespace isn
{
public class SourceSettings
{
public string ApiKey { get; set; }
public string Alias { get; set; }
/// <summary>
/// Protected API Key
/// </summary>
/// <value></value>
public string ProtectedApiKey { get; set; }
/// <summary>
/// Key alias
/// </summary>
/// <value></value>
public string Url { get; set; }
public SourceSettings()
{
}
public string GetClearApiKey(RSA rsa)
{
var decrypted = rsa.Decrypt(System.Convert.FromBase64String(ProtectedApiKey), RSAEncryptionPadding.Pkcs1);
return Encoding.Default.GetString(decrypted);
}
public void SetApiKey(RSA rsa, string key)
{
var ciphered =rsa.Encrypt(Encoding.Default.GetBytes(key), RSAEncryptionPadding.Pkcs1);
ProtectedApiKey = System.Convert.ToBase64String(ciphered);
}
}
public class Settings
{
public string DataProtectionTitle {get; set; }
private Settings()
{
}
public static Settings Create()
{
var rsaParams = CreateCipheringParameters();
return new Settings {
RSAParameters = rsaParams,
Sources = new Dictionary<string, SourceSettings>()
};
}
public RSAParameters RSAParameters { get; set; }
public Dictionary<string, SourceSettings> Sources { get; set; }
public bool AutoUpdateApiKey { get; set; } = false;
public string DefaultSource { get; set; }
private string defSourceKey;
/// <summary>
/// Default source by its alias
/// </summary>
/// <value></value>
public string DefaultSourceKey
{
get => defSourceKey;
set
{
defSourceKey = value;
}
}
[JsonIgnore, NotMapped]
public string CurrentSourceKey {get; set;}
private static RSAParameters CreateCipheringParameters()
{
var provider = new RSACryptoServiceProvider(2048);
return provider.ExportParameters(true);
}
[JsonIgnore, NotMapped]
public SourceSettings CurrentSource
{
get => this.Sources[CurrentSourceKey];
}
}
}
}

@ -17,8 +17,21 @@ namespace isn
// var json = await client.GetStringAsync(new System.Uri(url));
Task.Run(async ()=> {
try {
var response = await client.GetStringAsync(url);
result = JsonConvert.DeserializeObject<ApiIndexViewModel>(response);
} catch (HttpRequestException ex)
{
if (ex.StatusCode==HttpStatusCode.NotFound)
{
Console.Error.WriteLine("Not found ... server's down ?");
}
else
{
Console.Error.WriteLine($"{ex.StatusCode} : {ex.Message}");
}
}
}).Wait();
return result;

@ -4,6 +4,7 @@ using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace isn
{
@ -24,35 +25,19 @@ namespace isn
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);
}
if (result.IsSuccessStatusCode) return
new PushReport() {
KO = JsonConvert.DeserializeObject<APIKO>(await result.Content.ReadAsStringAsync())
};
else
{
string ereport = await result.Content.ReadAsStringAsync();
Console.WriteLine(ereport);
}
return new PushReport();
return new PushReport() {
OK = true
};
}
}
}

@ -1,195 +0,0 @@
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace isn
{
public class UploadFilesToServerUsingWebRequest
{
public void UploadFilesToServer(PushReport report, Uri uri, FileInfo fi,
string apikey)
{
// string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
const int TXLEN = 0x1000;
/// the form-data file upload, properly formatted
string fileheaderTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\";\r\nContent-Type: {2}\r\n\r\n";
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
// "X-NuGet-ApiKey
string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
string fileheader = string.Format(fileheaderTemplate, "file", fi.Name, "application/octet-stream");
byte[] fileheaderbytes = Encoding.ASCII.GetBytes(fileheader);
var boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
var endBoundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--");
HttpWebRequest httpWebRequest = (HttpWebRequest) WebRequest.Create(uri);
httpWebRequest.Method = "PUT";
httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary;
httpWebRequest.AllowAutoRedirect = false;
httpWebRequest.Headers.Add("X-NuGet-Client-Version", Constants.ClientVersion);
httpWebRequest.Headers.Add("X-NuGet-ApiKey", apikey);
httpWebRequest.ContentLength = boundarybytes.Length +
fileheaderbytes.Length + fi.Length + endBoundaryBytes.Length;
httpWebRequest.BeginGetRequestStream(async (result) =>
{
try
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
using (Stream requestStream = request.EndGetRequestStream(result))
{
await WriteToStream(requestStream, boundarybytes, boundarybytes.Length);
await WriteToStream(requestStream, fileheaderbytes, fileheaderbytes.Length);
using (var fss = fi.OpenRead())
{
byte[] buffer = new byte[TXLEN];
var form_bytes_read = fss.Read(buffer, 0, TXLEN);
while (form_bytes_read > 0)
{
await WriteToStream(requestStream, buffer, form_bytes_read);
form_bytes_read = fss.Read(buffer, 0, TXLEN);
}
}
requestStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
requestStream.Close();
}
}
catch (Exception rex)
{
report.Executed = false;
report.StackTrace = rex.StackTrace;
report.Message = rex.Message;
Console.Error.WriteLine("Stack trace:");
Console.Error.WriteLine(rex.StackTrace);
WebResponse eresp = httpWebRequest.GetResponse();
if (!CheckResponse(eresp, report))
throw new Exception("Invalid server response type");
}
}, httpWebRequest);
WebResponse resp = httpWebRequest.GetResponse();
if (!CheckResponse(resp, report)) throw new Exception("Invalid server response type");
if (Program.Settings.AutoUpdateApiKey)
Program.EnsureKeyStored();
}
static bool CheckResponse(WebResponse resp, PushReport report)
{
Stream stream = resp.GetResponseStream();
StreamReader re = new StreamReader(stream);
if (resp is HttpWebResponse)
{
if (resp.ContentType == "text/json")
{
String json = re.ReadToEnd();
report.Message = json;
var hrep = resp as HttpWebResponse;
report.StatusCode = hrep.StatusCode.ToString();
report.OK = hrep.StatusCode == HttpStatusCode.Accepted
|| hrep.StatusCode == HttpStatusCode.OK;
return true;
}
}
return false;
}
/// <summary>
/// Creates HTTP POST request &amp; uploads database to server. Author : Farhan Ghumra
/// </summary>
internal async Task UploadFilesToServerAsync(PushReport report, Uri uri, FileInfo fi,
string apikey)
{
// string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
const int TXLEN = 0x1000;
/// the form-data file upload, properly formatted
string fileheaderTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\";\r\nContent-Type: {2}\r\n\r\n";
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
// "X-NuGet-ApiKey
string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
string fileheader = string.Format(fileheaderTemplate, "file", fi.Name, "application/octet-stream");
byte[] fileheaderbytes = Encoding.ASCII.GetBytes(fileheader);
var boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
var endBoundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--");
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);
httpWebRequest.Method = "PUT";
httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary;
httpWebRequest.AllowAutoRedirect = false;
httpWebRequest.Headers.Add("X-NuGet-Client-Version", Constants.ClientVersion);
httpWebRequest.Headers.Add("X-NuGet-ApiKey", apikey);
httpWebRequest.ContentLength = boundarybytes.Length +
fileheaderbytes.Length + fi.Length + endBoundaryBytes.Length;
httpWebRequest.BeginGetRequestStream(async (result) =>
{
try
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
using (Stream requestStream = request.EndGetRequestStream(result))
{
await WriteToStream(requestStream, boundarybytes, boundarybytes.Length);
await WriteToStream(requestStream, fileheaderbytes, fileheaderbytes.Length);
using (var fss = fi.OpenRead())
{
byte[] buffer = new byte[TXLEN];
var form_bytes_read = fss.Read(buffer, 0, TXLEN);
while (form_bytes_read > 0)
{
await WriteToStream(requestStream, buffer, form_bytes_read);
form_bytes_read = fss.Read(buffer, 0, TXLEN);
}
}
requestStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
requestStream.Close();
}
}
catch (Exception rex)
{
report.Message = rex.Message;
Console.Error.WriteLine(rex.Message);
Console.Error.WriteLine("Stack trace:");
Console.Error.WriteLine(rex.StackTrace);
throw;
}
}, httpWebRequest);
WebResponse resp = await httpWebRequest.GetResponseAsync();
Stream stream = resp.GetResponseStream();
StreamReader re = new StreamReader(stream);
if (resp is HttpWebResponse)
{
String json = await re.ReadToEndAsync();
report.Message = json;
var hrep = resp as HttpWebResponse;
report.StatusCode = hrep.StatusCode.ToString();
report.OK = hrep.StatusCode == HttpStatusCode.Accepted
|| hrep.StatusCode == HttpStatusCode.OK;
}
else throw new Exception("Invalid server response type");
}
/// <summary>
/// Writes byte array to stream. Author : Farhan Ghumra
/// </summary>
private static async Task WriteToStream(Stream s, byte[] bytes, int len)
{
await s.WriteAsync(bytes, 0, len);
}
}
}

@ -10,12 +10,18 @@ namespace isn
{
public class PushCommand
{
static public PushReport Run(string pkg, string source)
Settings settings;
public PushCommand(Settings settings)
{
this.settings = settings;
}
public PushReport Run(string pkg, string source, string apiKey)
{
if (source == null) source = Program.Settings.DefaultSource;
if (source == null) throw new InvalidOperationException("source is null");
string apikey = Program.Protector.UnProtect(Program.Settings.Sources[source].ApiKey);
var resources = SourceHelpers.GetServerResources(source);
if (resources == null) return null;
if (resources.Resources == null)
throw new InvalidOperationException("source gave no resource");
if (!resources.Resources.Any(res => res.Type == "PackagePublish/2.0.0"))
@ -27,26 +33,30 @@ namespace isn
var report = new PushReport
{
PkgName = fi.Name,
Message = "Le fichier n'existe pas"
Message = "The package does not exist : " + fi.FullName
};
return report;
}
using (var client = new HttpClient())
using (var client = new HttpClient(
new HttpClientHandler
{
AllowAutoRedirect = false
}
))
try
{
Console.WriteLine("Connecting to "+ pubRes.Id);
return client.UploadFilesToServer(new Uri(pubRes.Id), fi, apikey);
return client.UploadFilesToServer(new Uri(pubRes.Id), fi, settings.Sources[source].GetClearApiKey(Program.rsa));
}
catch (HttpRequestException hrex)
catch (HttpRequestException httpEx)
{
var report = new PushReport
{
PkgName = fi.Name,
Message = "HttpRequest: " + hrex.Message,
StackTrace = hrex.StackTrace,
StatusCode = hrex.HResult.ToString()
Message = "HttpRequest: " + httpEx.Message,
StackTrace = httpEx.StackTrace,
StatusCode = httpEx.HResult.ToString()
};
Console.Error.WriteLine(hrex.Message);
Console.Error.WriteLine(httpEx.Message);
return report;
}
catch (Exception ex)

@ -12,17 +12,15 @@ namespace isn
public static List<PushReport> PushPkg(IEnumerable<string> pkgs)
{
List<PushReport> pushReports = new List<PushReport>();
var cmd = new PushCommand(Settings);
if (Settings.CurrentSource == null) throw new InvalidOperationException("source is null");
var source = Settings.CurrentSource;
foreach (string pkg in pkgs)
{
var report = PushCommand.Run(pkg, currentSource);
var report = cmd.Run(pkg, source.Url, source.GetClearApiKey(rsa));
pushReports.Add(report);
}
if (storApiKey)
{
EnsureKeyStored();
}
return pushReports;
}

@ -1,75 +0,0 @@
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.DefaultSource == null)
return;
currentSource = Settings.DefaultSource;
}
if (Settings.Sources.ContainsKey(currentSource))
{
if (apiKey == null)
{
// Une suppression
Settings.Sources.Remove(currentSource);
if (Settings.DefaultSource == currentSource) Settings.DefaultSource = null;
}
else
{
// Une mise À jour
string ptd = Protector.Protect(apiKey);
Settings.Sources[currentSource].ApiKey = ptd;
if (Settings.DefaultSource == null) Settings.DefaultSource = currentSource;
}
}
else if (apiKey != null)
{
// une addition
string ptd = Protector.Protect(apiKey);
Settings.Sources.Add(currentSource, new SourceSettings { ApiKey = ptd });
}
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
));
}
}
}

@ -16,7 +16,7 @@ namespace isn
{
SourceSettings setting = Settings.Sources[arg];
throw new InvalidOperationException
(setting.Alias);
(setting.Url);
}
throw new NotImplementedException();
}

@ -11,9 +11,9 @@ namespace isn
SourceSettings settings =
Settings.Sources.ContainsKey(arg) ?
Settings.Sources[arg] :
Settings.Sources.Values.FirstOrDefault((s)=> s.Alias == arg) ;
Settings.Sources.Values.FirstOrDefault((s)=> s.Url == arg) ;
if (settings==null) throw new InvalidOperationException(arg);
Settings.DefaultSource = arg;
Settings.DefaultSourceKey = arg;
SaveConfig();
}

@ -0,0 +1,46 @@
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 (args.Count != 1)
{
Console.Error.WriteLine("StoreApiKey command takes only one argument, the key.");
shouldShowPushHelp=true;
}
if (shouldShowPushHelp)
{
// output the options
Console.Error.WriteLine("StoreApiKey Options:");
storeoptions.WriteOptionDescriptions(Console.Out);
}
else
{
Settings.Sources[Settings.CurrentSourceKey].SetApiKey(Program.rsa, args[0]);
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
));
Console.WriteLine("config saved .");
}
}
}

@ -1,29 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.1</TargetFrameworks>
<RuntimeIdentifiers>linux-x64</RuntimeIdentifiers>
<TargetFrameworks>net8.0</TargetFrameworks>
<RootNamespace>nuget_cli</RootNamespace>
<UserSecretsId>45b74c62-05bc-4603-95b4-3e80ae2fdf50</UserSecretsId>
<Version>1.0.5</Version>
<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.5.0</AssemblyVersion>
<FileVersion>1.0.5.0</FileVersion>
<InformationalVersion>1.0.5+Branch.main.Sha.14206ac477d0f07566d5e8125dc52cbd7f474ca2</InformationalVersion>
<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="System.Security.Cryptography.Pkcs" Version="8.0.0" />
<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="microsoft.codeanalysis.analyzers" Version="1.1.0" />
<Reference Include="System.Net.Http" Version="4.0.0" />
<PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="unleash.client" Version="4.1.6" />
<PackageReference Include="GitVersion.MsBuild" Version="5.12.0" />
<ProjectReference Include="../isn.abst/isn.abst.csproj" />
</ItemGroup>
</Project>

@ -1,15 +1,42 @@
using System.Threading.Tasks.Dataflow;
using System.Net;
using System.Text;
using Newtonsoft.Json;
namespace isn
{
public class PushReport
{
public 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 bool Executed { get; set; }
public bool OK { get; set; }
public bool AlreadyPresent { get; set; }
public string Message { get; set; }
public string StatusCode { get; set; }
public string StackTrace { get; set; }
public APIKO KO { get; set; }
public string ToDoc()
{
StringBuilder sb = new StringBuilder($"= push {PkgName}\n\n");
if (Executed) sb.AppendLine("* Executed");
if (OK) sb.AppendLine("* OK");
if (!string.IsNullOrWhiteSpace(Message))
sb.AppendLine("* Message :" + Message);
if (!string.IsNullOrWhiteSpace(StatusCode))
sb.AppendLine($"* Status Code : ");
if (!string.IsNullOrWhiteSpace(StackTrace))
sb.AppendLine($"* StackTrace : " + StackTrace);
if (KO!=null)
sb.AppendLine($"* KO : " + KO.Context);
return sb.ToString();
}
}
}

@ -5,6 +5,4 @@ namespace isnd.Authorization
internal class ValidApiKeyRequirement : IAuthorizationRequirement
{
}
}

@ -13,6 +13,7 @@ using Microsoft.Extensions.Options;
using isnd.Data;
using isnd.Entities;
using isnd.Data.ApiKeys;
using isnd.Interfaces;
namespace isnd.Controllers
@ -23,17 +24,20 @@ namespace isnd.Controllers
private readonly ApplicationDbContext dbContext;
private readonly IsndSettings isndSettings;
private readonly UserManager<ApplicationUser> _userManager;
private readonly IApiKeyProvider apiKeyProvider;
private readonly IDataProtector protector;
public ApiKeysController(ApplicationDbContext dbContext,
IOptions<IsndSettings> isndSettingsOptions,
IDataProtectionProvider provider,
UserManager<ApplicationUser> userManager)
UserManager<ApplicationUser> userManager,
IApiKeyProvider apiKeyProvider
)
{
this.dbContext = dbContext;
this.isndSettings = isndSettingsOptions.Value;
protector = provider.CreateProtector(isndSettings.ProtectionTitle);
_userManager = userManager;
this.apiKeyProvider = apiKeyProvider;
}
[HttpGet]
@ -57,17 +61,17 @@ namespace isnd.Controllers
[HttpPost]
public async Task<ActionResult> Create(CreateModel model)
{
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
IQueryable<ApiKey> userKeys = GetUserKeys();
string userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
IQueryable<ApiKey> userKeys = apiKeyProvider.GetUserKeys(User.Identity.Name);
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();
model.UserId = userId;
ApiKey newKey = await apiKeyProvider.CreateApiKeyAsync(model);
return View("Details", new DetailModel { Name = newKey.Name,
ProtectedValue = protector.Protect(newKey.Id),
ApiKey = newKey });
@ -79,7 +83,6 @@ namespace isnd.Controllers
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]
@ -103,7 +106,7 @@ namespace isnd.Controllers
ApiKey key = await dbContext.ApiKeys.FirstOrDefaultAsync(k => k.Id == id && k.UserId == userid);
if (key == null)
{
ModelState.AddModelError(null, "Key not found");
ModelState.AddModelError("id", "Key not found");
return View();
}
return View("Details", new DetailModel { ApiKey = key, Name = key.Name, ProtectedValue = protector.Protect(key.Id)});

@ -4,23 +4,25 @@ 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>
public HomeController(
ApplicationDbContext dbContext,
IUnleash unleashĈlient)
ApplicationDbContext dbContext)
{
_dbContext = dbContext;
_unleashĈlient = unleashĈlient;
}
public IActionResult Index()
@ -28,9 +30,7 @@ namespace isnd.Controllers
return View(new HomeIndexViewModel{
PkgCount = _dbContext.Packages
.Where(p => p.Versions.Count > 0)
.Count(),
UnleashClient = _unleashĈlient
});
.Count()});
}
public IActionResult About()
@ -59,9 +59,9 @@ namespace isnd.Controllers
return View(ViewData);
}
public IActionResult Error()
public IActionResult Error(string id)
{
return View();
return View("Error", id);
}
}
}

@ -10,7 +10,7 @@ namespace isnd.Controllers
public class NewUpdateController : Controller
{
[Authorize(Policy = IsndConstants.RequireAdminPolicyName)]
public IActionResult NewRelease(NewReleaseInfo version)
public IActionResult NewRelease(NewReleaseInfo release)
{
throw new NotImplementedException("web hook");
}

@ -1,31 +1,39 @@
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;
using isn.abst;
using isnd.Interfaces;
using System.Linq;
using isnd.Entities;
namespace isnd.Controllers
{
public partial class PackagesController : Controller
/// <summary>
/// Api Controller
/// </summary>
public class ApiController : Controller
{
[HttpGet(_pkgRootPrefix + ApiConfig.IndexDotJson)]
private readonly IPackageManager packageManager;
private readonly Resource[] resources;
/// <summary>
/// Api Controller Constructor
/// </summary>
/// <param name="pm"></param>
public ApiController(IPackageManager pm)
{
packageManager = pm;
resources = packageManager.GetResources().ToArray();
}
/// <summary>
/// API index
/// </summary>
/// <returns></returns>
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Index)]
public IActionResult ApiIndex()
{
return Ok(new ApiIndexViewModel{ Version = PackageManager.BASE_API_LEVEL, Resources = resources });
return Ok(new ApiIndexViewModel(packageManager.CatalogBaseUrl){ Version = PackageManager.BASE_API_LEVEL, Resources = resources });
}
}

@ -1,69 +0,0 @@
using System.Linq;
using System.Threading.Tasks;
using isnd.Services;
using isnd.Entities;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using NuGet.Versioning;
namespace isnd.Controllers
{
public partial class PackagesController
{
// https://docs.microsoft.com/en-us/nuget/api/catalog-resource#versioning
[HttpGet(_pkgRootPrefix + ApiConfig.Catalog)]
public IActionResult CatalogIndex()
{
return Ok(PackageManager.CurrentCatalogIndex);
}
[HttpGet(_pkgRootPrefix + ApiConfig.CatalogPage + "-{id}")]
public IActionResult Index(string id)
{
// https://docs.microsoft.com/en-us/nuget/api/catalog-resource#versioning
return Ok(PackageManager.CurrentCatalogPages[int.Parse(id)]);
}
[HttpGet(_pkgRootPrefix + "{apiVersion}/" + ApiConfig.Registration + "/{id}/index.json")]
public async Task<IActionResult> CatalogRegistrationAsync(string apiVersion, string id)
{
var pkgs = packageManager.SearchById(id, null, null);
if (pkgs == null) return NotFound();
return Ok(pkgs);
}
[HttpGet(_pkgRootPrefix + ApiConfig.CatalogLeaf + "/{id}/{version}/{lower}/index.json")]
public async Task<IActionResult> CatalogLeafAsync(string id, string pversion, string lower)
{
bool askForindex = lower == null;
if (false)
{
if (!NuGetVersion.TryParse(lower, out NuGetVersion version))
return BadRequest(lower);
var pkgFromname = packageManager.GetVersions(id, version, true);
if (pkgFromname == null) return NotFound();
return Ok(pkgFromname);
}
var pkgvs = this.packageManager.GetCatalogLeaf(id, pversion, lower).ToArray();
if (pkgvs.Count() == 0) return NotFound();
List<string> types = pkgvs.Select(
v => v.Type ?? "Dependency"
).Distinct().ToList();
if (!types.Contains("PackageDelete"))
types.Add("PackageDetails");
var last = pkgvs.Last();
var pub = last.LatestCommit.CommitTimeStamp;
return Ok(new Data.Packages.Catalog.CatalogLeaf
{
CommitId = last.CommitId,
Id = id,
CommitTimeStamp = pub,
Version = last.FullString,
Published = pub,
RefType = types.ToArray()
});
}
}
}

@ -1,55 +0,0 @@
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(_pkgRootPrefix + ApiConfig.GetPackage + "/{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(_pkgRootPrefix + 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");
}
}
}

@ -1,14 +1,15 @@
using isnd.Services;
using isnd.Entities;
using Microsoft.AspNetCore.Mvc;
using isn.abst;
namespace isnd.Controllers
{
public partial class PackagesController
public partial class PackagesController
{
// GET /autocomplete?id=isn.protocol&prerelease=true
[HttpGet(_pkgRootPrefix + ApiConfig.AutoComplete)]
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.AutoComplete)]
public IActionResult AutoComplete(
string id,
string semVerLevel,

@ -0,0 +1,42 @@
using System.Threading.Tasks;
using isnd.Entities;
using Microsoft.AspNetCore.Mvc;
using isn.abst;
namespace isnd.Controllers
{
public partial class PackagesController
{
// https://docs.microsoft.com/en-us/nuget/api/catalog-resource#versioning
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Catalog)]
public async Task<IActionResult> CatalogIndex()
{
return Ok(await packageManager.GetCatalogIndexAsync());
}
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Content + "/{id}/{version}.json")]
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Registration + "/{id}/{version}.json")]
public async Task<IActionResult> CatalogRegistration(string id, string version)
{
if ("index" == version)
{
var query = new Data.Catalog.PackageRegistrationQuery
{
Query = id,
Prerelease = true
};
var index = await packageManager.GetPackageRegistrationIndexAsync(query);
if (index == null) return NotFound();
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);
}
}
}

@ -5,12 +5,13 @@ 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(_pkgRootPrefix + ApiConfig.Delete + "/{id}/{lower?}/{type?}")]
[HttpDelete("~" + Constants.ApiVersionPrefix + ApiConfig.Package + "/{id}/{lower?}/{type?}")]
public async Task<IActionResult> ApiDelete(
[FromRoute][SafeName][Required] string id,
[FromRoute][SafeName][Required] string lower,

@ -0,0 +1,57 @@
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.ApiVersionPrefix + ApiConfig.Nuget + "/{id}/{lower}/{idf}-{lowerFromName}."
+ Constants.PacketFileExtension)]
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Content + "/{id}/{lower}/{idf}-{lowerFromName}."
+ Constants.PacketFileExtension)]
public IActionResult GetPackage(
[FromRoute][SafeName][Required] string id,
[FromRoute][SafeName][Required] string lower,
[FromRoute] string idf, [FromRoute] string lowerFromName)
{
var pkgPath = Path.Combine(isndSettings.PackagesRootDir,
id, lower, $"{id}-{lower}." + Constants.PacketFileExtension
);
FileInfo pkgFileInfo = new FileInfo(pkgPath);
if (!pkgFileInfo.Exists)
{
return BadRequest("!pkgFileInfo.Exists");
}
return File(pkgFileInfo.OpenRead(), "application/zip; charset=binary");
}
// Web get spec
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Nuspec + "/{id}/{lower}/{idf}-{lowerFromName}."
+ Constants.SpecFileExtension)]
public IActionResult GetNuspec(
[FromRoute][SafeName][Required] string id,
[FromRoute][SafeName][Required] string lower,
[FromRoute][SafeName][Required] string idf,
[FromRoute][SafeName][Required] string lowerFromName)
{
var pkgPath = Path.Combine(isndSettings.PackagesRootDir,
id, lower, $"{id}." + Constants.SpecFileExtension);
FileInfo pkgFileInfo = new FileInfo(pkgPath);
if (!pkgFileInfo.Exists)
{
return BadRequest("!pkgFileInfo.Exists");
}
return File(pkgFileInfo.OpenRead(), "text/xml; charset=utf-8");
}
}
}

@ -1,13 +1,12 @@
using Microsoft.AspNetCore.Mvc;
using NuGet.Versioning;
using isnd.Entities;
using isn.abst;
namespace isnd.Controllers
{
public partial class PackagesController
{
[HttpGet(_pkgRootPrefix + ApiConfig.GetVersion + "/{id}/{lower}/" + ApiConfig.IndexDotJson)]
[HttpGet("~" + ApiConfig.V2Find)]
public IActionResult GetVersions(
string id,
string lower,

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using isnd.Entities;
using Microsoft.AspNetCore.Http;
using isn.abst;
namespace isnd.Controllers
{
public partial class PackagesController
{
// TODO [Authorize(Policy = IsndConstants.RequireValidApiKey)]
[HttpPut("~" + Constants.ApiVersionPrefix + 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 dbApiKey = dbContext.ApiKeys.SingleOrDefault(k => k.Id == clearKey);
if (dbApiKey == null)
{
logger.LogError("403 : no api-key");
return Unauthorized();
}
foreach (IFormFile file in Request.Form.Files)
{
var version = await packageManager.PutPackageAsync(file.OpenReadStream(), dbApiKey.UserId);
logger.LogInformation($"new package : {version.PackageId} {version.NugetLink}");
}
return Ok();
}
catch (Exception ex)
{
var message = $"PUT exception : {ex.Message} ({ex.GetType().Name})";
logger.LogError(message);
logger.LogError("Stack Trace : " + ex.StackTrace);
return new ObjectResult(new { ViewData, message })
{ StatusCode = 500 };
}
}
}
}

@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Mvc;
using isnd.Entities;
using isn.abst;
using System.Threading.Tasks;
using isnd.Data.Catalog;
namespace isnd.Controllers
{
// TODO /search GET {@id}?q={QUERY}&skip={SKIP}&take={TAKE}&prerelease={PRERELEASE}&semVerLevel={SEMVERLEVEL}&packageType={PACKAGETYPE}
public partial class PackagesController
{
// Web get the paquet
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Search)]
[HttpHead("~" + Constants.ApiVersionPrefix + ApiConfig.Search)]
[HttpHead("~" + ApiConfig.V2Find)]
public async Task<IActionResult> Search(
string q=null,
int skip=0,
int take=25,
bool prerelease=false,
string semVerLevel = "2.0.0",
string packageType = "Dependency")
{
PackageRegistrationQuery query = new PackageRegistrationQuery
{
Prerelease= prerelease,
Query = q,
Skip = skip,
Take = take
};
var result = await packageManager.SearchPackageAsync(query);
return Ok(result);
}
}
}

@ -0,0 +1,106 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using isn.abst;
using isnd.Data;
using isnd.Data.Catalog;
using isnd.Entities;
using isnd.Helpers;
using isnd.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Web.Virtualization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace isnd.Controllers
{
public partial class PackagesController
{
// Web search
public async Task<IActionResult> Index(PackageRegistrationQuery model)
{
var pkgs = await packageManager.SearchPackageAsync(model);
var result = new RegistrationPageIndexQueryAndResult
{
Source = packageManager.CatalogBaseUrl+ApiConfig.Index,
Query = model
};
List<PackageRegistration> registrations = new List<PackageRegistration>();
foreach (var pk in pkgs.data.GroupBy(x => x.PackageId))
{
registrations.Add(new PackageRegistration(apiBase, pk.Key, pkgs.GetResults().Single(p=>p.Id == pk.Key).Versions));
}
return View(new RegistrationPageIndexQueryAndResult
{
Source = packageManager.CatalogBaseUrl+ApiConfig.Index,
Query = model,
Result = registrations.ToArray()
});
}
public async Task<IActionResult> Details(PackageDetailViewModel model)
{
if (model.pkgid == null)
{
return NotFound();
}
var packageVersion = dbContext.PackageVersions
.Include(p=>p.LatestCommit)
.Include(p => p.Package)
.Where(m => m.PackageId == model.pkgid)
.OrderByDescending(p => p)
;
if (packageVersion.Count() == 0)
{
return NotFound();
}
bool results = await packageVersion.AnyAsync();
model.latest = await packageVersion.FirstAsync();
model.totalHits = packageVersion.Count();
model.data = packageVersion.Take(MAX_PKG_VERSION_LIST).ToArray();
return View("Details", model);
}
const int MAX_PKG_VERSION_LIST = 50;
[Authorize, HttpGet]
public async Task<IActionResult> Delete(string pkgid, string version, string pkgtype)
{
if (pkgid == null || version == null)
{
return NotFound();
}
var packageVersion = await dbContext.PackageVersions.Include(p => p.Package)
.FirstOrDefaultAsync(m => m.PackageId == pkgid && m.FullString == version
&& (pkgtype!=null && m.Type == pkgtype || m.Type != "Delete" ));
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]
[ValidateAntiForgeryToken][Authorize]
public async Task<IActionResult> DeleteConfirmed(string pkgid, string version,
string type)
{
var packageVersion = await dbContext.PackageVersions
.Include(pv => pv.Package)
.Where(m => m.PackageId == pkgid
&& m.FullString == version && (type==null || m.Type == type))
.ToArrayAsync();
if (packageVersion.Length==0) return NotFound();
if (!User.IsOwner(packageVersion.First())) return Unauthorized();
await packageManager.DeletePackageAsync(pkgid, version, type);
return RedirectToAction(nameof(Index));
}
}
}

@ -1,21 +1,14 @@
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;
using isn.abst;
namespace isnd.Controllers
{
@ -24,20 +17,18 @@ namespace isnd.Controllers
{
const int maxTake = 100;
private readonly Resource[] resources;
private readonly string apiBase;
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;
const string _pkgRootPrefix = "~/";
public PackagesController(
ILoggerFactory loggerFactory,
IDataProtectionProvider provider,
IOptions<IsndSettings> isndOptions,
IUnleash unleashĈlient,
ApplicationDbContext dbContext,
IPackageManager pm)
{
@ -46,8 +37,10 @@ namespace isnd.Controllers
protector = provider.CreateProtector(isndSettings.ProtectionTitle);
this.dbContext = dbContext;
packageManager = pm;
this.unleashĈlient = unleashĈlient;
resources = packageManager.GetResources(unleashĈlient).ToArray();
resources = packageManager.GetResources().ToArray();
this.apiBase = isndSettings.ExternalUrl + Constants.ApiVersionPrefix;
}
}
}

@ -1,220 +0,0 @@
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;
namespace isnd.Controllers
{
public partial class PackagesController
{
[HttpPut(_pkgRootPrefix + ApiConfig.Publish)]
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.ÛpdateCatalogFor(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 };
}
}
}
}

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

@ -1,90 +0,0 @@
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(PackageRegistrationIndexQuery model)
{
return View(packageManager.GetCatalogIndex());
}
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 == null)
{
return NotFound();
}
bool results = await packageVersion.AnyAsync();
var latest = await packageVersion.FirstAsync();
return View("Details", new PackageDetailViewModel
{
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));
}
}
}

@ -18,7 +18,7 @@ namespace isnd.Data.ApiKeys
public int ValidityPeriodInDays{ get; set; }
public DateTime CreationDate { get; set; }
public DateTimeOffset CreationDate { get; set; }
public bool IsValid => CreationDate.AddDays(ValidityPeriodInDays) > DateTime.Now;
}

@ -9,6 +9,8 @@ namespace isnd.Data.ApiKeys
[Display(Name = "Key Name")]
public string Name { get; set; }
public string UserId { get; set; }
public int ValidityPeriodInDays { get; set; }
}
}

@ -1,23 +1,63 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using isnd.Data;
using isnd.Data.ApiKeys;
using isnd.Data.Packages;
using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages;
using Microsoft.DotNet.Scaffolding.Shared.ProjectModel;
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) { }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
_ = builder.Entity<PackageVersion>()
.HasKey( v => new { v.PackageId, v.FullString } );
_ = builder.Entity<PackageVersion>()
.HasOne(v => v.Package).WithMany(p => p.Versions).HasForeignKey(x => x.PackageId);
_ = builder.Entity<PackageDependencyGroup>().HasOne(g=>g.PackageVersion)
.WithMany(v => v.DependencyGroups).HasForeignKey(x => new { x.PackageId, x.PackageVersionFullString } );
}
/// <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; }
public DbSet<Dependency> Dependencies { get; set; }
public DbSet<PackageDependencyGroup> PackageDependencyGroups { get; set; }
}
}

@ -5,6 +5,8 @@ namespace isnd.Data
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
[PersonalData]
public string FullName { get; set; }
}
}

@ -1,82 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
namespace isnd.Data.Catalog
{
public class CatalogEntry
{
/// <summary>
/// The URL to the document used to produce this object
/// </summary>
/// <value></value>
[Key][Required,JsonRequired]
[StringLength(1024)]
[JsonProperty("@id")]
public string Id { 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; }
/// <summary>
/// The ID of the package
/// </summary>
/// <value></value>
public string idp { 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; }
/// <summary>
/// A string containing a ISO 8601 timestamp of when the package was published
/// </summary>
/// <value></value>
public string published { 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 full version string after normalization
/// </summary>
/// <value></value>
[Required,JsonRequired]
public string version { get; set; } // string yes
/// <summary>
/// The security vulnerabilities of the package
/// </summary>
/// <value></value>
public Vulnerabilitie[] vulnerabilities { 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 : Permalink
{
private readonly string pkgid;
private readonly List<RegistrationLeaf> items;
private readonly string apiBase;
public RegistrationPage (string pkgid, string apiBase) : base(apiBase + $"/registration/{pkgid}/index.json")
{
Parent = apiBase + $"/registration/{pkgid}/index.json";
this.items = new List<RegistrationLeaf>();
this.pkgid = pkgid;
this.apiBase = apiBase;
}
public RegistrationPage(string pkgid, string apiBase, IEnumerable<PackageVersion> versions) : this(pkgid, apiBase)
{
AddVersionRange(versions);
}
public string GetPackageId()
{
return pkgid;
}
/// <summary>
/// The array of registration leaves and their associate metadata
/// </summary>
/// <value></value>
[JsonProperty("items")]
public RegistrationLeaf[] Items { get => items.ToArray(); }
public void AddVersionRange(IEnumerable<PackageVersion> vitems)
{
if (vitems.Count() == 0) return;
NuGetVersion upper = null;
NuGetVersion lower = null;
PackageVersion latest = 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 (p.LatestCommit==null) continue;
var pkg = p.ToPackage(apiBase);
if (items.Contains(pkg)) 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)
{
latest = p;
}
items.Add(pkg);
}
Upper = upper?.ToFullString() ?? lower?.ToFullString();
Lower = lower?.ToFullString() ?? upper?.ToFullString();
}
/// <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; }
}
}

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

@ -0,0 +1,237 @@
using System.ComponentModel;
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;
using NuGet.Protocol.Core.Types;
using NuGet.Protocol;
using NuGet.Packaging;
using NuGet.Packaging.Core;
using System.Threading.Tasks;
using isnd.Entities;
namespace isnd.Data.Catalog
{
public class PackageDetails : Permalink, IObject, IPackageSearchMetadata
{
/// <summary>
/// Creates a catalog entry
/// </summary>
/// <param name="pkg">package id</param>
/// <param name="apiBase">api Base</param>
/// <returns></returns>
public PackageDetails(PackageVersion pkg, string apiBase): base( apiBase + ApiConfig.Registration + "/" + pkg.PackageId + "/" + pkg.FullString + ".json")
{
Title = PackageId = pkg.Package.Id;
Version = pkg.FullString;
Authors = $"{pkg.Package.Owner.FullName} <${pkg.Package.Owner.Email}>";
packageContent = apiBase + pkg.NugetLink;
CommitId = pkg.CommitId;
Published = CommitTimeStamp = pkg.LatestCommit.CommitTimeStamp;
IsListed = !pkg.IsDeleted && pkg.Package.Public;
if (pkg.DependencyGroups!=null)
{
DependencySets = pkg.DependencyGroups.ToDepSetInfo();
}
PackageDetailsUrl = new Uri(this.id);
// TODO Licence Project Urls, Summary, Title, Owners, etc ...
}
[JsonProperty("@type")]
public string[] RefType { get; protected set; } = new string[] { "PackageDetails" };
/// <summary>
///
/// </summary>
/// <param name="apiBase"></param>
/// <param name="pkgId"></param>
/// <param name="pkgVersionString"></param>
/// <param name="commitId"></param>
/// <param name="commitTimeStamp"></param>
/// <param name="authors"></param>
/// <param name="deprecation"></param>
/// <param name="description"></param>
/// <param name="iconUrl"></param>
/// <param name="language"></param>
/// <param name="licenseUrl"></param>
/// <param name="licenseExpression"></param>
/// <param name="minClientVersion"></param>
/// <param name="projectUrl"></param>
/// <param name="requireLicenseAcceptance"></param>
/// <param name="summary"></param>
/// <param name="tags"></param>
/// <param name="title"></param>
/// <param name="packageContent"></param>
/// <param name="version"></param>
/// <param name="identity"></param>
/// <param name="readmeUrl"></param>
/// <param name="reportAbuseUrl"></param>
/// <param name="packageDetailsUrl"></param>
/// <param name="owners"></param>
/// <param name="isListed"></param>
/// <param name="prefixReserved"></param>
/// <param name="licenseMetadata"></param>
public PackageDetails(string apiBase, string pkgId, string pkgVersionString, string commitId, DateTimeOffset commitTimeStamp, string authors, Deprecation deprecation, string description, Uri iconUrl, string language, Uri licenseUrl, string licenseExpression, string minClientVersion, Uri projectUrl, bool requireLicenseAcceptance, string summary, string tags, string title, string packageContent, string version, PackageIdentity identity, Uri readmeUrl, Uri reportAbuseUrl, Uri packageDetailsUrl, string owners, bool isListed, bool prefixReserved, LicenseMetadata licenseMetadata)
: base( apiBase + ApiConfig.Registration + "/" + pkgId + "/" + pkgVersionString + ".json")
{
this.CommitId = commitId;
this.CommitTimeStamp = commitTimeStamp;
this.Authors = authors;
this.deprecation = deprecation;
this.Description = description;
this.IconUrl = iconUrl;
this.language = language;
this.LicenseUrl = licenseUrl;
this.licenseExpression = licenseExpression;
this.minClientVersion = minClientVersion;
this.ProjectUrl = projectUrl;
this.RequireLicenseAcceptance = requireLicenseAcceptance;
this.Summary = summary;
this.Tags = tags;
this.Title = title;
this.packageContent = packageContent;
this.Version = version;
this.Identity = identity;
this.ReadmeUrl = readmeUrl;
this.ReportAbuseUrl = reportAbuseUrl;
this.PackageDetailsUrl = packageDetailsUrl;
this.Owners = owners;
this.IsListed = isListed;
this.PrefixReserved = prefixReserved;
this.LicenseMetadata = licenseMetadata;
}
[JsonProperty("commitId")]
public string CommitId { get; set; }
[JsonProperty("commitTimeStamp")]
public DateTimeOffset CommitTimeStamp { get; set; }
/// <summary>
/// Authors
/// </summary>
/// <value>string or array of strings</value>
[JsonProperty("authors")]
public string Authors { get; set; }
/// <summary>
/// The deprecation associated with the package
/// </summary>
/// <value></value>
public Deprecation deprecation { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("iconUrl")]
public Uri IconUrl { get; set; }
public string language { get; set; }
[JsonProperty("licenseUrl")]
public Uri LicenseUrl { get; set; }
public string licenseExpression { get; set; }
public string minClientVersion { get; set; }
[JsonProperty("projectUrl")]
public Uri ProjectUrl { get; set; }
[JsonProperty("requireLicenseAcceptance")]
public bool RequireLicenseAcceptance { get; set; }
[JsonProperty("summary")]
public string Summary { get; set; }
/// <summary>
/// The tags
/// </summary>
/// <value></value>
[JsonProperty("tags")]
public string Tags { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
/// <summary>
/// The security vulnerabilities of the package
/// </summary>
/// <value></value>
public IEnumerable<PackageVulnerabilityMetadata> Vulnerabilities { get; }
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 DateTimeOffset? Published { get; set; }
/// <summary>
/// The full version string after normalization
/// </summary>
/// <value></value>
[Required,JsonRequired]
[JsonProperty("version")]
public string Version { get; set; }
[Required,JsonRequired]
[JsonProperty("id")]
public string PackageId { get; set; }
public long? DownloadCount { get; set; }
public PackageIdentity Identity{ get; set; }
public Uri ReadmeUrl { get; set; }
public Uri ReportAbuseUrl { get; set; }
public Uri PackageDetailsUrl { get; set; }
public string Owners { get; set; }
[JsonProperty("isListed")]
public bool IsListed { get; set; }
public bool PrefixReserved { get; set; }
public LicenseMetadata LicenseMetadata { get; set; }
public IEnumerable<PackageDependencyGroupInfo> DependencySets {get; set;}
IEnumerable<NuGet.Packaging.PackageDependencyGroup> IPackageSearchMetadata.DependencySets => throw new NotImplementedException();
public Task<PackageDeprecationMetadata> GetDeprecationMetadataAsync()
{
throw new NotImplementedException();
}
public Task<IEnumerable<VersionInfo>> GetVersionsAsync()
{
throw new NotImplementedException();
}
}
public class PackageDependencyGroupInfo
{
private PackageDependencyGroup group;
public PackageDependencyGroupInfo(PackageDependencyGroup group)
{
this.group = group;
}
}
}

@ -0,0 +1,33 @@
using isnd.Data.Packages;
using isnd.Entities;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
namespace isnd.Data.Catalog
{
public class PackageRegistration : Permalink
{
public PackageRegistration(string url) : base(url)
{
Items = new List<RegistrationPage>();
}
public PackageRegistration(string apiBase, string pkgId, IEnumerable<PackageVersion> versions) : base($"{apiBase}{ApiConfig.Registration}/{pkgId}/index.json")
{
Items = new List<RegistrationPage>
{
new RegistrationPage(pkgId, apiBase, versions)
};
}
[JsonProperty("count")]
public int Count { get => Items.Count; }
[JsonProperty("items")]
public List<RegistrationPage> Items { get; set; }
}
}

@ -1,20 +0,0 @@
using Newtonsoft.Json;
namespace isnd.Data.Catalog
{
public class PackageRegistrationIndexQuery : RegistrationPageIndex
{
public PackageRegistrationIndexQuery(string id) : base(id)
{
}
[JsonProperty("prerelease")]
public bool Prerelease { get; set; }
[JsonProperty("query")]
public string Query { get; set; }
[JsonProperty("totalHits")]
public int TotalHits { get; internal set; }
}
}

@ -0,0 +1,25 @@
using System.Collections.Generic;
using isnd.Data.Packages;
using Newtonsoft.Json;
namespace isnd.Data.Catalog
{
public class PackageRegistrationQuery
{
public PackageRegistrationQuery()
{
}
[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;
}
}

@ -1,5 +1,7 @@
using System.ComponentModel.DataAnnotations;
using isnd.Entities;
using Newtonsoft.Json;
using isn.abst;
namespace isnd.Data.Catalog
{
@ -9,18 +11,28 @@ namespace isnd.Data.Catalog
/// </summary>
public class RegistrationLeaf
{
public RegistrationLeaf(string apiBase, string pkgId, string fullVersionString, PackageDetails entry)
{
this.registration = apiBase + ApiConfig.Registration + "/" + pkgId + "/" + fullVersionString + ".json";
Id = registration;
this.PackageContent = apiBase + ApiConfig.Nuget + "/" + pkgId + "/" + fullVersionString
+ "/" + pkgId + "-" + fullVersionString + "." + Constants.PacketFileExtension;
Entry = entry;
}
/*
@id string yes
catalogEntry object yes
packageContent string yes
*/
[JsonProperty("@id")]
[Key][Required]
[StringLength(1024)]
/// <summary>
/// The URL to the registration leaf
/// </summary>
/// <value></value>
[JsonProperty("@id")]
[Key][Required]
[StringLength(1024)]
public string Id { get; set; }
/// <summary>
@ -28,7 +40,7 @@ namespace isnd.Data.Catalog
/// </summary>
/// <value></value>
[JsonProperty("catalogEntry")]
public CatalogEntry Entry { get; set; }
public PackageDetails Entry { get; set; }
/// <summary>
/// The URL to the package content (.nupkg)
@ -36,5 +48,7 @@ namespace isnd.Data.Catalog
/// <value></value>
[JsonProperty("packageContent")]
public string PackageContent { get; set; }
public string registration { get; set; }
}
}

@ -1,49 +0,0 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace isnd.Data.Catalog
{
public class RegistrationPage
{
[JsonProperty("@id")]
[JsonRequired]
public string Id { get; }
public RegistrationPage (string id)
{
Id = id;
}
/// <summary>
/// no The array of registration leaves and their associate metadata
/// </summary>
/// <value></value>
[JsonProperty("items")]
public List<RegistrationLeaf> Items { get; set; }
/// <summary>
/// The highest SemVer 2.0.0 version in the page (inclusive)
/// </summary>
/// <value></value>
[JsonProperty("upper"), JsonRequired]
public Version Upper { get; set; }
/// <summary>
/// The lowest SemVer 2.0.0 version in the page (inclusive)
/// </summary>
/// <value></value>
[JsonProperty("lower"), JsonRequired]
public Version Lower { get; set; }
/// <summary>
/// The URL to the registration index
/// </summary>
/// <value></value>
[JsonProperty("parent")]
public string Parent { get; set; }
[JsonProperty("count")]
public int Count { get; internal set; }
public string CommitId { get; internal set; }
public DateTime CommitTimeStamp { get; internal set; }
}
}

@ -1,47 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace isnd.Data.Catalog
{
public class RegistrationPageIndex
{
/// <summary>
/// Page Url
/// </summary>
/// <value></value>
[JsonProperty("@id")]
public string Id { get; set; }
public RegistrationPageIndex(string id)
{
Id = id;
Items = new List<RegistrationPage>();
}
public RegistrationPageIndex(IEnumerable<RegistrationPage> pages)
{
Items = new List<RegistrationPage>(pages);
}
public RegistrationPageIndex(string id, IEnumerable<RegistrationLeaf> leaves) : this(id)
{
// leaves;
this.Items = new List<RegistrationPage>
(
)
{
};
}
[JsonProperty("count")]
public int Count { get => Items?.Count ?? 0; }
[JsonProperty("items")]
public List<RegistrationPage> Items { get; set; }
public string CommitId { get; set; }
}
}

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using isnd.Interfaces;
using Newtonsoft.Json;
namespace isnd.Data.Packages.Catalog
{
public class CatalogLeaf : IObject
{
[JsonProperty("@type")]
public string[] RefType { get; set; }
[JsonProperty("commitId")]
public string CommitId { get; set; }
[JsonProperty("commitTimeStamp")]
public DateTime CommitTimeStamp { get; set; }
[JsonProperty("published")]
public DateTime Published { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("version")]
public string Version { get; set; }
}
}

@ -4,11 +4,15 @@ 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; }
DateTimeOffset CommitTimeStamp { get; }
}
}

@ -1,7 +0,0 @@
namespace isnd.Data.Packages.Catalog
{
public class PackageDetail : CatalogLeaf
{
}
}

@ -10,10 +10,9 @@ namespace isnd.Data.Packages.Catalog
/// for availability, or deletion,
///
/// </summary>
public class PackageRef : IObject
public class PackageDetails : IObject
{
[JsonProperty("@id")]
public string RefId { get; set; }
@ -47,6 +46,7 @@ namespace isnd.Data.Packages.Catalog
public virtual Commit LastCommit { get; set; }
[JsonProperty("commitTimeStamp")]
public DateTime CommitTimeStamp { get; set; }
public DateTimeOffset CommitTimeStamp { get; set; }
}
}

@ -0,0 +1,12 @@
using System;
using isnd.Interfaces;
namespace isnd.Data.Packages.Catalog
{
public class PackageEntry : IObject
{
public string CommitId => throw new NotImplementedException();
public DateTimeOffset CommitTimeStamp => throw new NotImplementedException();
}
}

@ -1,21 +0,0 @@
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; }
}
}

@ -21,7 +21,7 @@ namespace isnd.Data.Packages
public long Id { get; set; }
[Required][JsonIgnore]
public DateTime TimeStamp{ get; set; }
public DateTimeOffset TimeStamp{ get; set; }
[Required]
public PackageAction Action { get; set; }
@ -30,7 +30,7 @@ namespace isnd.Data.Packages
public string CommitId { get => Id.ToString(); }
[NotMapped]
public DateTime CommitTimeStamp { get => TimeStamp; }
public DateTimeOffset CommitTimeStamp { get => TimeStamp; }
[ForeignKey("CommitNId")]

@ -0,0 +1,39 @@
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System.ComponentModel.DataAnnotations.Schema;
using isnd.Data.Packages;
namespace isnd.Data
{
public class Dependency
{
[JsonIgnore]
[Key][DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get;set;}
/// <summary>
/// Dependency Package Identifier
/// </summary>
/// <value></value>
[JsonProperty("id")]
public string PackageId { get;set;}
/// <summary>
/// Dependency Group Id
/// </summary>
/// <value></value>
[Required]
[ForeignKey("Group")]
[JsonIgnore]
public string DependencyGroupId { set ; get ; }
[JsonIgnore]
public virtual PackageDependencyGroup Group{ get; set; }
// TODO Version Range
[JsonProperty("range")]
public string Version { get; set; }
}
}

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
namespace isnd.Data.Packages
{
public interface IPackage
{
string Id { get; set; }
string OwnerId { get; set; }
string Description { get; set; }
bool Public { get; set; }
ApplicationUser Owner { get; set; }
List<PackageVersion> Versions { get; set; }
long CommitNId { get; set; }
string CommitId { get; }
Commit LatestCommit { get; set; }
DateTimeOffset CommitTimeStamp { get; set; }
}
}

@ -3,15 +3,16 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using isnd.Data.Catalog;
using isnd.Interfaces;
using Newtonsoft.Json;
namespace isnd.Data.Packages
{
public class Package : IObject
public class Package
{
[Key][Required]
[Key]
[Required]
[StringLength(1024)]
public string Id { get; set; }
@ -22,7 +23,7 @@ namespace isnd.Data.Packages
[StringLength(1024)]
public string Description { get; set; }
public bool Public { get ; set;}
public bool Public { get; set; }
[JsonIgnore]
virtual public ApplicationUser Owner { get; set; }
@ -36,38 +37,20 @@ namespace isnd.Data.Packages
/// or even deletion when no more active version.
/// </summary>
/// <value></value>
[Required][JsonIgnore]
public long CommitNId { get; set ; }
[Required]
[JsonIgnore]
[ForeignKey("LatestCommit")]
public long CommitNId { get; set; }
[NotMapped]
public string CommitId { get => CommitNId.ToString(); }
[ForeignKey("CommitNId")]
public virtual Commit LatestCommit { get; set; }
public virtual Commit LatestVersion{ get; set; }
public DateTime CommitTimeStamp { get; set; }
/// <summary>
/// Returns the leaf
/// </summary>
/// <param name="bid">base url tu use for building the id property</param>
/// <returns></returns>
public RegistrationLeaf ToLeave(string bid)
internal string GetLatestVersion()
{
if (Versions.Count == 0) throw new Exception("NO VERSION");
var v = Versions.OrderBy(w => w.SystemVersion).First();
RegistrationLeaf leave = new RegistrationLeaf
{
Id = bid + Id + "/" + v.FullString + ".json",
PackageContent = v.NugetLink,
Entry = new CatalogEntry
{
Id = bid + Id + ".json",
idp = Id,
version = v.FullString,
authors = $"{Owner.FullName} <${Owner.Email}>"
}
};
return leave;
return Versions.Max(v => v.NugetVersion)?.ToFullString();
}
}
}

@ -0,0 +1,51 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using isnd.Data.Catalog;
using Microsoft.DotNet.Scaffolding.Shared.ProjectModel;
using Microsoft.Identity.Client;
using Newtonsoft.Json;
using NuGet.Frameworks;
using NuGet.Packaging;
using NuGet.Packaging.Core;
using NuGet.ProjectModel;
using NuGet.Versioning;
namespace isnd.Data
{
static class Helpers
{
public static PackageDependencyGroupInfo[] ToDepSetInfo(this IEnumerable<PackageDependencyGroup> groups)
{
return groups.Select(group => new PackageDependencyGroupInfo(group)).ToArray();
}
}
public class PackageDependencyGroup
{
[JsonIgnore]
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get ; set;}
[Required]
[JsonProperty("id")]
public string PackageId { get ; set;}
[Required]
[JsonIgnore]
public string PackageVersionFullString { get ; set;}
[JsonProperty("targetFramework")]
[Required]
public string TargetFramework { get; set; }
[JsonIgnore]
[ForeignKey("DependencyGroupId")]
public virtual List<Dependency> Dependencies { get; set; }
[JsonIgnore]
public virtual PackageVersion PackageVersion { get; set; }
}
}

@ -1,13 +1,24 @@
using System;
using System.Security.Principal;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using isn.abst;
using isnd.Data.Catalog;
using isnd.Data.Packages;
using isnd.Data.Packages.Catalog;
using isnd.Entities;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using NuGet.Versioning;
using System;
using NuGet.Packaging;
using System.Collections.Generic;
using Package = isnd.Data.Packages.Package;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
namespace isnd.Data
{
[PrimaryKey("PackageId", "FullString")]
public class PackageVersion
{
[Required]
@ -18,17 +29,22 @@ namespace isnd.Data
[Required]
public int Major { get; set; }
[Required]
public int Minor { get; set; }
[Required]
public int Patch { get; set; }
public int Revision { get; set; }
/// <summary>
/// Full version string
/// </summary>
/// <value></value>
[StringLength(256)]
[Required][Key]
[Required]
public string FullString { get; set; }
public bool IsPrerelease { get; set; }
@ -36,9 +52,10 @@ namespace isnd.Data
public string Type { get; set; }
[JsonIgnore]
public virtual Package Package { get; set; }
public virtual Packages.Package Package { get; set; }
[Required][JsonIgnore]
[Required]
[JsonIgnore]
[ForeignKey("LatestCommit")]
public long CommitNId { get; set; }
@ -46,14 +63,22 @@ namespace isnd.Data
public string CommitId { get => CommitNId.ToString(); }
public virtual Commit LatestCommit {get; set; }
public string NugetLink => $"/{Constants.PaquetFileEstension}/{PackageId}/{FullString}/{PackageId}-{FullString}."
+ Constants.PaquetFileEstension;
public string NuspecLink => $"/{Constants.SpecFileEstension}/{PackageId}/{FullString}/{PackageId}-{FullString}."
+ Constants.SpecFileEstension;
public virtual Commit LatestCommit { get; set; }
public virtual List<PackageDependencyGroup> DependencyGroups { get; set; }
public string NugetLink => $"{ApiConfig.Nuget}/{PackageId}/{FullString}/{PackageId}-{FullString}."
+ Constants.PacketFileExtension;
public string NuspecLink => $"{ApiConfig.Nuspec}/{PackageId}/{FullString}/{PackageId}-{FullString}."
+ Constants.SpecFileExtension;
public string SementicVersionString { get => $"{Major}.{Minor}.{Patch}"; }
public Version SystemVersion { get => new Version(Major, Minor, Patch, Revision); }
public NuGetVersion NugetVersion { get => new NuGetVersion(FullString); }
public Catalog.RegistrationLeaf ToPackage(string apiBase)
{
return new Catalog.RegistrationLeaf(apiBase, this.PackageId , FullString, new Catalog.PackageDetails(this, apiBase));
}
public bool IsDeleted => LatestCommit?.Action == PackageAction.DeletePackage;
}
}

@ -1,8 +0,0 @@
namespace isnd.Entities
{
public class UnleashClientSettings
{
public string ClientApiKey { get; set; }
public string ApiUrl { get; set; }
}
}

@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.Linq;
using isn;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace isnd.Helpers
{
public static class ApiHelpers
{
static public APIKO CreateAPIKO(this Controller controller, string context)
{
Dictionary<string,string[]> errors = new();
foreach (var elt in controller.ModelState)
{
errors[elt.Key] = elt.Value.Errors.Select( e => e.ErrorMessage).ToArray();
}
return new APIKO{ Context = context, Errors = errors };
}
}
}

@ -1,33 +1,17 @@
namespace isnd.Helpers
{
/// <summary>
/// Package Id Helpers
/// </summary>
public static class PackageIdHelpers
{
internal static bool SeparatedByMinusMatch(string id, string q)
{
foreach (var part in id.Split('-'))
{
if (part.StartsWith(q, System.StringComparison.OrdinalIgnoreCase)) return true;
if (part.Equals(q, System.StringComparison.InvariantCultureIgnoreCase)) return true;
}
return false;
}
internal static bool CamelCaseMatch(string id, string query)
{
// Assert.False (q==null);
if (string.IsNullOrEmpty(query)) return true;
while (id.Length > 0)
{
int i = 0;
while (id.Length > i && char.IsLower(id[i])) i++;
if (i == 0) break;
id = id.Substring(i);
if (id.StartsWith(query, System.StringComparison.OrdinalIgnoreCase)) return true;
}
return false;
}
}
}

@ -11,35 +11,10 @@ namespace isnd.Helpers
{
public static class PackageVersionHelpers
{
public static bool IsOwner(this ClaimsPrincipal user, PackageVersion v)
{
var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);
return v.Package.OwnerId == userId;
}
public static RegistrationPageIndex CreateRegistrationPages(this IEnumerable<RegistrationLeaf> leaves,
string bid)
{
List<RegistrationPage> pages = new List<RegistrationPage>();
var ids = leaves.Select(l => l.Entry.Id).Distinct().ToArray();
foreach (var id in ids)
{
var lbi = leaves.Where(l=>l.Entry.Id == id).OrderBy(l=>
new Version(l.Entry.version));
var latest = new Version(lbi.Last().Entry.version);
pages.Add(new RegistrationPage(bid + id + "/" + latest.Major + "."
+ latest.Minor + "."
+ latest.Build)
{
Count = lbi.Count(),
Lower = new Version(lbi.First().Entry.version),
Upper = latest,
Items = lbi.ToList(),
Parent = bid + id + "/" + ApiConfig.IndexDotJson,
});
}
return new RegistrationPageIndex(pages);
}
}
}

@ -1,32 +0,0 @@
using System;
using System.Collections.Generic;
using isnd.Entities;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Unleash;
using Unleash.ClientFactory;
namespace isnd.Helpers
{
public static class UnleashHelpers
{
public static IUnleash CreateUnleahClient(this IHostingEnvironment env,
UnleashClientSettings unleashClientSettings)
{
var unleashSettings = new UnleashSettings
{
UnleashApi = new Uri(unleashClientSettings.ApiUrl),
AppName = "isnd",
Environment = env.EnvironmentName,
CustomHttpHeaders = new Dictionary<string, string>
{
{ "Authorization", unleashClientSettings.ClientApiKey }
}
};
UnleashClientFactory unleashClientFactory = new UnleashClientFactory();
return unleashClientFactory.CreateClient(unleashSettings);
}
}
}

@ -0,0 +1,13 @@
using System.Linq;
using System.Threading.Tasks;
using isnd.Data.ApiKeys;
namespace isnd.Interfaces
{
public interface IApiKeyProvider
{
Task<ApiKey> CreateApiKeyAsync(CreateModel model);
IQueryable<ApiKey> GetUserKeys(string identityName);
}
}

@ -1,34 +1,36 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using isn.Abstract;
using isnd.Controllers;
using isnd.Data;
using isnd.Data.Catalog;
using isnd.Data.Packages;
using isnd.Data.Packages.Catalog;
using isnd.Services;
using isnd.ViewModels;
using NuGet.Versioning;
using Unleash;
namespace isnd.Interfaces
{
public interface IPackageManager
{
string CatalogBaseUrl { get; }
AutoCompleteResult AutoComplete(string pkgid, int skip, int take, bool prerelease = false, string packageType = null);
AutoCompleteResult AutoComplete(string pkgid, int skip=0, int take=25, bool prerelease = false, string packageType = null);
string[] GetVersions(string pkgid, NuGetVersion parsedVersion, bool prerelease = false, string packageType = null, int skip = 0, int take = 25);
RegistrationPageIndex SearchByName(string query, int skip, int take, bool prerelease = false, string packageType = null);
IEnumerable<Resource> GetResources(IUnleash unleashĈlient);
void ÛpdateCatalogFor(Commit commit);
IEnumerable<Resource> GetResources();
Task<PackageRegistration> UpdateCatalogForAsync(Commit commit);
Task<PackageDeletionReport> DeletePackageAsync(string pkgid, string version, string type);
Task<PackageDeletionReport> UserAskForPackageDeletionAsync(string userid, string pkgId, string lower, string type);
Task<PackageVersion> GetPackageAsync(string pkgid, string version, string type);
IEnumerable<PackageVersion> GetCatalogLeaf(string pkgId, string semver, string pkgType);
IEnumerable<RegistrationLeaf> SearchById(string pkgId, string semver, string pkgType);
Task<Data.Catalog.RegistrationLeaf> GetCatalogEntryAsync(string pkgId, string version, string pkgType);
IEnumerable<Data.Catalog.RegistrationLeaf> SearchCatalogEntriesById(string pkgId, string semver, string pkgType, bool preRelease);
RegistrationPageIndex GetCatalogIndex();
Task<PackageRegistration> GetCatalogIndexAsync();
Task<PackageRegistration> GetPackageRegistrationIndexAsync(PackageRegistrationQuery query);
Task<PackageSearchResult> SearchPackageAsync(PackageRegistrationQuery query);
Task<PackageVersion> PutPackageAsync(Stream packageStream, string ownerId);
}
}

@ -1,230 +0,0 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using isnd.Data;
namespace isndhost.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20210424155323_init")]
partial class init
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("ProductVersion", "2.2.6-servicing-10079")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Name")
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasName("RoleNameIndex");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("RoleId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider");
b.Property<string>("ProviderKey");
b.Property<string>("ProviderDisplayName");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("RoleId");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("LoginProvider");
b.Property<string>("Name");
b.Property<string>("Value");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("isn.Data.ApplicationUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<string>("FullName");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("UserName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasName("UserNameIndex");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("isn.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("isn.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("isn.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("isn.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}

@ -1,219 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace isndhost.Migrations
{
public partial class init : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<string>(nullable: false),
Name = table.Column<string>(maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<string>(nullable: false),
UserName = table.Column<string>(maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(maxLength: 256, nullable: true),
Email = table.Column<string>(maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(nullable: false),
PasswordHash = table.Column<string>(nullable: true),
SecurityStamp = table.Column<string>(nullable: true),
ConcurrencyStamp = table.Column<string>(nullable: true),
PhoneNumber = table.Column<string>(nullable: true),
PhoneNumberConfirmed = table.Column<bool>(nullable: false),
TwoFactorEnabled = table.Column<bool>(nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
LockoutEnabled = table.Column<bool>(nullable: false),
AccessFailedCount = table.Column<int>(nullable: false),
FullName = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn),
RoleId = table.Column<string>(nullable: false),
ClaimType = table.Column<string>(nullable: true),
ClaimValue = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn),
UserId = table.Column<string>(nullable: false),
ClaimType = table.Column<string>(nullable: true),
ClaimValue = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(nullable: false),
ProviderKey = table.Column<string>(nullable: false),
ProviderDisplayName = table.Column<string>(nullable: true),
UserId = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<string>(nullable: false),
RoleId = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<string>(nullable: false),
LoginProvider = table.Column<string>(nullable: false),
Name = table.Column<string>(nullable: false),
Value = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetRoleClaims");
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserRoles");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "AspNetRoles");
migrationBuilder.DropTable(
name: "AspNetUsers");
}
}
}

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

Loading…