Przeglądaj źródła

minor: 增加多个应用

tuonian 21 godzin temu
rodzic
commit
d04f780571
63 zmienionych plików z 978 dodań i 83 usunięć
  1. 2 2
      INFO.sh
  2. 8 1
      SynoBuildConf/build
  3. 2 1
      SynoBuildConf/install
  4. 23 0
      app.go
  5. 13 1
      etc/web-config/dsm.nginx-ui.conf
  6. 34 0
      go.mod
  7. 89 0
      go.sum
  8. 0 0
      materials/DSM_Developer_Guide_7_enu.pdf
  9. 2 1
      scripts/start-stop-status
  10. 55 0
      server/cgi.go
  11. 157 0
      server/request/request.go
  12. 54 0
      server/sso/common.go
  13. 196 0
      server/sso/syno.go
  14. 77 0
      server/utils/aes.go
  15. 36 0
      server/utils/cgi.go
  16. 56 0
      server/utils/index.go
  17. 53 0
      server/utils/rand.go
  18. 58 0
      server/utils/zip.go
  19. 7 29
      ui/config
  20. 0 0
      webapps/app/config
  21. 0 0
      webapps/app/helptoc.conf
  22. 0 0
      webapps/app/images/MyIcon_128.png
  23. 0 0
      webapps/app/images/MyIcon_16.png
  24. 0 0
      webapps/app/images/MyIcon_24.png
  25. 0 0
      webapps/app/images/MyIcon_256.png
  26. 0 0
      webapps/app/images/MyIcon_28.png
  27. 0 0
      webapps/app/images/MyIcon_32.png
  28. 0 0
      webapps/app/images/MyIcon_48.png
  29. 0 0
      webapps/app/images/MyIcon_512.png
  30. 0 0
      webapps/app/images/MyIcon_56.png
  31. 0 0
      webapps/app/images/MyIcon_64.png
  32. 0 0
      webapps/app/images/MyIcon_72.png
  33. 0 0
      webapps/app/index.html
  34. 0 11
      webapps/appui2/config
  35. 0 21
      webapps/appui2/helptoc.conf
  36. 0 10
      webapps/appui2/index.html
  37. 0 0
      webapps/link/config
  38. 3 3
      webapps/nginxui/NginxUI.js
  39. 25 0
      webapps/nginxui/config
  40. 0 0
      webapps/nginxui/icons/MyIcon_128.png
  41. 0 0
      webapps/nginxui/icons/MyIcon_16.png
  42. 0 0
      webapps/nginxui/icons/MyIcon_24.png
  43. 0 0
      webapps/nginxui/icons/MyIcon_256.png
  44. 0 0
      webapps/nginxui/icons/MyIcon_28.png
  45. 0 0
      webapps/nginxui/icons/MyIcon_32.png
  46. 0 0
      webapps/nginxui/icons/MyIcon_48.png
  47. 0 0
      webapps/nginxui/icons/MyIcon_512.png
  48. 0 0
      webapps/nginxui/icons/MyIcon_56.png
  49. 0 0
      webapps/nginxui/icons/MyIcon_64.png
  50. 0 0
      webapps/nginxui/icons/MyIcon_72.png
  51. 3 3
      webapps/trilium/Trilium.js
  52. 25 0
      webapps/trilium/config
  53. BIN
      webapps/trilium/icons/MyIcon_128.png
  54. BIN
      webapps/trilium/icons/MyIcon_16.png
  55. BIN
      webapps/trilium/icons/MyIcon_24.png
  56. BIN
      webapps/trilium/icons/MyIcon_256.png
  57. BIN
      webapps/trilium/icons/MyIcon_28.png
  58. BIN
      webapps/trilium/icons/MyIcon_32.png
  59. BIN
      webapps/trilium/icons/MyIcon_48.png
  60. BIN
      webapps/trilium/icons/MyIcon_512.png
  61. BIN
      webapps/trilium/icons/MyIcon_56.png
  62. BIN
      webapps/trilium/icons/MyIcon_64.png
  63. BIN
      webapps/trilium/icons/MyIcon_72.png

+ 2 - 2
INFO.sh

@@ -23,9 +23,9 @@ description="This my sample package"
 description_enu="This my sample package"
 description_cht="這是我的範例套件"
 #只有一个应用
-dsmuidir="ui"
+#dsmuidir="ui"
 #多目录时可配置,需要修改脚本,复制对应的目录
-#dsmuidir="MyApp1:appui1 MyApp2:appui2"
+dsmuidir="NginxUI:nginxui Trilium:trilium"
 
 [ "$(caller)" != "0 NULL" ] && return 0
 

+ 8 - 1
SynoBuildConf/build

@@ -1,4 +1,11 @@
 #!/bin/bash
 
 #make ${MAKE_FLAGS}
-
+cur=$(pwd)
+dir="$cur/../"
+echo "dir:$dir"
+cd $dir
+export GOARCH=amd64
+export GOOS=linux
+export CGO_ENABLED=0
+go build -o ./build/app app.go

+ 2 - 1
SynoBuildConf/install

