Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package goshs for openSUSE:Factory checked 
in at 2026-03-11 20:57:19
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/goshs (Old)
 and      /work/SRC/openSUSE:Factory/.goshs.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "goshs"

Wed Mar 11 20:57:19 2026 rev:2 rq:1338295 version:1.1.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/goshs/goshs.changes      2025-09-22 
16:42:04.547451699 +0200
+++ /work/SRC/openSUSE:Factory/.goshs.new.8177/goshs.changes    2026-03-11 
20:59:26.996140154 +0100
@@ -1,0 +2,15 @@
+Tue Dec 16 16:13:56 UTC 2025 - Martin Hauke <[email protected]>
+
+- Update to version 1.1.3
+  * New Feature: Invisible mode. Read more on that at
+    
https://goshs.de/en/usage/restrictions/index.html#be-invisible-invisible-mode
+  * made mDNS opt-in instead of opt-out.
+
+-------------------------------------------------------------------
+Wed Nov 12 18:53:33 UTC 2025 - Martin Hauke <[email protected]>
+
+- Update to version 1.1.2
+  * Fix upload behaviour. Details see issue #128
+  * Remove Upload form from WebUI when read-only to address issue.
+
+-------------------------------------------------------------------

Old:
----
  goshs-1.1.1.tar.gz

New:
----
  goshs-1.1.3.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ goshs.spec ++++++
--- /var/tmp/diff_new_pack.CNaNqn/_old  2026-03-11 20:59:27.636166513 +0100
+++ /var/tmp/diff_new_pack.CNaNqn/_new  2026-03-11 20:59:27.640166677 +0100
@@ -16,14 +16,14 @@
 #
 
 Name:           goshs
-Version:        1.1.1
+Version:        1.1.3
 Release:        0
 Summary:        A simple HTTP server
 License:        MIT
 Group:          Productivity/Networking/Web/Servers
 URL:            https://goshs.de/
 #Git-Clone:     https://github.com/patrickhener/goshs.git
-Source:         
https://github.com/patrickhener/goshs/archive/refs/tags/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
+Source:         
https://github.com/patrickhener/goshs/archive/refs/tags/%{version}.tar.gz#/%{name}-%{version}.tar.gz
 Source1:        vendor.tar.gz
 BuildRequires:  go >= 1.24.1
 BuildRequires:  golang-packaging

