184 Commits
main ... 1.0.0

Author SHA1 Message Date
97eba2390e https redirection 2022-06-19 14:17:49 +01:00
6c9f29bc56 MEF 2022-06-19 14:17:36 +01:00
2d5438c943 presentation 2022-06-18 15:44:06 +01:00
519a4fbd46 Okey 2022-06-16 17:03:38 +01:00
a11bab759e retour sur la MEF du footer 2022-05-25 19:17:31 +01:00
d7f0a5db36 Footer layout 2022-05-25 09:07:36 +01:00
5d59760a77 version bump 2022-04-24 15:13:12 +01:00
3e09afcbfe Errors to Error std output 2022-04-18 20:59:36 +01:00
8fa4c04367 naming 2022-04-18 20:58:14 +01:00
60e4ca8c54 ex to output 2022-04-17 23:30:48 +01:00
da92b9dbec er 2022-04-17 22:33:06 +01:00
6194e185b9 gitversion tool 2022-04-17 22:30:33 +01:00
5c1a49811a Versioning 2022-04-17 20:36:28 +01:00
328f6f166a deploy 2022-04-17 17:59:15 +01:00
4191513eef Compilation warns 2022-04-17 16:22:40 +01:00
217cc49019 Versionning 2022-04-17 14:48:18 +01:00
a4a1c6e271 WIP NuGet API 3.5.0 2022-04-17 14:10:20 +01:00
c06f518836 fixing url's 2022-04-16 03:55:37 +01:00
edc9628b67 testing config 2022-04-16 03:10:12 +01:00
4bb43877c7 Build test host using given app config file 2022-04-16 02:35:20 +01:00
ce8b7bcdb3 Fixes the 500 2022-04-16 01:30:33 +01:00
67ec19184b reposted a pkg 2022-04-15 23:56:15 +01:00
57609e6ed3 Response status code does not indicate success: 500 (Internal Server Error). 2022-04-15 22:54:05 +01:00
b46e786ace warn-- 2022-04-11 20:36:45 +01:00
423f9c15b3 not working by me. 2022-04-11 20:05:35 +01:00
6d21d7370c test 2022-04-11 19:57:30 +01:00
ee07affbbd ... 2022-04-11 01:48:43 +01:00
cba0720150 sources set-default 2022-04-10 18:07:14 +01:00
a2d91e072f ... 2022-04-09 19:53:41 +01:00
1befc2e053 ... 2022-04-09 19:53:26 +01:00
df55836c58 fixes the isn client update 2021-09-13 23:50:20 +01:00
cd3629a5a0 dark theme, logo, tests 2021-09-13 23:28:56 +01:00
51a08dec9a icon 2021-09-12 22:51:28 +01:00
386eec262d dark theme 2021-09-12 20:45:43 +01:00
45d6c22d1e bad config file path 2021-09-12 17:17:36 +01:00
225c8ef588 bad config file name 2021-09-12 17:14:51 +01:00
290a3047b5 echo settings file path 2021-09-12 17:08:14 +01:00
ec70927830 env is Dev 2021-09-12 17:02:21 +01:00
9f338ca09f testing app settings for ci 2021-09-12 17:00:30 +01:00
cfd63fe68d default source apikey 2021-09-12 16:47:26 +01:00
f33ca22255 uhnit testing from vscode 2021-09-08 01:55:00 +01:00
e6f4349621 reorg 2021-09-05 19:33:39 +01:00
903f5157d2 unleash migrates 2021-09-05 19:24:21 +01:00
066c038e4d web ui 2021-09-05 18:55:38 +01:00
95aae91156 Refactorisation of deletion 2021-09-05 17:10:50 +01:00
6dd76ac1a5 REORG+histo 2021-09-05 15:44:47 +01:00
459f8ea422 nodejs ... 2021-09-04 13:55:06 +01:00
5607c53329 Fixes the base resource 2021-09-04 13:41:00 +01:00
71de903f13 bodies 2021-09-03 03:07:58 +01:00
a92bee32e1 CQ 2021-09-02 23:37:28 +01:00
7a835c5c95 Fixes the versionCommit migration 2021-08-29 22:27:12 +01:00
f918d26273 catalog updated at push 2021-08-29 00:51:43 +01:00
25d545e327 isn as net472 assembly 2021-08-29 00:31:19 +01:00
57feb53e82 Fixe l'Url du paquet dans le catalogue 2021-08-29 00:18:16 +01:00
b7dae240cd Catalog packages 2021-08-29 00:08:34 +01:00
d8bfdc293d catalog index 2021-08-28 21:26:39 +01:00
f6fa7a0ec9 unit tests and pkg version commits 2021-08-28 18:41:47 +01:00
55e407d951 commit version 2021-08-27 21:25:33 +01:00
cdb9a26d2c Catalog 2021-08-23 03:21:08 +01:00
504f431937 refact 2021-08-15 19:09:01 +01:00
7da74b0dfb dep & tags 2021-08-15 16:21:34 +01:00
6520d8e4cc dotnet 2021-08-15 14:09:11 +01:00
55b74a584a msbuild 2021-08-15 14:03:53 +01:00
0ec9889e96 msbuild ci tag 2021-08-15 14:02:29 +01:00
b17ee8be75 Settings 2021-08-15 12:59:31 +01:00
f6f3473346 protect 2021-08-15 05:32:08 +01:00
ae114c68db refacts 2021-08-15 01:50:07 +01:00
5f0dfee768 bug on config 2021-08-13 18:55:25 +01:00
9ee058e1c8 bootstrap upgrade 2021-08-12 01:32:20 +01:00
30d81c06df update git ignore list 2021-08-12 01:06:21 +01:00
3845e2c9c4 serve 2021-08-12 01:04:39 +01:00
74427cc15e better Display 2021-08-12 00:38:16 +01:00
5c188b57fc cleaning 2021-08-12 00:02:40 +01:00
74ffc8e83e Prre release buton 2021-08-12 00:01:11 +01:00
7f0518ec82 Put it better 2021-08-11 23:59:08 +01:00
58750587d0 pkg upd by no db 2021-08-11 23:25:15 +01:00
bd1c47e7c6 throw 2021-08-11 20:57:46 +01:00
f7b375ad50 isnapikey 2021-08-11 20:52:50 +01:00
558d5fc8ae . 2021-08-11 20:45:40 +01:00
fff4599ff4 fixes the put 2021-08-10 00:10:26 +01:00
e356636539 Client installation notes 2021-07-12 03:35:03 +01:00
1aef7ce614 upgrade notes 2021-07-12 03:23:11 +01:00
82cec8eece Api Key view 2021-07-12 02:17:26 +01:00
cd7c0be03d Unleash client instance as singleton 2021-07-11 22:13:48 +01:00
a345992351 isn brand fix 2021-07-11 20:15:50 +01:00
5e74b24439 refact & client install notes 2021-07-11 20:04:12 +01:00
451d810ade using async methods 2021-07-11 19:20:56 +01:00
6f82a0a00f Activer le serveur 2021-07-11 19:14:55 +01:00
48ca2df19e async calls 2021-07-11 18:09:02 +01:00
355b2d4c7c Unleash client init 2021-07-11 18:08:49 +01:00
d33a19d35f installation instructions 2021-07-11 18:07:45 +01:00
5a783edac2 Pipline status 2021-07-05 21:46:18 +01:00
32d25733af ci fix due to refact 2021-07-05 21:30:49 +01:00
709e1433bb isntallation steps 2021-07-05 21:24:37 +01:00
476d35ae8a refact 2021-07-05 12:55:52 +01:00
5de53a3cba rebrand 2021-06-27 01:53:00 +01:00
ae6abc104a resources 2021-06-22 23:03:38 +01:00
eba75d0db4 getversions 2021-06-22 01:25:28 +01:00
aaa49788dc autocomplete 2021-06-22 00:10:01 +01:00
b8809deaa1 search 2021-06-21 23:38:05 +01:00
6fcad7c252 MAJ de la description À l'incrément de version 2021-06-21 01:51:57 +01:00
2c31ffb7c4 ignorer une version existante en base mais pas sur le disque 2021-06-21 01:49:19 +01:00
58501329ac removes auto devops 2021-06-21 00:58:44 +01:00
8c25889e88 not only main 2021-06-20 07:07:54 +01:00
90b8913e98 master => main 2021-06-20 07:01:37 +01:00
c88dccd950 reference some env 2021-06-20 06:41:26 +01:00
963ce8579c Update .gitlab-ci.yml 2021-06-20 05:28:47 +00:00
1c1964eb2c renames the 'deploy' job 2021-06-20 05:19:13 +01:00
a5d6e08945 Merge branch 'set-sast-config-1' into 'master'
Set .gitlab-ci.yml to enable or configure SAST