@@ -18,7 +18,7 @@ create_package_tgz() {
 	### install needed file into PKG_DIR
 	cp -av ui $package_tgz_dir
 	cp -av etc $package_tgz_dir
-	cp -av webapps $package_tgz_dir
+	cp -av webapps/* $package_tgz_dir
 	chown -R http:http $package_tgz_dir/webapps
 
 	### create package.tgz $1: source_dir $2: dest_dir
@@ -27,6 +27,7 @@ create_package_tgz() {
 
 create_spk() {
 	cp -av scripts $PKG_DIR/scripts
+	cp -av build/* $PKG_DIR/scripts/
 	cp -av conf $PKG_DIR
 	cp -av ui $PKG_DIR
 	cp -av LICENSE $PKG_DIR

+ 23 - 0
app.go

@@ -0,0 +1,23 @@
+package main
+
+import (
+	"github.com/gin-gonic/gin"
+	"syno-common/server"
+)
+
+func main() {
+	r := gin.Default()
+	r.POST("/login", func(c *gin.Context) {
+		user, err := server.Auth()
+		if err != nil {
+			c.JSON(500, gin.H{
+				"code": 500,
+				"msg":  err.Error(),
+			})
+			return
+		}
+		c.JSON(200, user)
+	})
+
+	r.Run(":9980")
+}

+ 13 - 1
etc/web-config/dsm.nginx-ui.conf

@@ -10,7 +10,19 @@
         proxy_http_version  1.1;
 }
 
- location ^~ /ng-proxy/ {
+location ^~ /ng-proxy/ {
+        proxy_pass      http://127.0.0.1:38080/;
+        proxy_set_header X-Real-IP $remote_addr;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header Host $host;
+        proxy_set_header Upgrade $http_upgrade;
+        proxy_set_header Connection "upgrade";
+        proxy_connect_timeout  30s;
+        proxy_read_timeout  10m;
+        proxy_http_version  1.1;
+}
+
+location ^~ /auth-proxy/ {
         proxy_pass      http://127.0.0.1:38080/;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

+ 34 - 0
go.mod

@@ -0,0 +1,34 @@
+module syno-common
+
+go 1.23
+
+require github.com/gin-gonic/gin v1.10.1
+
+require (
+	github.com/bytedance/sonic v1.11.6 // indirect
+	github.com/bytedance/sonic/loader v0.1.1 // indirect
+	github.com/cloudwego/base64x v0.1.4 // indirect
+	github.com/cloudwego/iasm v0.2.0 // indirect
+	github.com/gabriel-vasile/mimetype v1.4.3 // indirect
+	github.com/gin-contrib/sse v0.1.0 // indirect
+	github.com/go-playground/locales v0.14.1 // indirect
+	github.com/go-playground/universal-translator v0.18.1 // indirect
+	github.com/go-playground/validator/v10 v10.20.0 // indirect
+	github.com/goccy/go-json v0.10.2 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.7 // indirect
+	github.com/leodido/go-urn v1.4.0 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
+	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
+	github.com/ugorji/go/codec v1.2.12 // indirect
+	golang.org/x/arch v0.8.0 // indirect
+	golang.org/x/crypto v0.23.0 // indirect
+	golang.org/x/net v0.25.0 // indirect
+	golang.org/x/sys v0.20.0 // indirect
+	golang.org/x/text v0.15.0 // indirect
+	google.golang.org/protobuf v1.34.1 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)

+ 89 - 0
go.sum

@@ -0,0 +1,89 @@
+github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
+github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
+github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
+github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
+github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
+github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
+github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
+github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
+github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
+github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
+github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
+github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
+github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
+github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
+github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
+github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
+github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
+github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
+github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
+golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

+ 0 - 0
DSM_Developer_Guide_7_enu.pdf → materials/DSM_Developer_Guide_7_enu.pdf


+ 2 - 1
scripts/start-stop-status

@@ -5,7 +5,8 @@ case $1 in
 	start)
 		### Start this package.
 		# run start command
-		echo "the package has been started" > $SYNOPKG_TEMP_LOGFILE
+		./app
+		echo "the package has been started" > $SYNOPKG_TEMP_LOGFIL
 		exit 0
 	;;
 	stop)

+ 55 - 0
server/cgi.go

@@ -0,0 +1,55 @@
+package server
+
+import (
+	"encoding/json"
+	"fmt"
+	"log"
+	"os"
+	"os/user"
+	"syno-common/server/sso"
+	"syno-common/server/utils"
+)
+
+func Auth() (map[string]interface{}, error) {
+	// Todo:
+	// fix-up error handling with correct http responses (add --debug flag?/Synology's notifications?)
+	// worry about csrf
+	//dev = flag.Bool("dev", false, "Turns Authentication checks off")
+	//flag.Parse()
+
+	var logF *os.File
+	var err error
+
+	curDir := utils.GetCurDir()
+	logF, err = os.OpenFile(fmt.Sprintf("%v/commontools.log", curDir), os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm)
+	if err == nil {
+		defer func() {
+			logF.Close()
+		}()
+		log.SetOutput(logF)
+	}
+	u, _ := user.Current()
+	if u != nil {
+		log.Println("user", u)
+	}
+
+	synoResp := sso.SynoAuth()
+
+	if !synoResp.Ok {
+		synoResp.PrintNoData()
+		os.Exit(0)
+	}
+
+	userData := synoResp.Data
+	resp := sso.LoginByAccount(userData.User)
+	if !resp.Ok {
+		r := sso.UnauthorisedResp()
+		r.PrintNoData()
+		os.Exit(0)
+	}
+	synoResp.PrintNoData()
+	data := resp.Data
+	jsonData, _ := json.Marshal(data)
+	fmt.Print(string(jsonData))
+	return data, nil
+}

+ 157 - 0
server/request/request.go

@@ -0,0 +1,157 @@
+package request
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"log"
+	"net/http"
+	"strings"
+	"syno-common/server/utils"
+	"time"
+)
+
+type Option struct {
+	Url       string
+	Resp      any
+	Accept    string
+	Headers   map[string]string
+	ApiKey    string
+	ApiSecret string
+	Sign      func(option Option) map[string]string
+}
+
+// Request 封装请求库
+type Request struct {
+	BaseURL string
+	Timeout time.Duration
+}
+
+func defaultSign(option Option) map[string]string {
+	if option.Headers == nil {
+		option.Headers = map[string]string{}
+	}
+
+	apiKey := option.ApiKey
+	apiSecret := option.ApiSecret
+	timestamp := time.Now().Unix()
+	nonce := utils.RandString(16)
+
+	fmt.Printf("key: %v, secret: %v,time: %v,nonce: %v\n", apiKey, apiSecret, timestamp, nonce)
+
+	cipherText := fmt.Sprintf("%v%v%v", apiKey, timestamp, nonce)
+
+	sign, err := utils.AesEncrypt(cipherText, apiSecret)
+	if err != nil {
+		log.Printf("sign fail: %v", err)
+	} else {
+		option.Headers["x-api-key"] = apiKey
+		option.Headers["x-api-timestamp"] = fmt.Sprintf("%v", timestamp)
+		option.Headers["x-api-nonce"] = nonce
+		option.Headers["x-api-sign"] = sign
+		log.Printf("sign ok: %v", sign)
+	}
+	//log.Printf("headers: %v", option.Headers)
+	return option.Headers
+}
+
+func NewRequest(baseUrl string, timeout time.Duration) Request {
+	return Request{
+		BaseURL: baseUrl,
+		Timeout: timeout,
+	}
+}
+
+func (r *Request) DoPostJson(requestData any, option Option) (any, error) {
+	data, err := json.Marshal(requestData)
+	if err != nil {
+		return nil, err
+	}
+	url := fmt.Sprintf("%s%s", r.BaseURL, option.Url)
+	if !strings.HasPrefix(option.Url, "/") && !strings.HasSuffix(r.BaseURL, "/") {
+		url = fmt.Sprintf("%s/%s", r.BaseURL, option.Url)
+	}
+
+	req, err := http.NewRequest("POST", url, bytes.NewReader(data))
+	if err != nil {
+		return nil, err
+	}
+
+	userHeaders := option.Headers
+	if option.ApiKey != "" {
+		if option.Sign == nil {
+			userHeaders = defaultSign(option)
+		} else {
+			userHeaders = option.Sign(option)
+		}
+	}
+
+	log.Printf("headers: %v", userHeaders)
+	req.Header.Set("Content-Type", "application/json")
+	if userHeaders == nil {
+		userHeaders = map[string]string{}
+	}
+	for header := range userHeaders {
+		req.Header.Set(header, userHeaders[header])
+	}
+
+	client := &http.Client{
+		Timeout: r.Timeout,
+	}
+	rsp, err := client.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	if rsp.StatusCode < 200 || rsp.StatusCode > 299 {
+		err = errors.New(rsp.Status)
+		log.Printf("status: %v", rsp.StatusCode)
+		return nil, err
+	}
+	body, err := io.ReadAll(rsp.Body)
+	if err != nil {
+		log.Printf("read body fail: %v", err)
+		return nil, errors.New("body parse fail")
+	}
+
+	if option.Resp != nil {
+		err := json.Unmarshal(body, option.Resp)
+		if err != nil {
+			log.Printf("parse body fail: %v", err)
+			return nil, err
+		}
+		return option.Resp, nil
+	}
+	if option.Accept == "" || option.Accept == "application/json" {
+		var respData = map[string]interface{}{}
+		err := json.Unmarshal(body, &respData)
+		//log.Printf("resp data: %v", respData)
+		if err != nil {
+			log.Printf("parse body fail: %v", err)
+			return nil, err
+		}
+		return respData, nil
+	}
+	return body, nil
+}
+
+func Test(apiKey string, secret string) {
+	request := NewRequest("http://10.10.0.1:20003", time.Second*10)
+
+	data := map[string]interface{}{}
+
+	option := Option{
+		Url:       "/client/login",
+		Resp:      nil,
+		Accept:    "",
+		ApiKey:    apiKey,
+		ApiSecret: secret,
+	}
+
+	resp, err := request.DoPostJson(data, option)
+	if err != nil {
+		log.Fatalln(err)
+	}
+	log.Printf("resp: %v", resp)
+}

+ 54 - 0
server/sso/common.go

@@ -0,0 +1,54 @@
+package sso
+
+import (
+	"fmt"
+	"log"
+	"syno-common/server/request"
+	"time"
+)
+
+const apiKey = "XVlBzgbaiCMRAjWw"
+const apiSecret = "hTHctcuAxhxKQFDa"
+
+type BaseResp struct {
+	Code int                    `json:"code"`
+	Msg  string                 `json:"msg"`
+	Ok   bool                   `json:"ok"`
+	Data map[string]interface{} `json:"data"`
+}
+
+func (r *BaseResp) ToString() string {
+	return fmt.Sprintf("{Code: %v,Msg: %v,Ok: %v,Data: %v}", r.Code, r.Msg, r.Ok, r.Data)
+}
+
+// LoginByAccount
+// 直接向授权中心获取token,无赖之举,syno没有能检查token的接口,起码现在不知道
+func LoginByAccount(account string) BaseResp {
+
+	req := request.NewRequest("http://10.10.0.1:20003", time.Second*10)
+
+	data := map[string]interface{}{
+		"user_name": account,
+		"app_id":    "",
+	}
+
+	resp := BaseResp{
+		Ok:  false,
+		Msg: "request fail",
+	}
+
+	option := request.Option{
+		Url:       "/client/login",
+		Resp:      &resp,
+		Accept:    "",
+		ApiKey:    apiKey,
+		ApiSecret: apiSecret,
+	}
+
+	_, err := req.DoPostJson(data, option)
+	if err != nil {
+		log.Fatalln(err)
+	}
+	log.Printf("resp: %v", resp)
+	return resp
+}

+ 196 - 0
server/sso/syno.go

@@ -0,0 +1,196 @@
+// Package sso 群辉登录
+package sso
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"log"
+	"net/url"
+	"os"
+	"os/exec"
+	"regexp"
+	"strings"
+)
+
+// AppPrivilege is part of AuthJSON
+type AppPrivilege struct {
+	IsPermitted bool `json:"SYNO.SDS.DNSCryptProxy.Application"`
+}
+
+// Session is part of AuthJSON
+type Session struct {
+	IsAdmin bool `json:"is_admin"`
+}
+
+// AuthJSON is used to read JSON data from /usr/syno/synoman/webman/initdata.cgi
+type AuthJSON struct {
+	Session      Session `json:"session"`
+	AppPrivilege AppPrivilege
+}
+
+type RespJSON struct {
+	Code int    `json:"code"`
+	Msg  string `json:"msg"`
+	Data any    `json:"data"`
+}
+
+type UserData struct {
+	User      string `json:"user"`
+	SynoToken string `json:"synoToken"`
+	Data      string `json:"data"`
+}
+
+type SynoResp struct {
+	StatusCode int
+	Message    string
+	Data       UserData
+	Ok         bool
+}
+
+func (r *SynoResp) PrintNoData() {
+	fmt.Print(r.Message)
+}
+
+func OkResp() SynoResp {
+	return SynoResp{
+		StatusCode: 200,
+		Message:    "Status: 200 OK\nContent-Type: application/json; charset=utf-8\n\n",
+		Ok:         true,
+	}
+}
+
+func UnauthorisedResp() SynoResp {
+	return SynoResp{
+		StatusCode: 401,
+		Message:    "Status: 401 Unauthorized\nContent-Type: text/html; charset=utf-8\n\n",
+		Ok:         false,
+	}
+}
+
+func ErrorResp() SynoResp {
+	return SynoResp{
+		StatusCode: 500,
+		Message:    "Status: 500 Internal server error\nContent-Type: text/html; charset=utf-8\n\n",
+		Ok:         false,
+	}
+}
+
+// Retrieve login status and try to retrieve a CSRF token.
+// If either fails than we return an error to the user that they need to login.
+// Returns username or error
+// 现在没有权限访问这个,需要客户端进行调用
+func token() (string, error) {
+	cmd := exec.Command("/usr/syno/synoman/webman/login.cgi")
+	cmdOut, err := cmd.Output()
+	if err != nil && err.Error() != "exit status 255" { // in the Synology world, error code 255 apparently means success!
+		return string(cmdOut), err
+	}
+	// cmdOut = bytes.TrimLeftFunc(cmdOut, findJSON)
+
+	// Content-Type: text/html [..] { "SynoToken" : "GqHdJil0ZmlhE", "result" : "success", "success" : true }
+	r, err := regexp.Compile("SynoToken\" *: *\"([^\"]+)\"")
+	if err != nil {
+		return string(cmdOut), err
+	}
+	token := r.FindSubmatch(cmdOut)
+	if len(token) < 1 {
+		return string(cmdOut), errors.New("Sorry, you need to login first!")
+	}
+	return string(token[1]), nil
+}
+
+// Detect if the rune (character) contains '{' and therefore is likely to contain JSON
+// returns bool
+func findJSON(r rune) bool {
+	if r == '{' {
+		return false
+	}
+	return true
+}
+
+// Check if the logged in user is Authorised or Admin.
+// If either fails than we return a HTTP Unauthorized error.
+func SynoAuth() SynoResp {
+
+	//to, err := token()
+	//if err != nil {
+	//	log.Println("getToken fail", err)
+	//	return UnauthorisedResp()
+	//} else {
+	//	log.Println("getToken ok...", to)
+	//}
+
+	// X-SYNO-TOKEN:9WuK4Cf50Vw7Q
+	// http://192.168.1.1:5000/webman/3rdparty/DownloadStation/webUI/downloadman.cgi?SynoToken=9WuK4Cf50Vw7Q
+	tempQueryEnv := os.Getenv("QUERY_STRING")
+	log.Println("tempQueryEnv: ", tempQueryEnv)
+	if tempQueryEnv == "" || !strings.Contains(tempQueryEnv, "SynoToken") {
+		log.Println("query str miss SynoToken")
+		return ErrorResp()
+	}
+
+	u, err := url.Parse(fmt.Sprintf("http://test.example.cn/?%s", tempQueryEnv))
+	if err != nil {
+		log.Println("parse query params fail: ", err)
+		return ErrorResp()
+	}
+	query := u.Query()
+	tokenStr := query.Get("SynoToken")
+
+	//os.Setenv("QUERY_STRING", "SynoToken="+to)
+	cmd := exec.Command("/usr/syno/synoman/webman/modules/authenticate.cgi")
+	user, err := cmd.Output()
+	if err != nil && string(user) == "" {
+		log.Println("authenticate fail", err)
+		return UnauthorisedResp()
+	}
+	log.Println("user: ", string(user))
+	account := strings.NewReplacer("\r", "").Replace(string(user))
+	account = strings.NewReplacer("\n", "").Replace(account)
+	var userData = UserData{
+		User:      account,
+		SynoToken: tokenStr,
+	}
+	// check permissions
+	if checkIfFileExists("/usr/syno/synoman/webman/initdata.cgi") {
+		cmd = exec.Command("/usr/syno/synoman/webman/initdata.cgi") // performance hit
+		cmdOut, err := cmd.Output()
+		if err != nil {
+			log.Println("initdata fail", err)
+			//unauthorised()
+		}
+		cmdOut = bytes.TrimLeftFunc(cmdOut, findJSON)
+
+		var jsonData AuthJSON
+		if err := json.Unmarshal(cmdOut, &jsonData); err != nil { // performance hit
+			log.Println("initdata Unmarshal fail", err)
+			//unauthorised()
+		}
+
+		isAdmin := jsonData.Session.IsAdmin              // Session.IsAdmin:true
+		isPermitted := jsonData.AppPrivilege.IsPermitted // AppPrivilege.SYNO.SDS.DNSCryptProxy.Application:true
+		if !(isAdmin || isPermitted) {
+			log.Println("initdata Unmarshal fail", err)
+			//unauthorised()
+		}
+	}
+
+	//os.Setenv("QUERY_STRING", tempQueryEnv)
+	resp := OkResp()
+	resp.Data = userData
+	return resp
+}
+
+// Return true if the file path exists.
+func checkIfFileExists(file string) bool {
+	_, err := os.Stat(file)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return false
+		}
+		log.Printf("checkIfFileExists error: %v", err)
+	}
+	return true
+}

+ 77 - 0
server/utils/aes.go

@@ -0,0 +1,77 @@
+package utils
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"encoding/base64"
+	"errors"
+)
+
+// pkcs7Padding 填充
+func pkcs7Padding(data []byte, blockSize int) []byte {
+	//判断缺少几位长度。最少1,最多 blockSize
+	padding := blockSize - len(data)%blockSize
+	//补足位数。把切片[]byte{byte(padding)}复制padding个
+	padText := bytes.Repeat([]byte{byte(padding)}, padding)
+	return append(data, padText...)
+}
+
+// pkcs7UnPadding 填充的反向操作
+func pkcs7UnPadding(data []byte) ([]byte, error) {
+	length := len(data)
+	if length == 0 {
+		return nil, errors.New("加密字符串错误!")
+	}
+	//获取填充的个数
+	unPadding := int(data[length-1])
+	return data[:(length - unPadding)], nil
+}
+
+// AesEncrypt 加密
+func AesEncrypt(cipherText string, sKey string) (string, error) {
+
+	data := []byte(cipherText)
+	key := []byte(sKey)
+	//创建加密实例
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return "", err
+	}
+	//判断加密块的大小
+	blockSize := block.BlockSize()
+	//填充
+	encryptBytes := pkcs7Padding(data, blockSize)
+	//初始化加密数据接收切片
+	crypted := make([]byte, len(encryptBytes))
+	//使用cbc加密模式
+	blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
+	//执行加密
+	blockMode.CryptBlocks(crypted, encryptBytes)
+	return base64.StdEncoding.EncodeToString(crypted), nil
+}
+
+// AesDecrypt 解密
+func AesDecrypt(encryptText string, sKey string) (string, error) {
+	key := []byte(sKey)
+	data, _ := base64.StdEncoding.DecodeString(encryptText)
+	//创建实例
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return "", err
+	}
+	//获取块的大小
+	blockSize := block.BlockSize()
+	//使用cbc
+	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
+	//初始化解密数据接收切片
+	crypted := make([]byte, len(data))
+	//执行解密
+	blockMode.CryptBlocks(crypted, data)
+	//去除填充
+	crypted, err = pkcs7UnPadding(crypted)
+	if err != nil {
+		return "", err
+	}
+	return string(crypted), nil
+}

+ 36 - 0
server/utils/cgi.go

@@ -0,0 +1,36 @@
+package utils
+
+import (
+	"encoding/json"
+	"fmt"
+	"os"
+	"strings"
+)
+
+// LogError Exit program with a HTTP Internal Error status code and a message (dump and die)
+func LogError(str ...string) {
+	//fmt.Print("Status: 500 Internal server error\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")
+	fmt.Print("Status: 500 Internal server error\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")
+	fmt.Print(strings.Join(str, ", "))
+	os.Exit(0)
+}
+
+// Unauthorised Exit program with a HTTP Unauthorized status code and a message (dump and die)
+// 重定向到NAS的主页
+func Unauthorised() {
+	fmt.Print("Status: 401 Unauthorized\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")
+	os.Exit(0)
+}
+
+// RespData 响应数据
+func RespData(data any) {
+	fmt.Print("Status: 200 OK\r\nContent-Type: application/json; charset=utf-8\r\n\r\n")
+	r, err := json.Marshal(data)
+	if err == nil {
+		fmt.Print(string(r))
+	} else {
+		fmt.Print("marshal fail")
+		LogError(err.Error())
+	}
+	os.Exit(0)
+}

+ 56 - 0
server/utils/index.go

@@ -0,0 +1,56 @@
+package utils
+
+import (
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+)
+
+func FileIsExist(path string) bool {
+	_, err := os.Stat(path)
+	if err == nil {
+		return true
+	}
+	if os.IsNotExist(err) {
+		return false
+	}
+	return false
+}
+
+// ExecCmd 执行脚本
+func ExecCmd(command string) ([]byte, error) {
+	var cmd *exec.Cmd
+	if runtime.GOOS == "windows" {
+		cmd = exec.Command("powershell", "-command", command)
+	} else {
+		cmd = exec.Command("sh", "-c", command)
+	}
+	result, err := cmd.CombinedOutput()
+	if err != nil {
+		log.Println("install deps fail", err)
+		return nil, err
+	}
+	log.Println("install deps success")
+	return result, nil
+}
+
+func GetCurDir() string {
+	ex, err := os.Executable()
+	if err != nil {
+		panic(err)
+	}
+	// 可执行文件的路径
+	log.Println(ex)
+	//	获取执行文件所在目录
+	exPath := filepath.Dir(ex)
+	log.Println("可执行文件路径 :" + exPath)
+	// 使用EvalSymlinks获取真是路径
+	realPath, err := filepath.EvalSymlinks(exPath)
+	if err != nil {
+		panic(err)
+	}
+	log.Println("符号链接真实路径:" + realPath)
+	return realPath
+}

+ 53 - 0
server/utils/rand.go

@@ -0,0 +1,53 @@
+package utils
+
+import (
+	"math/rand"
+	"strings"
+)
+
+var CHARS = []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
+	"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
+	"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}
+
+/*
+RandAllString  生成随机字符串([a~zA~Z0~9])
+
+	lenNum 长度
+*/
+func RandAllString(lenNum int) string {
+	str := strings.Builder{}
+	length := len(CHARS)
+	for i := 0; i < lenNum; i++ {
+		l := CHARS[rand.Intn(length)]
+		str.WriteString(l)
+	}
+	return str.String()
+}
+
+/*
+RandNumString  生成随机数字字符串([0~9])
+
+	lenNum 长度
+*/
+func RandNumString(lenNum int) string {
+	str := strings.Builder{}
+	length := 10
+	for i := 0; i < lenNum; i++ {
+		str.WriteString(CHARS[52+rand.Intn(length)])
+	}
+	return str.String()
+}
+
+/*
+RandString  生成随机字符串(a~zA~Z])
+
+	lenNum 长度
+*/
+func RandString(lenNum int) string {
+	str := strings.Builder{}
+	length := 52
+	for i := 0; i < lenNum; i++ {
+		str.WriteString(CHARS[rand.Intn(length)])
+	}
+	return str.String()
+}

+ 58 - 0
server/utils/zip.go

@@ -0,0 +1,58 @@
+package utils
+
+import (
+	"archive/zip"
+	"io"
+	"os"
+	"path"
+	"path/filepath"
+)
+
+// Unzip decompresses a zip file to specified directory.
+// Note that the destination directory don't need to specify the trailing path separator.
+func Unzip(zipPath, dstDir string) error {
+	// open zip file
+	reader, err := zip.OpenReader(zipPath)
+	if err != nil {
+		return err
+	}
+	defer reader.Close()
+	for _, file := range reader.File {
+		if err := unzipFile(file, dstDir); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func unzipFile(file *zip.File, dstDir string) error {
+	// create the directory of file
+	filePath := path.Join(dstDir, file.Name)
+	if file.FileInfo().IsDir() {
+		if err := os.MkdirAll(filePath, os.ModePerm); err != nil {
+			return err
+		}
+		return nil
+	}
+	if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
+		return err
+	}
+
+	// open the file
+	rc, err := file.Open()
+	if err != nil {
+		return err
+	}
+	defer rc.Close()
+
+	// create the file
+	w, err := os.Create(filePath)
+	if err != nil {
+		return err
+	}
+	defer w.Close()
+
+	// save the decompressed file content
+	_, err = io.Copy(w, rc)
+	return err
+}

+ 7 - 29
ui/config

@@ -1,42 +1,20 @@
 {
-  "Demo.js": {
-    "com.mycompany.app.Instance": {
+  "main.js": {
+    "cn.tonyandmoney.app.Instance": {
       "type":"app",
       "version": "0.0.1",
-      "desc": "测试App描述",
+      "desc": "NginxUI",
       "icon": "icons/MyIcon_{0}.png",
-      "title": "测试App",
+      "title": "常用工具箱",
       "texts": "texts",
       "allowMultiInstance": false,
       "waterfallLoadTexts": true,
-      "appWindow": "com.mycompany.app.Demo",
+      "appWindow": "cn.tonyandmoney.app.NginxUI",
       "depend": []
     },
-    "com.mycompany.app.Demo": {
+    "cn.tonyandmoney.app.Main": {
       "type": "lib",
-      "title": "Web浏览器",
-      "icon": "icons/MyIcon_{0}.png",
-      "texts": "texts",
-      "depend": [
-      ]
-    }
-  },
-  "Trilium.js": {
-    "com.mycompany.app.Instance.Trilium": {
-      "type":"app",
-      "version": "0.0.1",
-      "desc": "Trilium笔记",
-      "icon": "icons/MyIcon_{0}.png",
-      "title": "Trilium笔记",
-      "texts": "texts",
-      "allowMultiInstance": false,
-      "waterfallLoadTexts": true,
-      "appWindow": "com.mycompany.app.Demo",
-      "depend": []
-    },
-    "com.mycompany.app.Trilium": {
-      "type": "lib",
-      "title": "Trilium笔记",
+      "title": "常用工具箱",
       "icon": "icons/MyIcon_{0}.png",
       "texts": "texts",
       "depend": [

+ 0 - 0
webapps/appui1/config → webapps/app/config


+ 0 - 0
webapps/appui1/helptoc.conf → webapps/app/helptoc.conf


+ 0 - 0
webapps/appui1/images/MyIcon_128.png → webapps/app/images/MyIcon_128.png


+ 0 - 0
webapps/appui1/images/MyIcon_16.png → webapps/app/images/MyIcon_16.png


+ 0 - 0
webapps/appui1/images/MyIcon_24.png → webapps/app/images/MyIcon_24.png


+ 0 - 0
webapps/appui1/images/MyIcon_256.png → webapps/app/images/MyIcon_256.png


+ 0 - 0
webapps/appui1/images/MyIcon_28.png → webapps/app/images/MyIcon_28.png


+ 0 - 0
webapps/appui1/images/MyIcon_32.png → webapps/app/images/MyIcon_32.png


+ 0 - 0
webapps/appui1/images/MyIcon_48.png → webapps/app/images/MyIcon_48.png


+ 0 - 0
webapps/appui1/images/MyIcon_512.png → webapps/app/images/MyIcon_512.png


+ 0 - 0
webapps/appui1/images/MyIcon_56.png → webapps/app/images/MyIcon_56.png


+ 0 - 0
webapps/appui1/images/MyIcon_64.png → webapps/app/images/MyIcon_64.png


+ 0 - 0
webapps/appui1/images/MyIcon_72.png → webapps/app/images/MyIcon_72.png


+ 0 - 0
webapps/appui1/index.html → webapps/app/index.html


+ 0 - 11
webapps/appui2/config

@@ -1,11 +0,0 @@
-{
-  ".url": {
-    "com.mycompany.app": {
-      "type": "legacy",
-      "icon": "images/MyIcon_{0}.png",
-      "title": "Common Tools",
-      "url": "http://192.168.1.95:38080",
-      "allUsers": true
-    }
-  }
-}

+ 0 - 21
webapps/appui2/helptoc.conf

@@ -1,21 +0,0 @@
-{
-  "app": "com.mycompany.app",
-  "title": "com.mycompany.app",
-  "content": "testapp_index.html",
-  "toc": [
-    {
-      "title": "app_tree:node_1",
-      "content": "testapp_node1.html",
-      "nodes": [
-        {
-          "title": "app_tree:node_1_child",
-          "content": "testapp_node1_child.html"
-        }
-      ]
-    },
-    {
-      "title": "app_tree:node_2",
-      "content": "testapp_node2.html"
-    }
-  ]
-}

+ 0 - 10
webapps/appui2/index.html

@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <title>Title</title>
-</head>
-<body>
-不知道是不是这样,还是哪样
-</body>
-</html>

+ 0 - 0
ui/link/config → webapps/link/config


+ 3 - 3
ui/Demo.js → webapps/nginxui/NginxUI.js

@@ -1,12 +1,12 @@
-Ext.define('com.mycompany.app.Instance', {
+Ext.define('cn.tonyandmoney.app.Instance.NginxUI', {
     extend: 'SYNO.SDS.AppInstance',
-    appWindowName: 'com.mycompany.app.Demo',
+    appWindowName: 'cn.tonyandmoney.app.NginxUI',
     constructor: function() {
         this.callParent(arguments);
     }
 });
 
-Ext.define('com.mycompany.app.Demo', {
+Ext.define('cn.tonyandmoney.app.NginxUI', {
     extend: 'SYNO.SDS.AppWindow',
     appInstance: null,
 

+ 25 - 0
webapps/nginxui/config

@@ -0,0 +1,25 @@
+{
+  "NginxUI.js": {
+    "cn.tonyandmoney.app.Instance.NginxUI": {
+      "type":"app",
+      "version": "0.0.1",
+      "desc": "NginxUI",
+      "icon": "icons/MyIcon_{0}.png",
+      "title": "NginxUI",
+      "texts": "texts",
+      "allowMultiInstance": false,
+      "waterfallLoadTexts": true,
+      "appWindow": "cn.tonyandmoney.app.NginxUI",
+      "depend": [],
+      "allUsers": true
+    },
+    "cn.tonyandmoney.app.NginxUI": {
+      "type": "lib",
+      "title": "NginxUI",
+      "icon": "icons/MyIcon_{0}.png",
+      "texts": "texts",
+      "depend": [
+      ]
+    }
+  }
+}

+ 0 - 0
webapps/appui2/images/MyIcon_128.png → webapps/nginxui/icons/MyIcon_128.png


+ 0 - 0
webapps/appui2/images/MyIcon_16.png → webapps/nginxui/icons/MyIcon_16.png


+ 0 - 0
webapps/appui2/images/MyIcon_24.png → webapps/nginxui/icons/MyIcon_24.png


+ 0 - 0
webapps/appui2/images/MyIcon_256.png → webapps/nginxui/icons/MyIcon_256.png


+ 0 - 0
webapps/appui2/images/MyIcon_28.png → webapps/nginxui/icons/MyIcon_28.png


+ 0 - 0
webapps/appui2/images/MyIcon_32.png → webapps/nginxui/icons/MyIcon_32.png


+ 0 - 0
webapps/appui2/images/MyIcon_48.png → webapps/nginxui/icons/MyIcon_48.png


+ 0 - 0
webapps/appui2/images/MyIcon_512.png → webapps/nginxui/icons/MyIcon_512.png


+ 0 - 0
webapps/appui2/images/MyIcon_56.png → webapps/nginxui/icons/MyIcon_56.png


+ 0 - 0
webapps/appui2/images/MyIcon_64.png → webapps/nginxui/icons/MyIcon_64.png


+ 0 - 0
webapps/appui2/images/MyIcon_72.png → webapps/nginxui/icons/MyIcon_72.png


+ 3 - 3
ui/Trilium.js → webapps/trilium/Trilium.js

@@ -1,12 +1,12 @@
-Ext.define('com.mycompany.app.Instance.Trilium', {
+Ext.define('cn.tonyandmoney.app.Instance.Trilium', {
     extend: 'SYNO.SDS.AppInstance',
-    appWindowName: 'com.mycompany.app.Trilium',
+    appWindowName: 'cn.tonyandmoney.app.Trilium',
     constructor: function() {
         this.callParent(arguments);
     }
 });
 
-Ext.define('com.mycompany.app.Trilium', {
+Ext.define('cn.tonyandmoney.app.Trilium', {
     extend: 'SYNO.SDS.AppWindow',
     appInstance: null,
 

+ 25 - 0
webapps/trilium/config

@@ -0,0 +1,25 @@
+{
+  "Trilium.js": {
+    "cn.tonyandmoney.app.Instance.Trilium": {
+      "type":"app",
+      "version": "0.0.1",
+      "desc": "Trilium笔记",
+      "icon": "icons/MyIcon_{0}.png",
+      "title": "Trilium笔记",
+      "texts": "texts",
+      "allowMultiInstance": false,
+      "waterfallLoadTexts": true,
+      "appWindow": "cn.tonyandmoney.app.Trilium",
+      "depend": [],
+      "allUsers": true
+    },
+    "cn.tonyandmoney.app.Trilium": {
+      "type": "lib",
+      "title": "Trilium笔记",
+      "icon": "icons/MyIcon_{0}.png",
+      "texts": "texts",
+      "depend": [
+      ]
+    }
+  }
+}

BIN
webapps/trilium/icons/MyIcon_128.png


BIN
webapps/trilium/icons/MyIcon_16.png


BIN
webapps/trilium/icons/MyIcon_24.png


BIN
webapps/trilium/icons/MyIcon_256.png


BIN
webapps/trilium/icons/MyIcon_28.png


BIN
webapps/trilium/icons/MyIcon_32.png


BIN
webapps/trilium/icons/MyIcon_48.png


BIN
webapps/trilium/icons/MyIcon_512.png


BIN
webapps/trilium/icons/MyIcon_56.png


BIN
webapps/trilium/icons/MyIcon_64.png


BIN
webapps/trilium/icons/MyIcon_72.png