diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bf9f5b9..4eb8511 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,12 +10,12 @@ jobs: strategy: matrix: - go: [ '1.19', '1.20', '1.21' ] + go: [ '1.21' ] steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} @@ -36,7 +36,7 @@ jobs: strategy: matrix: - go: [ '1.19', '1.20', '1.21' ] + go: [ '1.21' ] goos: [ 'freebsd', 'linux', 'openbsd' ] env: @@ -45,7 +45,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 4112d8f..9aba386 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ Types of changes: - Add goshy as bash script and NixOS program, [@riotbib](https://github.com/riotbib) in [#27](https://github.com/oxzi/gosh/pull/27). - Created Store RPC working on Unix domain sockets to allow a `fork`+`exec`ed daemon. - Configuration through YAML configuration file. +- Configurable index template and static files, partially by [@riotbib](https://github.com/riotbib) in [#45](https://github.com/oxzi/gosh/pull/45). +- ID of new items is now configurable both in length as well as in source (random, wordlist). ### Changed - Dependency version bumps. @@ -30,7 +32,8 @@ Types of changes: - `goshd` became `gosh`. - Made `gosh` a `chroot`ed, privilege dropped, `fork`+`exec`ed daemon. - OpenBSD installation changed due to structural program changes. -- Extract web template into a more editable file, [@riotbib](https://github.com/riotbib) in [#45](https://github.com/oxzi/gosh/pull/45). +- Bumped required Go version from 1.19 to 1.21. +- Replaced logrus logging with Go's new `log/slog` and do wrapping for child processes. ### Deprecated ### Removed diff --git a/README.md b/README.md index 5c329e9..8488e2f 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ All files have a maximum lifetime and are then purged. - One short YAML file for everything - Custom maximum file size and lifetime - MIME type filter and rewriting + - Templating the index page, also with additional static files - __Uploading__ - Configure a shorter file lifetime for each upload - Mark files as burn-after-reading to be deleted after first retrieval diff --git a/go.mod b/go.mod index 1bfc50c..518a6fe 100644 --- a/go.mod +++ b/go.mod @@ -1,20 +1,17 @@ module github.com/oxzi/gosh -go 1.19 +go 1.21 require ( github.com/akamensky/base58 v0.0.0-20210829145138-ce8bf8802e8f github.com/oxzi/syscallset-go v0.1.5 - github.com/sirupsen/logrus v1.9.3 github.com/timshannon/badgerhold/v4 v4.0.3 - golang.org/x/sys v0.14.0 + golang.org/x/sys v0.16.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/dgraph-io/badger/v3 v3.2103.5 // indirect github.com/dgraph-io/badger/v4 v4.1.0 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect diff --git a/go.sum b/go.sum index a2b6954..e68954a 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,9 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/akamensky/base58 v0.0.0-20210829145138-ce8bf8802e8f h1:z8MkSJCUyTmW5YQlxsMLBlwA7GmjxC7L4ooicxqnhz8= github.com/akamensky/base58 v0.0.0-20210829145138-ce8bf8802e8f/go.mod h1:UdUwYgAXBiL+kLfcqxoQJYkHA/vl937/PbFhZM34aZs= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= @@ -21,12 +17,8 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc 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/dgraph-io/badger/v3 v3.2103.1/go.mod h1:dULbq6ehJ5K0cGW/1TQ9iSfUk0gbSiToDWmWmTsJ53E= -github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg= -github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw= github.com/dgraph-io/badger/v4 v4.1.0 h1:E38jc0f+RATYrycSUf9LMv/t47XAy+3CApyYSq4APOQ= github.com/dgraph-io/badger/v4 v4.1.0/go.mod h1:P50u28d39ibBRmIJuQC/NSdBOg46HnHw7al2SW5QRHg= -github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= @@ -44,7 +36,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= @@ -64,15 +55,12 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/flatbuffers v1.12.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v23.5.9+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg= github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= @@ -91,7 +79,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.17.1 h1:NE3C767s2ak2bweCZo3+rdP4U/HoyVXLv/X9f2gPS5g= github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= @@ -112,11 +99,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= @@ -128,16 +110,10 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -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 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/timshannon/badgerhold/v3 v3.0.0-20210909134927-2b6764d68c1e h1:zWSVsQaifg0cVH9VvR+cMguV7exK6U+SoW8YD1cZpR4= -github.com/timshannon/badgerhold/v3 v3.0.0-20210909134927-2b6764d68c1e/go.mod h1:/Seq5xGNo8jLhSbDX3jdbeZrp4yFIpQ6/7n4TjziEWs= -github.com/timshannon/badgerhold/v4 v4.0.2 h1:83OLY/NFnEaMnHEPd84bYtkLipVkjTsMbzQRYbk47g4= -github.com/timshannon/badgerhold/v4 v4.0.2/go.mod h1:rh6RyXLQFsvrvcKondPQQFZnNovpRzu+gS0FlLxYuHY= github.com/timshannon/badgerhold/v4 v4.0.3 h1:W6pd2qckoXw2cl8eH0ZCV/9CXNaXvaM26tzFi5Tj+v8= github.com/timshannon/badgerhold/v4 v4.0.3/go.mod h1:IkZIr0kcZLMdD7YJfW/G6epb6ZXHD/h0XR2BTk/VZg8= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -146,7 +122,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -172,7 +147,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -195,27 +169,24 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= 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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= @@ -257,7 +228,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= diff --git a/gosh.go b/gosh.go index 68a5934..6a97c37 100644 --- a/gosh.go +++ b/gosh.go @@ -2,16 +2,23 @@ package main import ( "flag" + "log/slog" "os" "os/signal" "time" "golang.org/x/sys/unix" "gopkg.in/yaml.v3" - - log "github.com/sirupsen/logrus" ) +// StaticFileConfig describes a static_files from the YAML and holds its data. +type StaticFileConfig struct { + Path string `yaml:"path"` + Mime string `yaml:"mime"` + + data []byte +} + // Config is the struct representation of gosh's YAML configuration file. // // For each field's meaning, please consider the gosh.yml file in this @@ -23,6 +30,12 @@ type Config struct { Store struct { Path string + + IdGenerator struct { + Type string `yaml:"type"` + Length int `yaml:"length"` + File string `yaml:"file"` + } `yaml:"id_generator"` } Webserver struct { @@ -41,6 +54,10 @@ type Config struct { UrlPrefix string `yaml:"url_prefix"` + CustomIndex string `yaml:"custom_index"` + + StaticFiles map[string]StaticFileConfig `yaml:"static_files"` + ItemConfig struct { MaxSize string `yaml:"max_size"` MaxLifetime time.Duration `yaml:"max_lifetime"` @@ -71,30 +88,36 @@ func loadConfig(path string) (Config, error) { func mainMonitor(conf Config) { storeRpcServer, storeRpcClient, err := socketpair() if err != nil { - log.Fatal(err) + slog.Error("Failed to create socketpair", slog.Any("error", err)) + os.Exit(1) } storeFdServer, storeFdClient, err := socketpair() if err != nil { - log.Fatal(err) + slog.Error("Failed to create socketpair", slog.Any("error", err)) + os.Exit(1) } procStore, err := forkChild("store", []*os.File{storeRpcServer, storeFdServer}) if err != nil { - log.Fatal(err) + slog.Error("Failed to fork off child", slog.Any("error", err), slog.String("child", "store")) + os.Exit(1) } procWebserver, err := forkChild("webserver", []*os.File{storeRpcClient, storeFdClient}) if err != nil { - log.Fatal(err) + slog.Error("Failed to fork off child", slog.Any("error", err), slog.String("child", "webserver")) + os.Exit(1) } bottomlessPit, err := os.MkdirTemp("", "gosh-monitor-chroot") if err != nil { - log.WithError(err).Fatal("Cannot create bottomless pit jail") + slog.Error("Failed to create bottomless pit jail", slog.Any("error", err)) + os.Exit(1) } err = posixPermDrop(bottomlessPit, conf.User, conf.Group) if err != nil { - log.WithError(err).Fatal("Cannot drop permissions") + slog.Error("Failed to drop permissions", slog.Any("error", err)) + os.Exit(1) } err = restrict(restrict_linux_seccomp, @@ -104,7 +127,6 @@ func mainMonitor(conf Config) { "~@clock", "~@cpu-emulation", "~@debug", - "~@file-system", "~@keyring", "~@memlock", "~@module", @@ -118,12 +140,14 @@ func mainMonitor(conf Config) { /* @process */ "~execve", "~execveat", "~fork", }) if err != nil { - log.Fatal(err) + slog.Error("Failed to apply seccomp-bpf filter", slog.Any("error", err)) + os.Exit(1) } err = restrict(restrict_openbsd_pledge, "stdio tty proc error", "") if err != nil { - log.Fatal(err) + slog.Error("Failed to pledge", slog.Any("error", err)) + os.Exit(1) } sigintCh := make(chan os.Signal, 1) @@ -140,13 +164,13 @@ func mainMonitor(conf Config) { select { case <-sigintCh: - log.Info("Main process receives SIGINT, shutting down") + slog.Info("Main process receives SIGINT, shutting down") case <-storeCh: - log.Error("The store subprocess has stopped, cleaning up") + slog.Error("The store subprocess has stopped, cleaning up") case <-webserverCh: - log.Error("The web server subprocess has stopped, cleaning up") + slog.Error("The web server subprocess has stopped, cleaning up") } for i, childProc := range childProcs { @@ -160,9 +184,27 @@ func mainMonitor(conf Config) { } } -func main() { - log.SetFormatter(&log.TextFormatter{DisableTimestamp: true}) +// configureLogger sets the default logger with an optional debug log level and +// JSON encoded output, useful for the forked off childs. +func configureLogger(debug, jsonOutput bool) { + loggerLevel := new(slog.LevelVar) + if debug { + loggerLevel.Set(slog.LevelDebug) + } + + handlerOpts := &slog.HandlerOptions{Level: loggerLevel} + + var logger *slog.Logger + if jsonOutput { + logger = slog.New(slog.NewJSONHandler(os.Stderr, handlerOpts)) + } else { + logger = slog.New(slog.NewTextHandler(os.Stdout, handlerOpts)) + } + slog.SetDefault(logger) +} + +func main() { var ( flagConfig string flagForkChild string @@ -175,13 +217,12 @@ func main() { flag.Parse() - if flagVerbose { - log.SetLevel(log.DebugLevel) - } + configureLogger(flagVerbose, flagForkChild != "") conf, err := loadConfig(flagConfig) if err != nil { - log.WithError(err).Fatal("Cannot parse YAML configuration") + slog.Error("Failed to parse YAML configuration", slog.Any("error", err)) + os.Exit(1) } switch flagForkChild { @@ -195,6 +236,7 @@ func main() { mainMonitor(conf) default: - log.WithField("fork-child", flagForkChild).Fatal("Unknown child process") + slog.Error("Unknown child process identifier", slog.String("name", flagForkChild)) + os.Exit(1) } } diff --git a/gosh.yml b/gosh.yml index 7d9ea51..b5d09fe 100644 --- a/gosh.yml +++ b/gosh.yml @@ -9,6 +9,22 @@ group: "_gosh" store: path: "./store" + # id_generator specifies how the ID resp. name of new elements is generated. + id_generator: + # type specifies which generator to use: + # - "random" which generates a base58-encoded string of $length bytes. + # - "wordlist" picks $length words from $file where $file should contain + # one word per line. + type: "random" + # length is the ID length. + # - For the "random" type, this is the byte length, resulting in + # 2^($length * 8) possible combinations. + # - For the "wordlist" type, this is the amount of words, resulting in + # $wordlist_length^$length possible combinations. + length: 8 + # file is used as the source for type "wordlist". + # file: "/usr/share/dict/words" + # The webserver section describes the web server's configuration. # @@ -39,6 +55,20 @@ webserver: # url_prefix is an optional prefix in URL to be used, e.g., "/gosh" url_prefix: "" + # custom_index will be used instead of the compiled in index.html template. + # For starters, copy the index.html from the repository somewhere nice. + custom_index: "/path/to/alternative/index.html" + + # static_files to be read during startup and returned instead of being passed + # against the store's database. This might be used for custom resources. + static_files: + "/favicon.ico": + path: "/path/to/favicon.ico" + mime: "image/vnd.microsoft.icon" + "/custom.css": + path: "/path/to/custom.css" + mime: "text/css" + # item_config sets restrictions for new items, e.g., their max_size, in bytes # or suffixed with a unit, and max_lifetime, as a Go duration. Furthermore, # some MIME types might be dropped by mime_drop or rewritten with mime_map. diff --git a/gosh_store.go b/gosh_store.go index 5b01b71..3323629 100644 --- a/gosh_store.go +++ b/gosh_store.go @@ -1,11 +1,10 @@ package main import ( + "log/slog" "os" "os/signal" - log "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" ) @@ -38,16 +37,37 @@ func ensureStoreDir(path, username, groupname string) error { } func mainStore(conf Config) { - log.WithField("config", conf.Store).Debug("Starting store child") + slog.Debug("Starting store child", slog.Any("config", conf.Store)) + + var idGenerator func() (string, error) + switch conf.Store.IdGenerator.Type { + case "random": + idGenerator = randomIdGenerator(conf.Store.IdGenerator.Length) + + case "wordlist": + var err error + idGenerator, err = wordlistIdGenerator(conf.Store.IdGenerator.File, conf.Store.IdGenerator.Length) + if err != nil { + slog.Error("Failed to create wordlist ID generator", slog.Any("error", err)) + os.Exit(1) + } + + default: + slog.Error("Failed to configure an ID generator as the type is unknown", + slog.String("type", conf.Store.IdGenerator.Type)) + os.Exit(1) + } err := ensureStoreDir(conf.Store.Path, conf.User, conf.Group) if err != nil { - log.WithError(err).Fatal("Cannot prepare store directory") + slog.Error("Failed to prepare store directory", slog.Any("error", err)) + os.Exit(1) } err = posixPermDrop(conf.Store.Path, conf.User, conf.Group) if err != nil { - log.WithError(err).Fatal("Cannot drop permissions") + slog.Error("Failed to drop permissions", slog.Any("error", err)) + os.Exit(1) } err = restrict(restrict_linux_seccomp, @@ -70,28 +90,33 @@ func mainStore(conf Config) { /* @network-io */ "~bind", "~connect", "~listen", }) if err != nil { - log.Fatal(err) + slog.Error("Failed to apply seccomp-bpf filter", slog.Any("error", err)) + os.Exit(1) } err = restrict(restrict_openbsd_pledge, "stdio rpath wpath cpath flock unix sendfd recvfd error", "") if err != nil { - log.Fatal(err) + slog.Error("Failed to pledge", slog.Any("error", err)) + os.Exit(1) } - store, err := NewStore("/", true) + store, err := NewStore("/", idGenerator, true) if err != nil { - log.Fatal(err) + slog.Error("Failed to create store", slog.Any("error", err)) + os.Exit(1) } rpcConn, err := unixConnFromFile(os.NewFile(3, "")) if err != nil { - log.Fatal(err) + slog.Error("Failed to create Unix Domain Socket from FD", slog.Any("error", err)) + os.Exit(1) } fdConn, err := unixConnFromFile(os.NewFile(4, "")) if err != nil { - log.Fatal(err) + slog.Error("Failed to create Unix Domain Socket from FD", slog.Any("error", err)) + os.Exit(1) } rpcStore := NewStoreRpcServer(store, rpcConn, fdConn) @@ -102,6 +127,7 @@ func mainStore(conf Config) { err = rpcStore.Close() if err != nil { - log.Fatal(err) + slog.Error("Failed to close RPC Store", slog.Any("error", err)) + os.Exit(1) } } diff --git a/gosh_webserver.go b/gosh_webserver.go index cddbf9c..f93cb1a 100644 --- a/gosh_webserver.go +++ b/gosh_webserver.go @@ -2,15 +2,15 @@ package main import ( "fmt" + "io" "io/fs" + "log/slog" "net" "net/http" "os" "os/signal" "strconv" - log "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" ) @@ -81,46 +81,86 @@ func mkListenSocket(protocol, bound, unixChmod, unixOwner, unixGroup string) (*o } func mainWebserver(conf Config) { - log.WithField("config", conf.Webserver).Debug("Starting web server child") + slog.Debug("Starting webserver child", slog.Any("config", conf.Webserver)) rpcConn, err := unixConnFromFile(os.NewFile(3, "")) if err != nil { - log.Fatal(err) + slog.Error("Failed to prepare store directory", slog.Any("error", err)) + os.Exit(1) } fdConn, err := unixConnFromFile(os.NewFile(4, "")) if err != nil { - log.Fatal(err) + slog.Error("Failed to prepare store directory", slog.Any("error", err)) + os.Exit(1) } storeClient := NewStoreRpcClient(rpcConn, fdConn) + indexTpl := "" + if conf.Webserver.CustomIndex != "" { + f, err := os.Open(conf.Webserver.CustomIndex) + if err != nil { + slog.Error("Failed to open custom index file", slog.Any("error", err)) + os.Exit(1) + } + + indexTplRaw, err := io.ReadAll(f) + if err != nil { + slog.Error("Failed to read custom index file", slog.Any("error", err)) + os.Exit(1) + } + _ = f.Close() + + indexTpl = string(indexTplRaw) + } + + for k, sfc := range conf.Webserver.StaticFiles { + f, err := os.Open(sfc.Path) + if err != nil { + slog.Error("Failed to open static file", + slog.String("file", sfc.Path), slog.Any("error", err)) + os.Exit(1) + } + + sfc.data, err = io.ReadAll(f) + if err != nil { + slog.Error("Failed to read static file", + slog.String("file", sfc.Path), slog.Any("error", err)) + os.Exit(1) + } + _ = f.Close() + + conf.Webserver.StaticFiles[k] = sfc + } + maxFilesize, err := ParseBytesize(conf.Webserver.ItemConfig.MaxSize) if err != nil { - log.WithError(err).Fatal("Failed to parse byte size") + slog.Error("Failed to parse byte size", slog.Any("error", err)) + os.Exit(1) } - mimeMap := make(MimeMap) + mimeDrop := make(map[string]struct{}) for _, key := range conf.Webserver.ItemConfig.MimeDrop { - mimeMap[key] = MimeDrop - } - for key, value := range conf.Webserver.ItemConfig.MimeMap { - mimeMap[key] = value + mimeDrop[key] = struct{}{} } fd, err := mkListenSocket( conf.Webserver.Listen.Protocol, conf.Webserver.Listen.Bound, conf.Webserver.UnixSocket.Chmod, conf.Webserver.UnixSocket.Owner, conf.Webserver.UnixSocket.Group) if err != nil { - log.WithError(err).Fatal("Cannot create socket to be bound to") + slog.Error("Failed to create listening socket", slog.Any("error", err)) + os.Exit(1) } bottomlessPit, err := os.MkdirTemp("", "gosh-webserver-chroot") if err != nil { - log.WithError(err).Fatal("Cannot create bottomless pit jail") + slog.Error("Failed to create bottomless pit jail", slog.Any("error", err)) + os.Exit(1) } err = posixPermDrop(bottomlessPit, conf.User, conf.Group) if err != nil { - log.WithError(err).Fatal("Cannot drop permissions") + slog.Error("Failed to drop permissions", slog.Any("error", err)) + os.Exit(1) } err = restrict(restrict_linux_seccomp, @@ -143,24 +183,32 @@ func mainWebserver(conf Config) { /* @network-io */ "~bind", "~connect", "~listen", }) if err != nil { - log.Fatal(err) + slog.Error("Failed to apply seccomp-bpf filter", slog.Any("error", err)) + os.Exit(1) } err = restrict(restrict_openbsd_pledge, "stdio unix sendfd recvfd error", "") if err != nil { - log.Fatal(err) + slog.Error("Failed to pledge", slog.Any("error", err)) + os.Exit(1) } server, err := NewServer( storeClient, - maxFilesize, conf.Webserver.ItemConfig.MaxLifetime, + maxFilesize, + conf.Webserver.ItemConfig.MaxLifetime, conf.Webserver.Contact, - mimeMap, - conf.Webserver.UrlPrefix) + mimeDrop, + conf.Webserver.ItemConfig.MimeMap, + conf.Webserver.UrlPrefix, + indexTpl, + conf.Webserver.StaticFiles, + ) if err != nil { - log.WithError(err).Fatal("Cannot create web server") + slog.Error("Failed to create webserver", slog.Any("error", err)) + os.Exit(1) } defer server.Close() @@ -180,7 +228,8 @@ func mainWebserver(conf Config) { err = fmt.Errorf("unsupported protocol %q", conf.Webserver.Protocol) } if err != nil && err != http.ErrServerClosed { - log.WithError(err).Error("Web server failed to listen") + slog.Error("Webserver failed to listen", slog.Any("error", err)) + os.Exit(1) } close(serverCh) @@ -188,9 +237,9 @@ func mainWebserver(conf Config) { select { case <-sigintCh: - log.Info("Stopping web server") + slog.Info("Stopping webserver") case <-serverCh: - log.Error("Web server finished, shutting down") + slog.Error("Webserver finished, shutting down") } } diff --git a/index.html b/index.html index 9f78e4d..2ddf407 100644 --- a/index.html +++ b/index.html @@ -3,6 +3,8 @@