See merge request Paul/nuget-host!1
2021-06-20 04:09:43 +00:00
21b51d4cbd Set .gitlab-ci.yml to enable or configure SAST 2021-06-20 04:07:59 +00:00
27634c3159 api key settings 2021-06-19 00:41:05 +01:00
a11c30e782 re-ignore already present 2021-06-19 00:31:29 +01:00
5cb35f54d5 ci & admin & auth & cli 2021-06-18 23:57:02 +01:00
981f3209e0 ignore code 1 2021-06-18 21:16:38 +01:00
3fa1241ea2 cleaning 2021-06-18 20:44:20 +01:00
c14adcdd80 try++ 2021-06-16 20:19:08 +01:00
25069e5aa2 try++ 2021-06-16 20:14:53 +01:00
b341fdfa4d trying and fix 401 2021-06-16 20:10:33 +01:00
e88763df09 simplified 2021-06-16 19:39:58 +01:00
c456a28282 re push 2021-06-14 19:59:16 +01:00
f7cfeeba8d add source or true 2021-06-14 00:57:06 +01:00
7752620bef deploy src/**/*.nupkg 2021-06-14 00:53:59 +01:00
4fa03c5a1d link warn & deploy to gitlab 2021-06-14 00:46:09 +01:00
61ba3b2bf8 a valid nuget local repo 2021-05-23 20:21:46 +01:00
1266dd54db nugetd 2021-05-23 01:00:57 +01:00
be30ef3c25 gestion des versions :
* dossier des versions = FullString
* Suppressioni de versions
2021-05-22 22:49:57 +01:00
41fbe54638 minor change 2021-05-20 20:35:11 +01:00
d80271dcbf permissions sur le paquet 2021-05-20 20:24:03 +01:00
3a59b8304a [{"PkgName":"nuget-cli.1.0.0.nupkg","Executed":true,"OK":true,"AlreadyPresent":false,"Message":"{\"versionId\":\"nuget-host, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\",\"files\":[\"nuget-cli-1.0.0.nupkg\"]}","StatusCode":"OK","StackTrace":null}] 2021-05-18 23:17:48 +01:00
f6a27fa919 don't use redirection 2021-05-18 02:58:52 +01:00
e51da7f359 TODO policy on existing zip from fs 2021-05-18 00:39:03 +01:00
e4511a8aaa owner id 2021-05-16 14:07:14 +01:00
9575dd2754 report.OK 2021-05-16 05:33:05 +01:00
54a900c361 Merge branch 'master' of gitlab.pschneider.fr:Paul/nuget-host 2021-05-16 02:51:20 +01:00
efb004ee08 Fixe l'envoi du fichier 2021-05-16 02:41:36 +01:00
e0a3ec0bd5 Ok 2021-05-16 02:13:58 +01:00
d7cabaad8b using web request 2021-05-16 01:31:12 +01:00
9adad9a327 refact 2021-05-15 18:38:11 +01:00
3d3a6cf017 refact 2021-05-15 18:36:42 +01:00
2f4ff1e774 return to canonical usage 2021-05-15 04:45:54 +01:00
9289b3af91 no more nuget 2021-05-14 21:48:01 +01:00
90cfc29492 cli to msbuild 2021-05-14 03:15:34 +01:00
c83ff84370 Don't merge. 2021-05-14 01:41:52 +01:00
d117f26c77 seeing some PUT 2021-05-14 01:41:16 +01:00
c2f38800aa ... 2021-05-13 23:05:19 +01:00
a8c9b7619f TODO cli output 2021-05-11 23:44:43 +01:00
97dec15153 push 2021-05-11 23:01:11 +01:00
512495d10b ci test 2021-05-11 20:52:39 +01:00
5bbcf9cb29 cli helped 2021-05-11 02:38:52 +01:00
b6098c28a6 refact 2021-05-10 23:03:59 +01:00
36e1137e50 sln 2021-05-10 21:36:08 +01:00
3086cc65c4 clean 2021-05-10 21:32:29 +01:00
4cec5d0229 launch 2021-05-09 18:07:48 +01:00
61dc82df5b artifacts 2021-05-09 16:28:20 +01:00
db6f514fb5 .... 2021-05-09 15:49:52 +01:00
cc675844b6 ... 2021-05-09 15:41:05 +01:00
f95765f541 not user-secret 2021-05-09 15:35:05 +01:00
e5d3ba36cc testing? 2021-05-09 15:33:14 +01:00
ffb7cad00a Réussi! - échec : 0, réussite : 2, ignorée(s) : 0, total : 2, durée : 444 ms 2021-05-09 14:56:32 +01:00
6a59f776d5 refact 2021-05-09 13:45:55 +01:00
93394b3e82 api key unprotected 2021-05-09 03:06:23 +01:00
d063f10da5 c'est pas ici! 2021-05-09 02:02:50 +01:00
bb02706773 apikey.creationdate 2021-05-09 01:52:55 +01:00
915736c4e2 migrate database 2021-05-08 23:51:40 +01:00
b550f05c4f typo 2021-05-08 22:01:37 +01:00
dd4dd9321b ci++ 2021-05-08 21:50:59 +01:00
a238bd8cbf arts2 2021-05-08 21:47:24 +01:00
fb822b6aaf yml 2021-05-08 21:43:28 +01:00
ffd1dca16e artfcts 2021-05-08 21:40:03 +01:00
198189ab09 fixes build 2021-05-08 21:27:22 +01:00
ccbdd155f3 ci 2021-05-08 21:18:43 +01:00
445ea24dd2 ngh 2021-05-08 20:44:40 +01:00
48df937b7f Add .gitlab-ci.yml 2021-05-08 15:02:19 +00:00
10b1fd0748 Add LICENSE 2021-05-08 14:59:27 +00:00
15fa91138d version 2021-05-08 15:36:56 +01:00
dd6d83cf06 ApiKey 2021-05-08 15:27:46 +01:00
749eb645d5 refactorisation de la configuration 2021-05-02 15:22:46 +01:00
838de379fd Removes IdentityServer4 usage 2021-05-01 16:43:57 +01:00
dc37c9a9f0 adds aspnet.identity 2021-04-25 12:12:50 +01:00
a2f26f1e8e base namespace to nuget_host 2021-04-17 14:19:00 +01:00
1b2d850522 refact 2021-04-11 22:39:26 +01:00
ec5bd7ca1f builds 2021-04-11 22:22:37 +01:00
cede04a33e more references. 2021-04-10 14:11:09 +01:00
5b6d74d8ee protecting api 2021-04-08 03:08:20 +01:00
356 changed files with 67544 additions and 20472 deletions