++++++ goshs-1.1.1.tar.gz -> goshs-1.1.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/README.md new/goshs-1.1.3/README.md
--- old/goshs-1.1.1/README.md   2025-09-22 09:54:08.000000000 +0200
+++ new/goshs-1.1.3/README.md   2025-12-16 10:29:53.000000000 +0100
@@ -1,4 +1,4 @@
-![Version](https://img.shields.io/badge/Version-v1.1.1-green)
+![Version](https://img.shields.io/badge/Version-1.1.3-green)
 
[![GitHub](https://img.shields.io/github/license/patrickhener/goshs)](https://github.com/patrickhener/goshs/blob/master/LICENSE)
 ![GitHub go.mod Go 
version](https://img.shields.io/github/go-mod/go-version/patrickhener/goshs)
 [![GitHub 
issues](https://img.shields.io/github/issues-raw/patrickhener/goshs)](https://github.com/patrickhener/goshs/issues)
@@ -47,6 +47,7 @@
   * Key Auth
   * Password Auth
 * Silent mode (no webserver output)
+* Invisible mode (no output whatsoever)
 * Retrieve json on cli
 * Drop user privileges before execution (Unix only)
   * Example: Run on port 80, but process is "www-data"
@@ -149,6 +150,10 @@
 
 [![Join 
Discord](https://invidget.switchblade.xyz/3ZnskY8HcJ)](https://discord.gg/3ZnskY8HcJ)
 
+# Star History
+
+[![Star History 
Chart](https://api.star-history.com/svg?repos=patrickhener/goshs&type=date&legend=top-left)](https://www.star-history.com/#patrickhener/goshs&type=date&legend=top-left)
+
 # Credits
 
 A special thank you goes to *sc0tfree* for inspiring this project with his 
project [updog](https://github.com/sc0tfree/updog) written in Python.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/config/config.go 
new/goshs-1.1.3/config/config.go
--- old/goshs-1.1.1/config/config.go    2025-09-22 09:54:08.000000000 +0200
+++ new/goshs-1.1.3/config/config.go    2025-12-16 10:29:53.000000000 +0100
@@ -37,6 +37,7 @@
        NoDelete            bool     `json:"no_delete"`
        Verbose             bool     `json:"verbose"`
        Silent              bool     `json:"silent"`
+       Invisible           bool     `json:"invisible"`
        RunningUser         string   `json:"running_user"`
        CLI                 bool     `json:"cli"`
        Embedded            bool     `json:"embedded"`
@@ -96,6 +97,7 @@
                NoDelete:            false,
                Verbose:             false,
                Silent:              false,
+               Invisible:           false,
                RunningUser:         "",
                CLI:                 false,
                Embedded:            false,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/example/goshs.json.example 
new/goshs-1.1.3/example/goshs.json.example
--- old/goshs-1.1.1/example/goshs.json.example  2025-09-22 09:54:08.000000000 
+0200
+++ new/goshs-1.1.3/example/goshs.json.example  2025-12-16 10:29:53.000000000 
+0100
@@ -25,6 +25,7 @@
   "no_delete": false,
   "verbose": false,
   "silent": false,
+  "invisible": false,
   "running_user": "",
   "cli": false,
   "embedded": false,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/go.mod new/goshs-1.1.3/go.mod
--- old/goshs-1.1.1/go.mod      2025-09-22 09:54:08.000000000 +0200
+++ new/goshs-1.1.3/go.mod      2025-12-16 10:29:53.000000000 +0100
@@ -18,8 +18,8 @@
        github.com/stretchr/testify v1.10.0
        github.com/studio-b12/gowebdav v0.10.0
        github.com/testcontainers/testcontainers-go v0.37.0
-       golang.org/x/crypto v0.40.0
-       golang.org/x/net v0.42.0
+       golang.org/x/crypto v0.45.0
+       golang.org/x/net v0.47.0
        software.sslmate.com/src/go-pkcs12 v0.5.0
 )
 
@@ -73,11 +73,11 @@
        go.opentelemetry.io/otel/metric v1.36.0 // indirect
        go.opentelemetry.io/otel/trace v1.36.0 // indirect
        go.opentelemetry.io/proto/otlp v1.6.0 // indirect
-       golang.org/x/mod v0.25.0 // indirect
-       golang.org/x/sync v0.16.0 // indirect
-       golang.org/x/sys v0.34.0 // indirect
-       golang.org/x/term v0.33.0 // indirect
-       golang.org/x/text v0.27.0 // indirect
-       golang.org/x/tools v0.34.0 // indirect
+       golang.org/x/mod v0.29.0 // indirect
+       golang.org/x/sync v0.18.0 // indirect
+       golang.org/x/sys v0.38.0 // indirect
+       golang.org/x/term v0.37.0 // indirect
+       golang.org/x/text v0.31.0 // indirect
+       golang.org/x/tools v0.38.0 // indirect
        gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/go.sum new/goshs-1.1.3/go.sum
--- old/goshs-1.1.1/go.sum      2025-09-22 09:54:08.000000000 +0200
+++ new/goshs-1.1.3/go.sum      2025-12-16 10:29:53.000000000 +0100
@@ -174,8 +174,8 @@
 golang.org/x/crypto v0.19.0/go.mod 
h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
 golang.org/x/crypto v0.23.0/go.mod 
h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
 golang.org/x/crypto v0.31.0/go.mod 
h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
-golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
-golang.org/x/crypto v0.40.0/go.mod 
h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
+golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
+golang.org/x/crypto v0.45.0/go.mod 
h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod 
h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -184,8 +184,8 @@
 golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
-golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
+golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
+golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod 
h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod 
h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod 
h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -199,8 +199,8 @@
 golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
 golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
-golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
-golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
+golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
+golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -210,8 +210,8 @@
 golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sync v0.10.0/go.mod 
h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
-golang.org/x/sync v0.16.0/go.mod 
h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
+golang.org/x/sync v0.18.0/go.mod 
h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -231,8 +231,8 @@
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
-golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
+golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
 golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod 
h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod 
h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod 
h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -242,8 +242,8 @@
 golang.org/x/term v0.17.0/go.mod 
h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
 golang.org/x/term v0.20.0/go.mod 
h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
 golang.org/x/term v0.27.0/go.mod 
h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
-golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
-golang.org/x/term v0.33.0/go.mod 
h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
+golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
+golang.org/x/term v0.37.0/go.mod 
h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@@ -253,8 +253,8 @@
 golang.org/x/text v0.14.0/go.mod 
h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.15.0/go.mod 
h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.21.0/go.mod 
h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
-golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
-golang.org/x/text v0.27.0/go.mod 
h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
+golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
+golang.org/x/text v0.31.0/go.mod 
h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
 golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
 golang.org/x/time v0.12.0/go.mod 
h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -266,8 +266,8 @@
 golang.org/x/tools v0.6.0/go.mod 
h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.13.0/go.mod 
h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod 
h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
-golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
-golang.org/x/tools v0.34.0/go.mod 
h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
+golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
+golang.org/x/tools v0.38.0/go.mod 
h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/goshsversion/version.go 
new/goshs-1.1.3/goshsversion/version.go
--- old/goshs-1.1.1/goshsversion/version.go     2025-09-22 09:54:08.000000000 
+0200
+++ new/goshs-1.1.3/goshsversion/version.go     2025-12-16 10:29:53.000000000 
+0100
@@ -1,3 +1,3 @@
 package goshsversion
 
-var GoshsVersion = "v1.1.1"
+var GoshsVersion = "1.1.3"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/httpserver/error.go 
new/goshs-1.1.3/httpserver/error.go
--- old/goshs-1.1.1/httpserver/error.go 2025-09-22 09:54:08.000000000 +0200
+++ new/goshs-1.1.3/httpserver/error.go 2025-12-16 10:29:53.000000000 +0100
@@ -9,7 +9,25 @@
        "github.com/patrickhener/goshs/utils"
 )
 
+func (fs *FileServer) handleInvisible(w http.ResponseWriter) {
+       hj, ok := w.(http.Hijacker)
+       if !ok {
+               return
+       }
+
+       conn, _, err := hj.Hijack()
+       if err != nil {
+               return
+       }
+
+       conn.Close()
+}
+
 func (fs *FileServer) handleError(w http.ResponseWriter, req *http.Request, 
err error, status int) {
+       if fs.Invisible {
+               fs.handleInvisible(w)
+               return
+       }
        // Set header to status
        w.WriteHeader(status)
 
@@ -22,8 +40,14 @@
        // Construct error for template filling
        e.ErrorCode = status
        e.ErrorMessage = err.Error()
-       e.Directory = &directory{
-               AbsPath: path.Join(fs.Webroot, req.URL.Path),
+       if fs.Silent {
+               e.Directory = &directory{
+                       AbsPath: "silent mode",
+               }
+       } else {
+               e.Directory = &directory{
+                       AbsPath: path.Join(fs.Webroot, req.URL.Path),
+               }
        }
        e.GoshsVersion = fs.Version
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/httpserver/handler.go 
new/goshs-1.1.3/httpserver/handler.go
--- old/goshs-1.1.1/httpserver/handler.go       2025-09-22 09:54:08.000000000 
+0200
+++ new/goshs-1.1.3/httpserver/handler.go       2025-12-16 10:29:53.000000000 
+0100
@@ -106,22 +106,34 @@
                return true
        }
        if _, ok := req.URL.Query()["cbDown"]; ok {
-               if !fs.NoClipboard {
+               if !fs.NoClipboard && !fs.Invisible {
                        fs.cbDown(w, req)
                        return true
                }
        }
        if _, ok := req.URL.Query()["bulk"]; ok {
-               fs.bulkDownload(w, req)
+               if !fs.Invisible {
+                       fs.bulkDownload(w, req)
+               } else {
+                       fs.handleInvisible(w)
+               }
                return true
        }
        if _, ok := req.URL.Query()["static"]; ok {
-               fs.static(w, req)
+               if !fs.Invisible {
+                       fs.static(w, req)
+               } else {
+                       fs.handleInvisible(w)
+               }
                return true
        }
        if _, ok := req.URL.Query()["embedded"]; ok {
                if err := fs.embedded(w, req); err != nil {
-                       logger.LogRequest(req, http.StatusNotFound, fs.Verbose, 
fs.Webhook)
+                       if !fs.Invisible {
+                               logger.LogRequest(req, http.StatusNotFound, 
fs.Verbose, fs.Webhook)
+                       } else {
+                               fs.handleInvisible(w)
+                       }
                        return true
                }
                logger.LogRequest(req, http.StatusOK, fs.Verbose, fs.Webhook)
@@ -137,16 +149,24 @@
                }
        }
        if _, ok := req.URL.Query()["share"]; ok {
-               fs.CreateShareHandler(w, req)
+               if !fs.Invisible {
+                       fs.CreateShareHandler(w, req)
+               } else {
+                       fs.handleInvisible(w)
+               }
                return true
        }
        if _, ok := req.URL.Query()["token"]; ok {
-               switch req.Method {
-               case http.MethodGet:
-                       fs.ShareHandler(w, req)
-               case http.MethodDelete:
-                       fs.DeleteShareHandler(w, req)
-               default:
+               if !fs.Invisible {
+                       switch req.Method {
+                       case http.MethodGet:
+                               fs.ShareHandler(w, req)
+                       case http.MethodDelete:
+                               fs.DeleteShareHandler(w, req)
+                       default:
+                       }
+               } else {
+                       fs.handleInvisible(w)
                }
                return true
        }
@@ -213,14 +233,16 @@
 }
 
 // Applies custom auth for file based acls
-func (fileS *FileServer) applyCustomAuth(w http.ResponseWriter, req 
*http.Request, acl configFile) {
+func (fileS *FileServer) applyCustomAuth(w http.ResponseWriter, req 
*http.Request, acl configFile) bool {
        if acl.Auth != "" {
-               w.Header().Set("WWW-Authenticate", `Basic realm="Filebased 
Restricted"`)
+               if !fileS.Invisible {
+                       w.Header().Set("WWW-Authenticate", `Basic 
realm="Filebased Restricted"`)
+               }
 
                username, password, authOK := req.BasicAuth()
                if !authOK {
                        fileS.handleError(w, req, fmt.Errorf("%s", "not 
authorized"), http.StatusUnauthorized)
-                       return
+                       return false
                }
 
                user := strings.Split(acl.Auth, ":")[0]
@@ -228,9 +250,10 @@
 
                if username != user || !checkPasswordHash(password, 
passwordHash) {
                        fileS.handleError(w, req, fmt.Errorf("%s", "not 
authorized"), http.StatusUnauthorized)
-                       return
+                       return false
                }
        }
+       return true
 }
 
 func (fileS *FileServer) constructEmbedded() []item {
@@ -358,6 +381,7 @@
                NoClipboard:     fileS.NoClipboard,
                NoDelete:        fileS.NoDelete,
                SharedLinks:     fileS.SharedLinks,
+               ReadOnly:        fileS.ReadOnly,
        }
 
        files := []string{"static/templates/index.html", 
"static/templates/header.tmpl", "static/templates/footer.tmpl", 
"static/templates/scripts_index.tmpl"}
@@ -458,6 +482,11 @@
 }
 
 func (fileS *FileServer) processDir(w http.ResponseWriter, req *http.Request, 
file *os.File, relpath string, jsonOutput bool, acl configFile) {
+       // Early break for invisible mode
+       if fileS.Invisible {
+               fileS.handleInvisible(w)
+               return
+       }
        // Read directory FileInfo
        fis, err := file.Readdir(-1)
        if err != nil {
@@ -469,7 +498,10 @@
        relpath = strings.TrimLeft(relpath, "\\")
 
        // Apply Custom Auth if there is any due to file based acl
-       fileS.applyCustomAuth(w, req, acl)
+       if ok := fileS.applyCustomAuth(w, req, acl); !ok {
+               fileS.handleError(w, req, err, http.StatusUnauthorized)
+               return
+       }
 
        // Construct items list
        items := fileS.constructItems(fis, relpath, acl, req)
@@ -479,6 +511,10 @@
 
        // if ?json output json listing
        if jsonOutput {
+               if fileS.Silent {
+                       fileS.handleError(w, req, fmt.Errorf("%s", "json output 
deactivated in silent mode"), http.StatusNotFound)
+                       return
+               }
                returnJsonDirListing(w, items)
                return
        }
@@ -498,7 +534,9 @@
 
        // Apply Custom Auth if there
        if acl.Auth != "" {
-               w.Header().Set("WWW-Authenticate", `Basic realm="Filebased 
Restricted"`)
+               if !fs.Invisible {
+                       w.Header().Set("WWW-Authenticate", `Basic 
realm="Filebased Restricted"`)
+               }
 
                username, password, authOK := req.BasicAuth()
                if !authOK {
@@ -569,7 +607,11 @@
 
 // socket will handle the socket connection
 func (fs *FileServer) socket(w http.ResponseWriter, req *http.Request) {
-       ws.ServeWS(fs.Hub, w, req)
+       ok := ws.ServeWS(fs.Hub, w, req)
+       if !ok {
+               fs.handleError(w, req, fmt.Errorf("failed to serve websocket"), 
http.StatusInternalServerError)
+               return
+       }
 }
 
 // deleteFile will delete a file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/httpserver/log.go 
new/goshs-1.1.3/httpserver/log.go
--- old/goshs-1.1.1/httpserver/log.go   2025-09-22 09:54:08.000000000 +0200
+++ new/goshs-1.1.3/httpserver/log.go   2025-12-16 10:29:53.000000000 +0100
@@ -8,6 +8,11 @@
 
 func (fs *FileServer) logOnly(w http.ResponseWriter, req *http.Request) {
        logger.LogRequest(req, http.StatusOK, fs.Verbose, fs.Webhook)
-       w.WriteHeader(200)
-       w.Write([]byte("ok\n"))
+       if fs.Invisible {
+               // In invisible mode, do not respond
+               fs.handleInvisible(w)
+       } else {
+               w.WriteHeader(200)
+               w.Write([]byte("ok\n"))
+       }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/httpserver/middleware.go 
new/goshs-1.1.3/httpserver/middleware.go
--- old/goshs-1.1.1/httpserver/middleware.go    2025-09-22 09:54:08.000000000 
+0200
+++ new/goshs-1.1.3/httpserver/middleware.go    2025-12-16 10:29:53.000000000 
+0100
@@ -87,9 +87,72 @@
        })
 }
 
+// InvisibleBasicAuthMiddleware is a middleware to handle basic auth in 
invisible mode
+func (fs *FileServer) InvisibleBasicAuthMiddleware(next http.Handler) 
http.Handler {
+       return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               auth := r.Header.Get("Authorization")
+               if !strings.HasPrefix(auth, "Basic ") {
+                       fs.handleInvisible(w)
+                       return
+               }
+
+               authVal := auth[len("Basic "):]
+               // Cache check
+               authCacheMutex.RLock()
+               cachedOK := authCache[authVal]
+               authCacheMutex.RUnlock()
+
+               if cachedOK {
+                       next.ServeHTTP(w, r)
+                       return
+               }
+
+               //Check if provided password is a bcrypt hash
+               if strings.HasPrefix(fs.Pass, "$2a$") {
+                       username, password, authOK := r.BasicAuth()
+                       if !authOK {
+                               fs.handleInvisible(w)
+                               return
+                       }
+
+                       if username != fs.User {
+                               fs.handleInvisible(w)
+                               return
+                       }
+
+                       if err := 
bcrypt.CompareHashAndPassword([]byte(fs.Pass), []byte(password)); err != nil {
+                               fs.handleInvisible(w)
+                               return
+                       }
+               } else {
+                       username, password, authOK := r.BasicAuth()
+                       if !authOK {
+                               fs.handleInvisible(w)
+                               return
+                       }
+
+                       if username != fs.User || password != fs.Pass {
+                               fs.handleInvisible(w)
+                               return
+                       }
+               }
+
+               authCacheMutex.Lock()
+               authCache[authVal] = true
+               authCacheMutex.Unlock()
+
+               next.ServeHTTP(w, r)
+       })
+}
+
 // ServerHeaderMiddleware sets a custom Server header for all responses
 func (fs *FileServer) ServerHeaderMiddleware(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               // Invisible mode
+               if fs.Invisible {
+                       next.ServeHTTP(w, r)
+                       return
+               }
                serverHeader := fmt.Sprintf("goshs/%s (%s; %s)", fs.Version, 
runtime.GOOS, runtime.Version())
                w.Header().Set("Server", serverHeader)
                next.ServeHTTP(w, r)
@@ -104,8 +167,13 @@
 
                if !fs.Whitelist.IsAllowed(clientIP) {
                        logger.Warnf("[WHITELIST] Access denied for IP: %s", 
clientIP)
-                       http.Error(w, "Access Denied", http.StatusForbidden)
-                       return
+                       if !fs.Invisible {
+                               http.Error(w, "Access Denied", 
http.StatusForbidden)
+                               return
+                       } else {
+                               fs.handleInvisible(w)
+                               return
+                       }
                }
 
                // logger.Infof("[WHITELIST] Access granted for IP: %s", 
clientIP)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/httpserver/server.go 
new/goshs-1.1.3/httpserver/server.go
--- old/goshs-1.1.1/httpserver/server.go        2025-09-22 09:54:08.000000000 
+0200
+++ new/goshs-1.1.3/httpserver/server.go        2025-12-16 10:29:53.000000000 
+0100
@@ -30,8 +30,13 @@
                                logger.Warnf("You are using basic auth without 
SSL. Your credentials will be transferred in cleartext. Consider using -s, 
too.")
                        }
                        logger.Infof("Using basic auth with user '%s' and 
password '%s'", fs.User, fs.Pass)
-                       // Use middleware
-                       mux.Use(fs.BasicAuthMiddleware)
+                       if fs.Invisible {
+                               // Use invisible basic auth middleware
+                               mux.Use(fs.InvisibleBasicAuthMiddleware)
+                       } else {
+                               // Use middleware
+                               mux.Use(fs.BasicAuthMiddleware)
+                       }
                }
 
                // IP Whitelist Middleware
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/httpserver/static/templates/index.html 
new/goshs-1.1.3/httpserver/static/templates/index.html
--- old/goshs-1.1.1/httpserver/static/templates/index.html      2025-09-22 
09:54:08.000000000 +0200
+++ new/goshs-1.1.3/httpserver/static/templates/index.html      2025-12-16 
10:29:53.000000000 +0100
@@ -4,6 +4,7 @@
     <div class="row h-100">
         <!-- 6: File Listing -->
         <div class="col-xl-6">
+            {{ if not .ReadOnly}}
             <!-- Heading Row -->
             <div class="row">
                 <div class="col mb-2">
@@ -30,6 +31,7 @@
                         </form>
                 </div>
             </div>
+            {{ end }}
             <!-- Checkbox Control Row -->
             <div class="row">
                 <div class="col mb-2">
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/httpserver/structs.go 
new/goshs-1.1.3/httpserver/structs.go
--- old/goshs-1.1.1/httpserver/structs.go       2025-09-22 09:54:08.000000000 
+0200
+++ new/goshs-1.1.3/httpserver/structs.go       2025-12-16 10:29:53.000000000 
+0100
@@ -20,6 +20,7 @@
        NoClipboard     bool
        NoDelete        bool
        SharedLinks     map[string]SharedLink
+       ReadOnly        bool
 }
 
 type directory struct {
@@ -75,6 +76,7 @@
        NoClipboard    bool
        NoDelete       bool
        Silent         bool
+       Invisible      bool
        Embedded       bool
        Verbose        bool
        Webhook        webhook.Webhook
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/main.go new/goshs-1.1.3/main.go
--- old/goshs-1.1.1/main.go     2025-09-22 09:54:08.000000000 +0200
+++ new/goshs-1.1.3/main.go     2025-12-16 10:29:53.000000000 +0100
@@ -27,7 +27,7 @@
        ip                  = "0.0.0.0"
        cli                 = false
        webroot             = "."
-       uploadFolder        = "."
+       uploadFolder        = ""
        ssl                 = false
        selfsigned          = false
        letsencrypt         = false
@@ -64,7 +64,8 @@
        webhookEventsParsed = []string{}
        whitelist           = ""
        trustedProxies      = ""
-       noMDNS              = false
+       MDNS                = false
+       invisible           = false
 )
 
 // Man page
@@ -86,6 +87,7 @@
   -nc, --no-clipboard   Disable the clipboard sharing           (default: 
false)
   -nd, --no-delete      Disable the delete option               (default: 
false)
   -si, --silent         Running without dir listing             (default: 
false)
+  -I,  --invisible      Invisible mode                          (default: 
false)
   -c,  --cli            Enable cli (only with auth and tls)     (default: 
false)
   -e,  --embedded       Show embedded files in UI               (default: 
false)
   -o,  --output         Write output to logfile                 (default: 
false)
@@ -115,8 +117,8 @@
   -H,  --hash           Hash a password for file based ACLs
 
 Connection restriction:
-  -ipw, --ip-whitelist             Comma seperated list of IPs to whitelist
-  -tpw, --trusted-proxy-whitelist  Comma seperated list of trusted proxies
+  -ipw, --ip-whitelist             Comma separated list of IPs to whitelist
+  -tpw, --trusted-proxy-whitelist  Comma separated list of trusted proxies
 
 Webhook options:
   -W,  --webhook            Enable webhook support                             
          (default: false)
@@ -131,7 +133,7 @@
   -P  --print-config  Print sample config to STDOUT           (default: false)
   -u  --user          Drop privs to user (unix only)          (default: 
current user)
       --update        Update goshs to most recent version
-  -nm --no-mdns       Disable zeroconf mDNS registration      (default: false)
+  -m  --mdns          Disable zeroconf mDNS registration      (default: false)
   -V  --verbose       Activate verbose log output             (default: false)
   -v                  Print the current goshs version
 
@@ -234,8 +236,10 @@
        flag.StringVar(&trustedProxies, "trusted-proxy-whitelist", 
trustedProxies, "")
        flag.StringVar(&uploadFolder, "uf", uploadFolder, "")
        flag.StringVar(&uploadFolder, "upload-folder", uploadFolder, "")
-       flag.BoolVar(&noMDNS, "nm", noMDNS, "Disable zeroconf mDNS 
registration")
-       flag.BoolVar(&noMDNS, "no-mdns", noMDNS, "Disable zeroconf mDNS 
registration")
+       flag.BoolVar(&MDNS, "m", MDNS, "Enable zeroconf mDNS registration")
+       flag.BoolVar(&MDNS, "mdns", MDNS, "Enable zeroconf mDNS registration")
+       flag.BoolVar(&invisible, "I", invisible, "Enable invisible mode")
+       flag.BoolVar(&invisible, "invisible", invisible, "Enable invisible 
mode")
 
        updateGoshs := flag.Bool("update", false, "update")
        hash := flag.Bool("H", false, "hash")
@@ -271,6 +275,17 @@
 }
 
 func sanityChecks() {
+       // Sanity check for invisible mode
+       if invisible {
+               if sftp || webdav {
+                       sftp = false
+                       webdav = false
+                       MDNS = false
+                       silent = false
+                       logger.Warn("Invisible mode activated, disabling SFTP, 
WebDAV, silent mode and mDNS support")
+               }
+       }
+
        // Sanity check for upload only vs read only
        if uploadOnly && readOnly {
                logger.Fatal("You can only select either 'upload only' or 'read 
only', not both.")
@@ -339,6 +354,11 @@
                os.Exit(0)
        }
 
+       // Set uploadFolder to webroot if not set
+       if uploadFolder == "" {
+               uploadFolder = webroot
+       }
+
        if configFile != "" {
                cfg, err := config.Load(configFile)
                if err != nil {
@@ -391,6 +411,7 @@
                sftpHostKeyfile = cfg.SFTPHostKeyFile
                whitelist = cfg.Whitelist
                trustedProxies = cfg.TrustedProxies
+               invisible = cfg.Invisible
 
                // Abspath for webroot
                // Trim trailing / for linux/mac and \ for windows
@@ -539,6 +560,7 @@
                NoClipboard:  noClipboard,
                NoDelete:     noDelete,
                Silent:       silent,
+               Invisible:    invisible,
                Embedded:     embedded,
                Webhook:      *webhook,
                Verbose:      verbose,
@@ -547,7 +569,7 @@
        }
 
        // Zeroconf mDNS
-       if !noMDNS {
+       if MDNS {
                err = utils.RegisterZeroconfMDNS(ssl, port, webdav, webdavPort, 
sftp, sftpPort)
                if err != nil {
                        logger.Warnf("error registering zeroconf mDNS: %+v", 
err)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/goshs-1.1.1/ws/client.go new/goshs-1.1.3/ws/client.go
--- old/goshs-1.1.1/ws/client.go        2025-09-22 09:54:08.000000000 +0200
+++ new/goshs-1.1.3/ws/client.go        2025-12-16 10:29:53.000000000 +0100
@@ -150,11 +150,11 @@
 }
 
 // ServeWS will handle the socket connections
-func ServeWS(hub *Hub, w http.ResponseWriter, r *http.Request) {
+func ServeWS(hub *Hub, w http.ResponseWriter, r *http.Request) bool {
        conn, err := websocket.Accept(w, r, nil)
        if err != nil {
                logger.Errorf("Failed to upgrade ws: %+v", err)
-               return
+               return false
        }
 
        client := &Client{hub: hub, conn: conn, send: make(chan []byte, 1024)}
@@ -162,6 +162,8 @@
 
        go client.writePump()
        go client.readPump()
+
+       return true
 }
 
 func (c *Client) refreshClipboard() {

++++++ vendor.tar.gz ++++++
++++ 12147 lines of diff (skipped)

Reply via email to