24
.build Normal file
View File

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

20
.gitignore vendored
View File

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

66
.gitlab-ci.yml Normal file
View File

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

38
.vs/isn/xs/UserPrefs.xml Normal file
View File

@ -0,0 +1,38 @@
<Properties StartupConfiguration="{9D758F00-17FF-433D-B088-F9C2D97C9BD1}|Default">
<MonoDevelop.Ide.Workbench ActiveDocument="src/isn/Program.cs">
<Files>
<File FileName="src/isn/Program.cs" Line="66" Column="10" />
</Files>
<Pads>
<Pad Id="ProjectPad">
<State name="__root__">
<Node name="isn" expanded="True">
<Node name="src" expanded="True">
<Node name="isn" expanded="True" selected="True" />
<Node name="isn.abst" expanded="True" />
</Node>
<Node name="test" expanded="True">
<Node name="isnd.tests" expanded="True" />
</Node>
</Node>
</State>
</Pad>
<Pad Id="MonoDevelop.UnitTesting.TestPad">
<State name="__root__">
<Node name="isn" expanded="True">
<Node name="test" expanded="True">
<Node name="isn.tests" selected="True" />
</Node>
</Node>
</State>
</Pad>
</Pads>
</MonoDevelop.Ide.Workbench>
<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 />
</Properties>

57
.vscode/launch.json vendored
View File

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

50
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,50 @@
{
"omnisharp.msbuild": false,
"dotnet-test-explorer.testProjectPath": "**/*.sln",
"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"
}
]
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,46 @@
{
"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"
}
]
}

View File

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

58
.vscode/tasks.json vendored
View File

@ -1,15 +1,41 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "restore",
"command": "dotnet",
"type": "process",
"args": [
"restore",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"--ignore-failed-sources"
],
"problemMatcher": "$msCompile"
},
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/nuget-host.csproj",
"/p:Configuration=Debug",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
"/consoleloggerparameters:NoSummary",
"--ignore-failed-sources"
],
"problemMatcher": "$msCompile"
},
{
"label": "buildcli",
"command": "msbuild",
"type": "process",
"args": [
"src/isn",
"/p:Configuration=Debug",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"/restore"
],
"problemMatcher": "$msCompile"
},
@ -19,32 +45,46 @@
"type": "process",
"args": [
"publish",
"${workspaceFolder}/nuget-host.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "launch-dotnet",
"label": "copyTestConfig",
"command": "dotnet",
"type": "process",
"args": [ "build", "/t:CopyTestConfig" ]
},
{
"label": "test",
"command": "dotnet",
"type": "process",
"options": {
"env": {
"ASPNETCORE_ENVIRONMENT": "Testing"
}
},
"args": [
"${workspaceFolder}/bin/Debug/netcoreapp2.0/nuget-host.dll"
"test",
"/property:GenerateFullPaths=true",
"--logger:xunit"
],
"problemMatcher": "$msCompile"
"problemMatcher": "$msCompile",
"dependsOn": [ "build", "copyTestConfig"]
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"bin/Debug/netcoreapp2.0/nuget-host.dll",
"/property:GenerateFullPaths=true"
"bin/Debug/netcoreapp2.1/isnd.dll",
"/property:GenerateFullPaths=true",
"/restore"
],
"options": {
"env": {
"ASPNETCORE_ENV": "Development"
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"problemMatcher": "$msCompile"

View File

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

View File

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

5
GitVersion.yml Normal file
View File

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

14
LICENSE Normal file
View File

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

View File

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

View File

@ -1,9 +1,78 @@
# Usage
# ISN
[![pipeline status](http://gitlab.pschneider.fr/Paul/nuget-host/badges/main/pipeline.svg)](http://gitlab.pschneider.fr/Paul/nuget-host/-/commits/main)
## Usage
````sh
nuget sources remove -Name dev
nuget sources add -Name dev -Source Http://localhost:5000/packages
nuget push your-versionned.nupkg -ApiKey 15d0dda1-4028-4896-9f1a-188817da23f4 -Source http://localhost:5000/packages
dotnet user-secrets set ConnectionStrings:DefaultConnection "Server=<lame-pgserver>;Port=<lame-pgport>;Database=<lame-dbname>;Username=<lame-dbusername>;Password=<lame-dbpass>;"
isnd&
# get an api-key from <http://localhost:5000/ApkKeys>
isn push -k <lame-api-key> -s http://localhost:5000/index.json your-lame-versionned.nupkg
wget http://localhost:5000/package/index.json?q=your&prerelease=true&semVerLevel=2.0.0
````
## Installation
Depuis le dossier de la solution, compiler la solution :
````bash
dotnet build /restore -c Release
dotnet publish -c Release
````
### Déployer le serveur
````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 systemctl daemon-reload
````
* Créer une base de donées Postgresql,
* ajuster un fichier de configuration `/srv/www/isnd/appsettings.Production.json`
* Démarrer le serveur :
````bash
sudo systemctl start isnd
````
* Activer le serveur :
````bash
sudo systemctl enable isnd
````
### Installer le client
````bash
sudo mkdir /usr/local/lib/isn
sudo cp -a src/isn/bin/Release/netcoreapp2.1/* /usr/local/lib/isn
sudo chown -R root.root /usr/local/lib/isn
sudo ln -s /usr/local/lib/isn/isn /usr/local/bin/isn
````
### Mises à jour
````bash
# compiler tout
dotnet build -c Release
dotnet publish -c Release -f 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
````
## TODO

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

3
contrib/isn Executable file
View File

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

110
contrib/isnd Normal file
View File

@ -0,0 +1,110 @@
#!/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

11
contrib/upgrade-isn-isnd.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash
set -e
# compiler tout
dotnet publish -c Release
# 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/net472/* /usr/local/lib/isn
sudo chmod +x /usr/local/lib/isn/isn.exe

30
dotnet-tools.json Normal file
View File

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

101
isn.sln Normal file
View File

@ -0,0 +1,101 @@

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

View File

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

View File

@ -0,0 +1,13 @@
using Newtonsoft.Json;
namespace isn.Abstract
{
public class ApiIndexViewModel
{
[JsonProperty("version")]
public string Version { get; set; }
[JsonProperty("resources")]
public Resource[] Resources { get; set; }
}
}

17
src/isn.abst/Resource.cs Normal file
View File

@ -0,0 +1,17 @@
using Newtonsoft.Json;
namespace isn.Abstract
{
public class Resource
{
[JsonProperty("@id")]
public string Id {get; set; }
[JsonProperty("@type")]
public string Type {get; set; }
[JsonProperty("comment")]
public string Comment {get; set; }
}
}

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageVersion>1.0.1</PackageVersion>
<Version>0.1.175</Version>
<TargetFramework>netcoreapp2.1</TargetFramework>
<NoWarn>NETSDK1138</NoWarn>
<AssemblyVersion>0.1.175.0</AssemblyVersion>
<FileVersion>0.1.175.0</FileVersion>
<InformationalVersion>0.1.175+Branch.main.Sha.3e09afcbfe0eff74c0b3aa0fb974e0801f4708b6</InformationalVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
</ItemGroup>
</Project>

7
src/isn/Constants.cs Normal file
View File

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

46
src/isn/IDataProtector.cs Normal file
View File

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

View File

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

View File

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

210
src/isn/Program.cs Normal file
View File

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

19
src/isn/Settings.cs Normal file
View File

@ -0,0 +1,19 @@
using System.Collections.Generic;
namespace isn
{
public class SourceSettings
{
public string ApiKey { get; set; }
public string Alias { get; set; }
}
public class Settings
{
public string DataProtectionTitle {get; set; }
public Dictionary<string, SourceSettings> Sources { get; set; }
public bool AutoUpdateApiKey { get; set; } = false;
public string DefaultSource { get; set; }
}
}

59
src/isn/SourceHelpers.cs Normal file
View File

@ -0,0 +1,59 @@
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using isn.Abstract;
namespace isn
{
public static class SourceHelpers
{
public static ApiIndexViewModel GetServerResources(string url)
{
HttpClient client = new HttpClient();
ApiIndexViewModel result = null;
// var json = await client.GetStringAsync(new System.Uri(url));
Task.Run(async ()=> {
var response = await client.GetStringAsync(url);
result = JsonConvert.DeserializeObject<ApiIndexViewModel>(response);
}).Wait();
return result;
}
public static async Task<ApiIndexViewModel> GetServerResourcesUsingWebRequestAsync(string url)
{
ApiIndexViewModel viewModel=null;
var uri = new Uri(url);
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.Method = "GET";
httpWebRequest.AllowAutoRedirect = false;
try{
using (var resp = await httpWebRequest.GetResponseAsync())
{
using (var stream = resp.GetResponseStream())
{
using (var reader = new StreamReader(stream))
{
var json = await reader.ReadToEndAsync();
Console.Write("got json : "+json);
viewModel = JsonConvert.DeserializeObject<ApiIndexViewModel>(json);
}
}
}
}
catch(Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
return viewModel;
}
}
}

View File

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

View File

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

View File

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

35
src/isn/commands/push.cs Normal file
View File

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

View File

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
namespace isn
{
partial class Program
{
private static void StoreApiKey(IEnumerable<string> storeArgs)
{
var args = storeoptions.Parse(storeArgs);
if (shouldShowPushHelp)
{
// output the options
Console.Error.WriteLine("Push Options:");
storeoptions.WriteOptionDescriptions(Console.Out);
}
else
{
apiKey = args[0];
EnsureKeyStored();
}
}
public static void EnsureKeyStored()
{
if (currentSource == null)
{
if (Settings.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
));
}
}
}

View File

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

View File

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

View File

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

View File

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

27
src/isn/isn.csproj Normal file
View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.1</TargetFrameworks>
<RootNamespace>nuget_cli</RootNamespace>
<UserSecretsId>45b74c62-05bc-4603-95b4-3e80ae2fdf50</UserSecretsId>
<Version>0.1.175</Version>
<PackageVersion>1.0.1</PackageVersion>
<IsPackable>true</IsPackable>
<PackageLicenseExpression>WTFPL</PackageLicenseExpression>
<IsTool>true</IsTool>
<NoWarn>NETSDK1138</NoWarn>
<AssemblyVersion>0.1.175.0</AssemblyVersion>
<FileVersion>0.1.175.0</FileVersion>
<InformationalVersion>0.1.175+Branch.main.Sha.3e09afcbfe0eff74c0b3aa0fb974e0801f4708b6</InformationalVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mono.Options" Version="5.3.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="unleash.client" Version="1.6.1" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<Reference Include="System.Net.Http" Version="4.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../isn.abst/isn.abst.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,15 @@
using System.Net;
namespace isn
{
public class PushReport
{
public string PkgName { get; set; }
public bool Executed { get; internal set; }
public bool OK { get; internal set; }
public bool AlreadyPresent { get; internal set; }
public string Message { get; internal set; }
public string StatusCode { get; internal set; }
public string StackTrace { get; internal set; }
}
}

View File

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

View File

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

View File

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

9
src/isnd/Constants.cs Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,106 @@
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using isnd.Data;
using isnd.ViewModels;
using isnd.Helpers;
using isnd.Interfaces;
namespace isnd
{
[AllowAnonymous]
public class PackageVersionController : Controller
{
private readonly ApplicationDbContext _context;
private readonly IPackageManager _pm;
public PackageVersionController(ApplicationDbContext context,
IPackageManager pm)
{
_context = context;
_pm = pm;
}
// GET: PackageVersion
public async Task<IActionResult> Index(PackageVersionIndexViewModel model)
{
var applicationDbContext = _context.PackageVersions.Include(p => p.Package).Where(
p => (model.Prerelease || !p.IsPrerelease)
&& ((model.PackageId == null) || p.PackageId.StartsWith(model.PackageId)));
model.Versions = await applicationDbContext.ToArrayAsync();
return View(model);
}
[Authorize]
public async Task<IActionResult> Mines(PackageVersionIndexViewModel model)
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var applicationDbContext = _context.PackageVersions
.Include(p => p.Package).Where(
p => (string.IsNullOrEmpty(model.PackageId) || p.PackageId.StartsWith(model.PackageId))
&& p.Package.OwnerId == userId);
model.Versions = await applicationDbContext.ToArrayAsync();
return View("Index", model);
}
// GET: PackageVersion/Details/5
public async Task<IActionResult> Details(string pkgid, string version)
{
if (pkgid == null || version == null)
{
return NotFound();
}
var packageVersion = await _context.PackageVersions
.Include(p => p.Package)
.FirstOrDefaultAsync(m => m.PackageId == pkgid && m.FullString == version);
if (packageVersion == null)
{
return NotFound();
}
return View(packageVersion);
}
[Authorize]
public async Task<IActionResult> Delete(string pkgid, string version, string pkgtype)
{
if (pkgid == null || version == null)
{
return NotFound();
}
var packageVersion = await _context.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 _pm.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 _context.PackageVersions
.FirstOrDefaultAsync(m => m.PackageId == PackageId
&& m.FullString == FullString && m.Type == Type);
if (packageVersion == null) return NotFound();
if (!User.IsOwner(packageVersion)) return Unauthorized();
await _pm.DeletePackageAsync(PackageId, FullString, Type);
return RedirectToAction(nameof(Index));
}
}
}

View File

@ -0,0 +1,31 @@
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NuGet.Versioning;
using isnd.Data;
using isnd.Entities;
using Unleash;
using isnd.Services;
using isnd.ViewModels;
using System.Threading.Tasks;
using isnd.Interfaces;
using isn.Abstract;
namespace isnd.Controllers
{
public partial class PackagesController : Controller
{
[HttpGet(_pkgRootPrefix + ApiConfig.Base)]
public IActionResult ApiIndex()
{
return Ok(new ApiIndexViewModel{ Version = PackageManager.BASE_API_LEVEL, Resources = resources });
}
}
}

View File

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

View File

@ -0,0 +1,61 @@
using System.Linq;
using System.Threading.Tasks;
using isnd.Data.Catalog;
using isnd.Helpers;
using isnd.Services;
using isnd.Entities;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
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 + ApiConfig.CatalogLeaf + "/{id}/{*lower}")]
public async Task<IActionResult> CatalogLeafAsync(string id, string lower)
{
string pkgType = ParamHelpers.Optional(ref lower);
var pkgVersion = await dbContext.PackageVersions
.Include(v => v.LatestCommit)
.SingleOrDefaultAsync(
v => v.PackageId == id &&
v.FullString == lower &&
v.Type == pkgType
);
if (pkgVersion == null) return NotFound();
var pub = await dbContext.Commits
.Include(c => c.Versions)
.OrderBy(c => c.CommitTimeStamp)
.SingleOrDefaultAsync
(
c => c.Action == PackageAction.PublishPackage
&& c.Versions.Contains(pkgVersion)
);
return Ok(new CatalogLeaf
{
CommitId = id,
Id = pkgVersion.PackageId,
CommitTimeStamp = pkgVersion.LatestCommit.CommitTimeStamp
});
}
}
}

View File

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

View File

@ -0,0 +1,21 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using isnd.Helpers;
using isnd.Entities;
using System.ComponentModel.DataAnnotations;
using isnd.Attributes;
namespace isnd.Controllers
{
public partial class PackagesController
{
[HttpDelete(_pkgRootPrefix + ApiConfig.Delete + "/{id}/{*lower}")]
public async Task<IActionResult> Delete(
[FromRoute][SafeName][Required] string id,
[FromRoute][SafeName][Required] string lower)
{
string pkgtype = ParamHelpers.Optional(ref lower);
var report = await packageManager.DeletePackageAsync(id, lower, pkgtype);
return Ok(report);
}
}
}

View File

@ -0,0 +1,51 @@
using System.ComponentModel.DataAnnotations;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using isnd.Attributes;
using isnd.Entities;
namespace isnd.Controllers
{
public partial class PackagesController
{
// Web get nupkg
[HttpGet(_pkgRootPrefix + ApiConfig.Get + "/{id}/{lower}/{idf}-{lowerf}.nupkg")]
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}.nupkg"
);
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 + ApiConfig.Get + "/{id}/{lower}/{idf}-{lowerf}.nuspec")]
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}.nuspec");
FileInfo pkgfi = new FileInfo(pkgpath);
if (!pkgfi.Exists)
{
return BadRequest("!pkgfi.Exists");
}
return File(pkgfi.OpenRead(), "text/xml; charset=utf-8");
}
}
}

View File

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

View File

@ -0,0 +1,217 @@
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 isnd.Data.Catalog;
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()}.nupkg");
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 nuspec = archive.Entries.FirstOrDefault(e => e.FullName.EndsWith(".nuspec"));
if (nuspec == null) return BadRequest(new { error = "no nuspec from archive" });
string pkgpath;
NuGetVersion version;
string pkgid;
string fullpath;
using (var specstr = nuspec.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}.nupkg";
fullpath = Path.Combine(pkgpath, name);
var destpkgiddir = new DirectoryInfo(pkgidpath);
Package package = dbContext.Packages.SingleOrDefault(p => p.Id == pkgid);
if (package != null)
{
if (package.OwnerId != apikey.UserId)
{
return new ForbidResult();
}
package.Description = pkgdesc;
}
else
{
package = new Package
{
Id = pkgid,
Description = pkgdesc,
OwnerId = apikey.UserId,
LatestVersion = commit
};
dbContext.Packages.Add(package);
}
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 == package.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 == package.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 = package,
Major = version.Major,
Minor = version.Minor,
Patch = version.Patch,
IsPrerelease = version.IsPrerelease,
FullString = version.ToFullString(),
Type = null,
LatestCommit = commit
});
else
foreach (var type in types)
{
var pkgver = new PackageVersion
{
Package = package,
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 package : {nuspec.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 + ".nuspec");
FileInfo nfpi = new FileInfo(nuspecfullpath);
if (nfpi.Exists)
nfpi.Delete();
nuspec.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 };
}
}
}
}

View File

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

View File

@ -0,0 +1,55 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using isnd.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace isnd.Controllers
{
public partial class PackagesController
{
// Web search
public async Task<IActionResult> Index(PackageIndexViewModel model)
{
var applicationDbContext = dbContext.Packages.Include(p => p.Versions).Where(
p => ( model.Prerelease || p.Versions.Any(v => !v.IsPrerelease))
&& ((model.Query == null) || p.Id.StartsWith(model.Query)));
model.Data = await applicationDbContext.ToArrayAsync();
return View(model);
}
public async Task<IActionResult> Details(string pkgid)
{
if (pkgid == null)
{
return NotFound();
}
var packageVersion = dbContext.PackageVersions
.Include(p => p.Package)
.Where(m => m.PackageId == pkgid)
.OrderByDescending(p => p)
;
if (packageVersion == 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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using isnd.Data;
using isnd.Data.ApiKeys;
using isnd.Data.Catalog;
using isnd.Data.Historic;
namespace isnd.Data
{
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options) { }
public DbSet<ApiKey> ApiKeys { get; set; }
public DbSet<Package> Packages { get; set; }
public DbSet<PackageVersion> PackageVersions { get; set; }
public DbSet<Commit> Commits { get; set; }
}
}

View File

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

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace isnd.Data.Catalog
{
public class CatalogIndex : IObject
{
[JsonProperty("@id")]
public string Id { get; set ; }
[JsonProperty("items")]
public List<PageRef> Items { get; set; }
[JsonProperty("count")]
public int Count { get => Items?.Count ?? 0; }
public string CommitId { get; set; }
public DateTime CommitTimeStamp { get; set; }
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace isnd.Data.Catalog
{
public class CatalogLeaf : IObject
{
[JsonProperty("@type")]
public List<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; }
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json;
namespace isnd.Data.Catalog
{
public enum PackageAction
{
DeletePackage,
PublishPackage
}
public class Commit : IObject
{
[Key,
DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[JsonIgnore]
public long Id { get; set; }
[Required][JsonIgnore]
public DateTime TimeStamp{ get; set; }
[Required]
public PackageAction Action { get; set; }
[NotMapped]
public string CommitId { get => Id.ToString(); }
[NotMapped]
public DateTime CommitTimeStamp { get => TimeStamp; }
[ForeignKey("CommitNId")]
public virtual List<PackageVersion> Versions { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
using Newtonsoft.Json;
namespace isnd.Data.Catalog
{
public interface IObject
{
[JsonProperty("commitId")]
string CommitId { get; }
[JsonProperty("commitTimeStamp")]
DateTime CommitTimeStamp { get; }
}
}

View File

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

View File

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

View File

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

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