Compare commits

...

10 Commits

65 changed files with 3126 additions and 185 deletions

3
.gitignore vendored
View File

@ -7,3 +7,6 @@ dist/
/emissary.sqlite /emissary.sqlite
/.gitea-release /.gitea-release
/agent-key.json /agent-key.json
/apps
/server-key.json
/.emissary-token

View File

@ -2,6 +2,7 @@ project_name: emissary
before: before:
hooks: hooks:
- go mod tidy - go mod tidy
- go generate ./...
builds: builds:
- id: emissary-server - id: emissary-server
env: env:
@ -101,6 +102,18 @@ nfpms:
file_info: file_info:
mode: 0755 mode: 0755
packager: apk packager: apk
- dst: /var/lib/emissary
type: dir
file_info:
mode: 0700
- dst: /usr/share/emissary
type: dir
file_info:
mode: 0700
- dst: /var/log/emissary
type: dir
file_info:
mode: 0700
scripts: scripts:
postinstall: "misc/packaging/common/postinstall-server.sh" postinstall: "misc/packaging/common/postinstall-server.sh"
- id: emissary-agent - id: emissary-agent

View File

@ -138,3 +138,6 @@ tools/gitea-release/bin/gitea-release.sh:
mkdir -p tools/gitea-release/bin mkdir -p tools/gitea-release/bin
curl --output tools/gitea-release/bin/gitea-release.sh https://forge.cadoles.com/Cadoles/Jenkins/raw/branch/master/resources/com/cadoles/gitea/gitea-release.sh curl --output tools/gitea-release/bin/gitea-release.sh https://forge.cadoles.com/Cadoles/Jenkins/raw/branch/master/resources/com/cadoles/gitea/gitea-release.sh
chmod +x tools/gitea-release/bin/gitea-release.sh chmod +x tools/gitea-release/bin/gitea-release.sh
.emissary-token:
$(MAKE) run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml server auth create-token > .emissary-token"

59
go.mod
View File

@ -3,6 +3,7 @@ module forge.cadoles.com/Cadoles/emissary
go 1.19 go 1.19
require ( require (
forge.cadoles.com/arcad/edge v0.0.0-20230303153719-6399196fe5c9
github.com/alecthomas/participle/v2 v2.0.0-beta.5 github.com/alecthomas/participle/v2 v2.0.0-beta.5
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883
github.com/btcsuite/btcd/btcutil v1.1.3 github.com/btcsuite/btcd/btcutil v1.1.3
@ -12,28 +13,47 @@ require (
github.com/go-chi/chi v4.1.2+incompatible github.com/go-chi/chi v4.1.2+incompatible
github.com/go-chi/cors v1.2.1 github.com/go-chi/cors v1.2.1
github.com/golang-migrate/migrate/v4 v4.15.2 github.com/golang-migrate/migrate/v4 v4.15.2
github.com/jackc/pgx/v5 v5.2.0 github.com/jackc/pgx/v5 v5.3.1
github.com/jedib0t/go-pretty/v6 v6.4.4 github.com/jedib0t/go-pretty/v6 v6.4.4
github.com/lestrrat-go/jwx/v2 v2.0.8
github.com/lithammer/shortuuid/v4 v4.0.0
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/qri-io/jsonschema v0.2.1 github.com/qri-io/jsonschema v0.2.1
github.com/santhosh-tekuri/jsonschema/v5 v5.1.1 github.com/santhosh-tekuri/jsonschema/v5 v5.1.1
github.com/urfave/cli/v2 v2.23.7 github.com/urfave/cli/v2 v2.24.4
gitlab.com/wpetit/goweb v0.0.0-20230227162855-a1f09bafccb3 gitlab.com/wpetit/goweb v0.0.0-20230227162855-a1f09bafccb3
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v1.20.3 modernc.org/sqlite v1.21.0
) )
require google.golang.org/genproto v0.0.0-20220728213248-dd149ef739b9 // indirect require (
github.com/barnybug/go-cast v0.0.0-20201201064555-a87ccbc26692 // indirect
github.com/dop251/goja v0.0.0-20230226152633-7c93113e17ac // indirect
github.com/dop251/goja_nodejs v0.0.0-20230226152057-060fa99b809f // indirect
github.com/gabriel-vasile/mimetype v1.4.1 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/mdns v1.0.5 // indirect
github.com/igm/sockjs-go/v3 v3.0.2 // indirect
github.com/miekg/dns v1.1.51 // indirect
github.com/oklog/ulid/v2 v2.1.0 // indirect
github.com/orcaman/concurrent-map v1.0.0 // indirect
golang.org/x/net v0.7.0 // indirect
google.golang.org/genproto v0.0.0-20220728213248-dd149ef739b9 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
require ( require (
cdr.dev/slog v1.4.1 // indirect cdr.dev/slog v1.4.1 // indirect
github.com/alecthomas/chroma v0.10.0 // indirect github.com/alecthomas/chroma v0.10.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/dlclark/regexp2 v1.8.0 // indirect github.com/dlclark/regexp2 v1.8.1 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.13.0 // indirect github.com/fatih/color v1.14.1 // indirect
github.com/go-chi/chi/v5 v5.0.8
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/goccy/go-json v0.9.11 // indirect github.com/goccy/go-json v0.9.11 // indirect
@ -43,21 +63,20 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/puddle/v2 v2.1.2 // indirect github.com/jackc/puddle/v2 v2.2.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/leodido/go-urn v1.2.2 // indirect github.com/leodido/go-urn v1.2.2 // indirect
github.com/lestrrat-go/blackmagic v1.0.1 // indirect github.com/lestrrat-go/blackmagic v1.0.1 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.4 // indirect github.com/lestrrat-go/httprc v1.0.4 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/jwx/v2 v2.0.8 // indirect
github.com/lestrrat-go/option v1.0.0 // indirect github.com/lestrrat-go/option v1.0.0 // indirect
github.com/lib/pq v1.10.7 // indirect github.com/lib/pq v1.10.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/qri-io/jsonpointer v0.1.1 // indirect github.com/qri-io/jsonpointer v0.1.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
@ -65,23 +84,23 @@ require (
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.10.0 // indirect go.uber.org/atomic v1.10.0 // indirect
golang.org/x/crypto v0.5.0 // indirect golang.org/x/crypto v0.6.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/mod v0.8.0 // indirect
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.4.0 // indirect golang.org/x/sys v0.5.0 // indirect
golang.org/x/term v0.4.0 // indirect golang.org/x/term v0.5.0 // indirect
golang.org/x/text v0.6.0 // indirect golang.org/x/text v0.7.0 // indirect
golang.org/x/tools v0.1.12 // indirect golang.org/x/tools v0.6.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/go-playground/validator.v9 v9.31.0 // indirect gopkg.in/go-playground/validator.v9 v9.31.0 // indirect
lukechampine.com/uint128 v1.2.0 // indirect lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect modernc.org/ccgo/v3 v3.16.13 // indirect
modernc.org/libc v1.22.2 // indirect modernc.org/libc v1.22.3 // indirect
modernc.org/mathutil v1.5.0 // indirect modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.4.0 // indirect modernc.org/memory v1.5.0 // indirect
modernc.org/opt v0.1.3 // indirect modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect modernc.org/token v1.1.0 // indirect
) )

142
go.sum
View File

@ -54,6 +54,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
forge.cadoles.com/arcad/edge v0.0.0-20230303153719-6399196fe5c9 h1:dleaaf/rV2GWtGvrPunRakjrKVDfXoANxAy8/1ctMVs=
forge.cadoles.com/arcad/edge v0.0.0-20230303153719-6399196fe5c9/go.mod h1:pl9EMtSLSVr4wbDgQBDjr4aizwtmwasE686dm5arYPw=
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg=
github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
@ -178,6 +180,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.6.1/go.mod h1:hLZ/AnkIKHLuPGjEiyghNE
github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g= github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g=
github.com/aws/smithy-go v1.7.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.7.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/barnybug/go-cast v0.0.0-20201201064555-a87ccbc26692 h1:JW4WZlqyaNWUUahfr7MigeDW6jmtam5cTzzo1lwsFhE=
github.com/barnybug/go-cast v0.0.0-20201201064555-a87ccbc26692/go.mod h1:Au0ipPuCBA7zsOC61SnyrYetm8VT3vo1UJtwHeYke44=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@ -390,6 +394,7 @@ github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjI
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.0.1-0.20160907170601-6d212800a42e/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -410,8 +415,10 @@ github.com/dhui/dktest v0.3.10/go.mod h1:h5Enh0nG3Qbo9WjNFRrwmKUaePEBhXMOygbz3Ww
github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.8.0 h1:rJD5HeGIT/2b5CDk63FVCwZA3qgYElfg+oQK7uH5pfE= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.8.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.8.1 h1:6Lcdwya6GjPUNsBct8Lg/yRPwMhABj269AAzdGSiR+0=
github.com/dlclark/regexp2 v1.8.1/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
@ -434,9 +441,18 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja v0.0.0-20221118162653-d4bf6fde1b86/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs=
github.com/dop251/goja v0.0.0-20230226152633-7c93113e17ac h1:NGu46Adk2oPN3tinGFItahy4W9l+9uhEf03ZxbwmdVE=
github.com/dop251/goja v0.0.0-20230226152633-7c93113e17ac/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs=
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM=
github.com/dop251/goja_nodejs v0.0.0-20230226152057-060fa99b809f h1:mmnNidRg3cMfcgyeNtIBSDZgjf/85lA/2pplccwSxYg=
github.com/dop251/goja_nodejs v0.0.0-20230226152057-060fa99b809f/go.mod h1:0tlktQL7yHfYEtjcRGi/eiOkbDR5XF7gyFFvbC5//E0=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
@ -458,8 +474,8 @@ github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJ
github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
@ -473,6 +489,8 @@ github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q=
github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M=
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@ -480,6 +498,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=
@ -525,6 +545,8 @@ github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/Nu
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 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/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@ -567,6 +589,7 @@ github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
github.com/gogo/protobuf v0.0.0-20161014173244-50d1bd39ce4e/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
@ -692,6 +715,8 @@ github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
@ -719,12 +744,16 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.0-20151006203346-104dcad90073/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v0.0.0-20151206042412-9d85cf22f9f8/go.mod h1:aa76Av3qgPeIQp9Y3qIkTBPieQYNkQ13Kxe7pze9Wb0=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/mdns v1.0.5 h1:1M5hW1cunYeoXOqHwEb/GBDDHAFo0Yqb/uz/beC6LbE=
github.com/hashicorp/mdns v1.0.5/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
@ -732,6 +761,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/igm/sockjs-go/v3 v3.0.2 h1:2m0k53w0DBiGozeQUIEPR6snZFmpFpYvVsGnfLPNXbE=
github.com/igm/sockjs-go/v3 v3.0.2/go.mod h1:UqchsOjeagIBFHvd+RZpLaVRbCwGilEC08EDHsD1jYE=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
@ -782,15 +813,15 @@ github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXg
github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o=
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA= github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA=
github.com/jackc/pgx/v5 v5.2.0 h1:NdPpngX0Y6z6XDFKqmFQaE+bCtkqzvQIOt1wvBlAqs8= github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU=
github.com/jackc/pgx/v5 v5.2.0/go.mod h1:Ptn7zmohNsWEsdxRawMzk3gaKma2obW+NWTnKa0S4nk= github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle/v2 v2.1.2 h1:0f7vaaXINONKTsxYDn4otOAiJanX/BMeAtY//BXqzlg= github.com/jackc/puddle/v2 v2.2.0 h1:RdcDk92EJBuBS55nQMMYFXTxwstHug4jkhT5pq8VxPk=
github.com/jackc/puddle/v2 v2.1.2/go.mod h1:2lpufsF5mRHO6SuZkm0fNYxM6SWHfvyFj62KwNzgels= github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jedib0t/go-pretty/v6 v6.4.4 h1:N+gz6UngBPF4M288kiMURPHELDMIhF/Em35aYuKrsSc= github.com/jedib0t/go-pretty/v6 v6.4.4 h1:N+gz6UngBPF4M288kiMURPHELDMIhF/Em35aYuKrsSc=
github.com/jedib0t/go-pretty/v6 v6.4.4/go.mod h1:MgmISkTWDSFu0xOqiZ0mKNntMQ2mDgOcwOkwBEkMDJI= github.com/jedib0t/go-pretty/v6 v6.4.4/go.mod h1:MgmISkTWDSFu0xOqiZ0mKNntMQ2mDgOcwOkwBEkMDJI=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
@ -850,6 +881,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
@ -881,6 +913,8 @@ github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
github.com/lithammer/shortuuid/v4 v4.0.0 h1:QRbbVkfgNippHOS8PXDkti4NaWeyYfcBTHtw7k08o4c=
github.com/lithammer/shortuuid/v4 v4.0.0/go.mod h1:Zs8puNcrvf2rV9rTH51ZLLcj7ZXqQI3lv67aw4KiB1Y=
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@ -899,7 +933,6 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
@ -911,7 +944,6 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
@ -924,11 +956,15 @@ github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lL
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
github.com/miekg/dns v0.0.0-20161006100029-fc4e1e2843d8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/miekg/dns v1.1.51 h1:0+Xg7vObnhrz/4ZCZcZh7zPXlmU0aveS2HDBd0m0qSo=
github.com/miekg/dns v1.1.51/go.mod h1:2Z9d3CP1LQWihRZUf29mQ19yDThaI4DAYzte2CaQW5c=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@ -978,6 +1014,8 @@ github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYX
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@ -1033,8 +1071,11 @@ github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/orcaman/concurrent-map v1.0.0 h1:I/2A2XPCb4IuQWcQhBhSwGfiuybl/J0ev9HDbW65HOY=
github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
@ -1053,6 +1094,7 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
@ -1095,8 +1137,9 @@ github.com/qri-io/jsonpointer v0.1.1/go.mod h1:DnJPaYgiKu56EuDp8TU5wFLdZIcAnb/uH
github.com/qri-io/jsonschema v0.2.1 h1:NNFoKms+kut6ABPf6xiKNM5214jzxAhDBrPHCJ97Wg0= github.com/qri-io/jsonschema v0.2.1 h1:NNFoKms+kut6ABPf6xiKNM5214jzxAhDBrPHCJ97Wg0=
github.com/qri-io/jsonschema v0.2.1/go.mod h1:g7DPkiOsK1xv6T/Ao5scXRkd+yTFygcANPBaaqW+VrI= github.com/qri-io/jsonschema v0.2.1/go.mod h1:g7DPkiOsK1xv6T/Ao5scXRkd+yTFygcANPBaaqW+VrI=
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@ -1104,6 +1147,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
@ -1175,6 +1219,7 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 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.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.1.5-0.20160925220609-976c720a22c8/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -1203,8 +1248,8 @@ github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.23.7 h1:YHDQ46s3VghFHFf1DdF+Sh7H4RqhcM+t0TmZRJx4oJY= github.com/urfave/cli/v2 v2.24.4 h1:0gyJJEBYtCV87zI/x2nZCPyDxD51K6xM8SkwjHFCNEU=
github.com/urfave/cli/v2 v2.23.7/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/urfave/cli/v2 v2.24.4/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
@ -1234,6 +1279,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
@ -1327,8 +1373,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -1376,8 +1422,11 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20161013035702-8b4af36cd21a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1434,6 +1483,7 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@ -1447,7 +1497,12 @@ golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -1478,8 +1533,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1569,6 +1625,7 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1603,16 +1660,22 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -1622,8 +1685,10 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -1711,8 +1776,10 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1927,6 +1994,7 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@ -2009,8 +2077,8 @@ modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/internal v1.0.0/go.mod h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM= modernc.org/internal v1.0.0/go.mod h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM=
modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.5/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= modernc.org/libc v1.9.5/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.22.2 h1:4U7v51GyhlWqQmwCHj28Rdq2Yzwk55ovjFrdPjs8Hb0= modernc.org/libc v1.22.3 h1:D/g6O5ftAfavceqlLOFwaZuA5KYafKwmr30A6iSqoyY=
modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug= modernc.org/libc v1.22.3/go.mod h1:MQrloYP209xa2zHome2a8HLiLm6k0UT8CoHpV74tOFw=
modernc.org/lldb v1.0.0/go.mod h1:jcRvJGWfCGodDZz8BPwiKMJxGJngQ/5DrRapkQnLob8= modernc.org/lldb v1.0.0/go.mod h1:jcRvJGWfCGodDZz8BPwiKMJxGJngQ/5DrRapkQnLob8=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
@ -2018,24 +2086,24 @@ modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc= modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk= modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/ql v1.0.0/go.mod h1:xGVyrLIatPcO2C1JvI/Co8c0sr6y91HKFNy4pt9JXEY= modernc.org/ql v1.0.0/go.mod h1:xGVyrLIatPcO2C1JvI/Co8c0sr6y91HKFNy4pt9JXEY=
modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k= modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k=
modernc.org/sqlite v1.10.6/go.mod h1:Z9FEjUtZP4qFEg6/SiADg9XCER7aYy9a/j7Pg9P7CPs= modernc.org/sqlite v1.10.6/go.mod h1:Z9FEjUtZP4qFEg6/SiADg9XCER7aYy9a/j7Pg9P7CPs=
modernc.org/sqlite v1.20.3 h1:SqGJMMxjj1PHusLxdYxeQSodg7Jxn9WWkaAQjKrntZs= modernc.org/sqlite v1.21.0 h1:4aP4MdUf15i3R3M2mx6Q90WHKz3nZLoz96zlB6tNdow=
modernc.org/sqlite v1.20.3/go.mod h1:zKcGyrICaxNTMEHSr1HQ2GUraP0j+845GYw37+EyT6A= modernc.org/sqlite v1.21.0/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI=
modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/tcl v1.5.2/go.mod h1:pmJYOLgpiys3oI4AeAafkcUfE+TKKilminxNyU/+Zlo= modernc.org/tcl v1.5.2/go.mod h1:pmJYOLgpiys3oI4AeAafkcUfE+TKKilminxNyU/+Zlo=
modernc.org/tcl v1.15.0 h1:oY+JeD11qVVSgVvodMJsu7Edf8tr5E/7tuhF5cNYz34= modernc.org/tcl v1.15.1 h1:mOQwiEK4p7HruMZcwKTZPw/aqtGM4aY00uzWhlKKYws=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.0.1-0.20210308123920-1f282aa71362/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA= modernc.org/z v1.0.1-0.20210308123920-1f282aa71362/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA= modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE= modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE=

View File

@ -5,6 +5,7 @@ import (
"time" "time"
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata" "forge.cadoles.com/Cadoles/emissary/internal/agent/metadata"
"forge.cadoles.com/Cadoles/emissary/internal/auth/agent"
"forge.cadoles.com/Cadoles/emissary/internal/client" "forge.cadoles.com/Cadoles/emissary/internal/client"
"forge.cadoles.com/Cadoles/emissary/internal/jwk" "forge.cadoles.com/Cadoles/emissary/internal/jwk"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -15,7 +16,7 @@ import (
type Agent struct { type Agent struct {
thumbprint string thumbprint string
privateKey jwk.Key privateKey jwk.Key
client *client.Client serverURL string
controllers []Controller controllers []Controller
interval time.Duration interval time.Duration
collectors []metadata.Collector collectors []metadata.Collector
@ -29,7 +30,15 @@ func (a *Agent) Run(ctx context.Context) error {
ticker := time.NewTicker(a.interval) ticker := time.NewTicker(a.interval)
defer ticker.Stop() defer ticker.Stop()
ctx = withClient(ctx, a.client) logger.Info(ctx, "generating token")
token, err := agent.GenerateToken(a.privateKey, a.thumbprint)
if err != nil {
return errors.WithStack(err)
}
client := client.New(a.serverURL, client.WithToken(token))
ctx = withClient(ctx, client)
for { for {
select { select {
@ -37,7 +46,7 @@ func (a *Agent) Run(ctx context.Context) error {
logger.Debug(ctx, "registering agent") logger.Debug(ctx, "registering agent")
if err := a.registerAgent(ctx, state); err != nil { if err := a.registerAgent(ctx, client, state); err != nil {
logger.Error(ctx, "could not register agent", logger.E(errors.WithStack(err))) logger.Error(ctx, "could not register agent", logger.E(errors.WithStack(err)))
continue continue
@ -76,7 +85,7 @@ func (a *Agent) Reconcile(ctx context.Context, state *State) error {
return nil return nil
} }
func (a *Agent) registerAgent(ctx context.Context, state *State) error { func (a *Agent) registerAgent(ctx context.Context, client *client.Client, state *State) error {
meta, err := a.collectMetadata(ctx) meta, err := a.collectMetadata(ctx)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
@ -84,7 +93,7 @@ func (a *Agent) registerAgent(ctx context.Context, state *State) error {
sorted := metadata.Sort(meta) sorted := metadata.Sort(meta)
agent, err := a.client.RegisterAgent(ctx, a.privateKey, a.thumbprint, sorted) agent, err := client.RegisterAgent(ctx, a.privateKey, a.thumbprint, sorted)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
@ -129,12 +138,10 @@ func New(serverURL string, privateKey jwk.Key, thumbprint string, funcs ...Optio
fn(opt) fn(opt)
} }
client := client.New(serverURL)
return &Agent{ return &Agent{
serverURL: serverURL,
privateKey: privateKey, privateKey: privateKey,
thumbprint: thumbprint, thumbprint: thumbprint,
client: client,
controllers: opt.Controllers, controllers: opt.Controllers,
interval: opt.Interval, interval: opt.Interval,
collectors: opt.Collectors, collectors: opt.Collectors,

View File

@ -0,0 +1,286 @@
package app
import (
"context"
"io"
"net/http"
"os"
"path/filepath"
"forge.cadoles.com/Cadoles/emissary/internal/agent"
"forge.cadoles.com/Cadoles/emissary/internal/spec/app"
"forge.cadoles.com/arcad/edge/pkg/bundle"
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type Controller struct {
currentSpecRevision int
client *http.Client
downloadDir string
dataDir string
servers map[string]*Server
}
// Name implements node.Controller.
func (c *Controller) Name() string {
return "app-controller"
}
// Reconcile implements node.Controller.
func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
appSpec := app.NewSpec()
if err := state.GetSpec(app.NameApp, appSpec); err != nil {
if errors.Is(err, agent.ErrSpecNotFound) {
logger.Info(ctx, "could not find app spec, stopping all remaining apps")
c.stopAllApps(ctx)
return nil
}
return errors.WithStack(err)
}
logger.Info(ctx, "retrieved spec", logger.F("spec", appSpec.SpecName()), logger.F("revision", appSpec.SpecRevision()))
if c.currentSpecRevision == appSpec.SpecRevision() {
logger.Info(ctx, "spec revision did not change, doing nothing")
return nil
}
c.updateApps(ctx, appSpec)
return nil
}
func (c *Controller) stopAllApps(ctx context.Context) {
for appID, server := range c.servers {
logger.Info(ctx, "stopping app", logger.F("appID", appID))
if err := server.Stop(); err != nil {
logger.Error(
ctx, "error while stopping app",
logger.F("appID", appID),
logger.E(errors.WithStack(err)),
)
delete(c.servers, appID)
}
}
}
func (c *Controller) updateApps(ctx context.Context, spec *app.Spec) {
hadError := false
// Stop and remove obsolete apps
for appID, server := range c.servers {
if _, exists := spec.Apps[appID]; exists {
continue
}
logger.Info(ctx, "stopping app", logger.F("appID", appID))
if err := server.Stop(); err != nil {
logger.Error(
ctx, "error while stopping app",
logger.F("gatewayID", appID),
logger.E(errors.WithStack(err)),
)
delete(c.servers, appID)
hadError = true
}
}
// (Re)start apps
for appID, appSpec := range spec.Apps {
appCtx := logger.With(ctx, logger.F("appID", appID))
if err := c.updateApp(ctx, appID, appSpec); err != nil {
logger.Error(appCtx, "could not update app", logger.E(errors.WithStack(err)))
hadError = true
continue
}
}
if !hadError {
c.currentSpecRevision = spec.SpecRevision()
logger.Info(ctx, "updating current spec revision", logger.F("revision", c.currentSpecRevision))
}
}
func (c *Controller) updateApp(ctx context.Context, appID string, appSpec app.AppEntry) error {
bundle, sha256sum, err := c.ensureAppBundle(ctx, appID, appSpec)
if err != nil {
return errors.Wrap(err, "could not download app bundle")
}
dataDir, err := c.ensureAppDataDir(ctx, appID)
if err != nil {
return errors.Wrap(err, "could not retrieve app data dir")
}
server, exists := c.servers[appID]
if !exists {
logger.Info(ctx, "app currently not running")
} else if sha256sum != appSpec.SHA256Sum {
logger.Info(
ctx, "bundle hash mismatch, stopping app",
logger.F("currentHash", sha256sum),
logger.F("specHash", appSpec.SHA256Sum),
)
if err := server.Stop(); err != nil {
return errors.Wrap(err, "could not stop app")
}
server = nil
}
if server == nil {
dbFile := filepath.Join(dataDir, appID+".sqlite")
db, err := sqlite.Open(dbFile)
if err != nil {
return errors.Wrapf(err, "could not opend database file '%s'", dbFile)
}
server = NewServer(bundle, db)
c.servers[appID] = server
}
logger.Info(
ctx, "starting app",
logger.F("address", appSpec.Address),
)
if err := server.Start(ctx, appSpec.Address); err != nil {
delete(c.servers, appID)
return errors.Wrap(err, "could not start app")
}
return nil
}
func (c *Controller) ensureAppBundle(ctx context.Context, appID string, spec app.AppEntry) (bundle.Bundle, string, error) {
if err := os.MkdirAll(c.downloadDir, os.ModePerm); err != nil {
return nil, "", errors.WithStack(err)
}
bundlePath := filepath.Join(c.downloadDir, appID+"."+spec.Format)
_, err := os.Stat(bundlePath)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return nil, "", errors.WithStack(err)
}
if errors.Is(err, os.ErrNotExist) {
if err := c.downloadFile(spec.URL, spec.SHA256Sum, bundlePath); err != nil {
return nil, "", errors.WithStack(err)
}
}
sha256sum, err := hash(bundlePath)
if err != nil {
return nil, "", errors.WithStack(err)
}
if sha256sum == spec.SHA256Sum {
bdle, err := bundle.FromPath(bundlePath)
if err != nil {
return nil, "", errors.WithStack(err)
}
return bdle, sha256sum, nil
}
logger.Info(ctx, "bundle hash mismatch, downloading app", logger.F("url", spec.URL))
if err := c.downloadFile(spec.URL, spec.SHA256Sum, bundlePath); err != nil {
return nil, "", errors.WithStack(err)
}
bdle, err := bundle.FromPath(bundlePath)
if err != nil {
return nil, "", errors.WithStack(err)
}
return bdle, "", nil
}
func (c *Controller) downloadFile(url string, sha256sum string, dest string) error {
res, err := c.client.Get(url)
if err != nil {
return errors.WithStack(err)
}
defer func() {
if err := res.Body.Close(); err != nil && !errors.Is(err, os.ErrClosed) {
panic(errors.WithStack(err))
}
}()
tmp, err := os.CreateTemp(filepath.Dir(dest), "download_")
if err != nil {
return errors.WithStack(err)
}
defer func() {
if err := os.Remove(tmp.Name()); err != nil && !os.IsNotExist(err) {
panic(errors.WithStack(err))
}
}()
if _, err := io.Copy(tmp, res.Body); err != nil {
return errors.WithStack(err)
}
tmpFileHash, err := hash(tmp.Name())
if err != nil {
return errors.WithStack(err)
}
if tmpFileHash != sha256sum {
return errors.Errorf("sha256 sum mismatch: expected '%s', got '%s'", sha256sum, tmpFileHash)
}
if err := os.Rename(tmp.Name(), dest); err != nil {
return errors.WithStack(err)
}
return nil
}
func (c *Controller) ensureAppDataDir(ctx context.Context, appID string) (string, error) {
dataDir := filepath.Join(c.dataDir, appID)
if err := os.MkdirAll(dataDir, os.ModePerm); err != nil {
return "", errors.WithStack(err)
}
return dataDir, nil
}
func NewController(funcs ...OptionFunc) *Controller {
opts := defaultOptions()
for _, fn := range funcs {
fn(opts)
}
return &Controller{
client: opts.Client,
downloadDir: opts.DownloadDir,
dataDir: opts.DataDir,
currentSpecRevision: -1,
servers: make(map[string]*Server),
}
}
var _ agent.Controller = &Controller{}

View File

@ -0,0 +1,31 @@
package app
import (
"crypto/sha256"
"encoding/hex"
"io"
"os"
"github.com/pkg/errors"
)
func hash(path string) (string, error) {
file, err := os.Open(path)
if err != nil {
return "", errors.WithStack(err)
}
hasher := sha256.New()
defer func() {
if err := file.Close(); err != nil {
panic(errors.WithStack(err))
}
}()
if _, err := io.Copy(hasher, file); err != nil {
return "", errors.WithStack(err)
}
return hex.EncodeToString(hasher.Sum(nil)), nil
}

View File

@ -0,0 +1,37 @@
package app
import "net/http"
type Options struct {
DataDir string
DownloadDir string
Client *http.Client
}
func defaultOptions() *Options {
return &Options{
DataDir: "apps/data",
DownloadDir: "apps/download",
Client: &http.Client{},
}
}
type OptionFunc func(*Options)
func WithDataDir(dataDir string) OptionFunc {
return func(o *Options) {
o.DataDir = dataDir
}
}
func WithDownloadDir(downloadDir string) OptionFunc {
return func(o *Options) {
o.DownloadDir = downloadDir
}
}
func WithClient(client *http.Client) OptionFunc {
return func(o *Options) {
o.Client = client
}
}

View File

@ -0,0 +1,125 @@
package app
import (
"context"
"database/sql"
"net/http"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/bus"
"forge.cadoles.com/arcad/edge/pkg/bus/memory"
edgeHTTP "forge.cadoles.com/arcad/edge/pkg/http"
"forge.cadoles.com/arcad/edge/pkg/module"
"forge.cadoles.com/arcad/edge/pkg/module/cast"
"forge.cadoles.com/arcad/edge/pkg/module/net"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
"forge.cadoles.com/arcad/edge/pkg/bundle"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/chi/v5"
"github.com/pkg/errors"
)
type Server struct {
bundle bundle.Bundle
db *sql.DB
server *http.Server
}
func (s *Server) Start(ctx context.Context, addr string) error {
if s.server != nil {
if err := s.Stop(); err != nil {
return errors.WithStack(err)
}
}
router := chi.NewRouter()
router.Use(middleware.Logger)
bus := memory.NewBus()
ds := sqlite.NewDocumentStoreWithDB(s.db)
bs := sqlite.NewBlobStoreWithDB(s.db)
handler := edgeHTTP.NewHandler(
edgeHTTP.WithBus(bus),
edgeHTTP.WithServerModules(s.getAppModules(bus, ds, bs)...),
)
if err := handler.Load(s.bundle); err != nil {
return errors.Wrap(err, "could not load app bundle")
}
router.Handle("/*", handler)
server := &http.Server{
Addr: addr,
Handler: router,
}
go func() {
defer func() {
if err := s.Stop(); err != nil {
panic(errors.WithStack(err))
}
}()
if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
panic(errors.WithStack(err))
}
}()
s.server = server
return nil
}
func (s *Server) Stop() error {
if s.server == nil {
return nil
}
defer func() {
s.server = nil
}()
if err := s.server.Close(); err != nil {
panic(errors.WithStack(err))
}
return nil
}
func (s *Server) getAppModules(bus bus.Bus, ds storage.DocumentStore, bs storage.BlobStore) []app.ServerModuleFactory {
return []app.ServerModuleFactory{
module.ContextModuleFactory(),
module.ConsoleModuleFactory(),
cast.CastModuleFactory(),
module.LifecycleModuleFactory(),
net.ModuleFactory(bus),
module.RPCModuleFactory(bus),
module.StoreModuleFactory(ds),
module.BlobModuleFactory(bus, bs),
// module.Extends(
// auth.ModuleFactory(
// auth.WithJWT(dummyKeyFunc),
// ),
// func(o *goja.Object) {
// if err := o.Set("CLAIM_ROLE", "role"); err != nil {
// panic(errors.New("could not set 'CLAIM_ROLE' property"))
// }
// if err := o.Set("CLAIM_PREFERRED_USERNAME", "preferred_username"); err != nil {
// panic(errors.New("could not set 'CLAIM_PREFERRED_USERNAME' property"))
// }
// },
// ),
}
}
func NewServer(bundle bundle.Bundle, db *sql.DB) *Server {
return &Server{
bundle: bundle,
db: db,
}
}

View File

@ -0,0 +1,92 @@
package agent
import (
"context"
"net/http"
"strings"
"forge.cadoles.com/Cadoles/emissary/internal/auth"
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
"github.com/lestrrat-go/jwx/v2/jws"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type Authenticator struct {
repo datastore.AgentRepository
}
// Authenticate implements auth.Authenticator.
func (a *Authenticator) Authenticate(ctx context.Context, r *http.Request) (auth.User, error) {
ctx = logger.With(r.Context(), logger.F("remoteAddr", r.RemoteAddr))
authorization := r.Header.Get("Authorization")
if authorization == "" {
return nil, errors.WithStack(auth.ErrUnauthenticated)
}
rawToken := strings.TrimPrefix(authorization, "Bearer ")
if rawToken == "" {
return nil, errors.WithStack(auth.ErrUnauthenticated)
}
token, err := jwt.Parse([]byte(rawToken), jwt.WithVerify(false))
if err != nil {
return nil, errors.WithStack(err)
}
rawThumbprint, exists := token.Get(keyThumbprint)
if !exists {
return nil, errors.Errorf("could not find '%s' claim", keyThumbprint)
}
thumbrint, ok := rawThumbprint.(string)
if !ok {
return nil, errors.Errorf("unexpected '%s' claim value: '%v'", keyThumbprint, rawThumbprint)
}
agents, _, err := a.repo.Query(
ctx,
datastore.WithAgentQueryThumbprints(thumbrint),
datastore.WithAgentQueryLimit(1),
)
if err != nil {
return nil, errors.WithStack(err)
}
if len(agents) != 1 {
return nil, errors.Errorf("unexpected number of found agents: '%d'", len(agents))
}
agent, err := a.repo.Get(
ctx,
agents[0].ID,
)
if err != nil {
return nil, errors.WithStack(err)
}
_, err = jwt.Parse(
[]byte(rawToken),
jwt.WithKeySet(agent.KeySet.Set, jws.WithRequireKid(false)),
jwt.WithValidate(true),
)
if err != nil {
return nil, errors.WithStack(err)
}
user := &User{
agent: agent,
}
return user, nil
}
func NewAuthenticator(repo datastore.AgentRepository) *Authenticator {
return &Authenticator{
repo: repo,
}
}
var _ auth.Authenticator = &Authenticator{}

View File

@ -0,0 +1,37 @@
package agent
import (
"time"
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/pkg/errors"
)
const keyThumbprint = "thumbprint"
func GenerateToken(key jwk.Key, thumbprint string) (string, error) {
token := jwt.New()
if err := token.Set(keyThumbprint, thumbprint); err != nil {
return "", errors.WithStack(err)
}
now := time.Now()
if err := token.Set(jwt.NotBeforeKey, now); err != nil {
return "", errors.WithStack(err)
}
if err := token.Set(jwt.IssuedAtKey, now); err != nil {
return "", errors.WithStack(err)
}
rawToken, err := jwt.Sign(token, jwt.WithKey(jwa.RS256, key))
if err != nil {
return "", errors.WithStack(err)
}
return string(rawToken), nil
}

View File

@ -0,0 +1,23 @@
package agent
import (
"fmt"
"forge.cadoles.com/Cadoles/emissary/internal/auth"
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
)
type User struct {
agent *datastore.Agent
}
// Subject implements auth.User
func (u *User) Subject() string {
return fmt.Sprintf("agent-%d", u.agent.ID)
}
func (u *User) Agent() *datastore.Agent {
return u.agent
}
var _ auth.User = &User{}

View File

@ -0,0 +1,79 @@
package auth
import (
"context"
"net/http"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/api"
"gitlab.com/wpetit/goweb/logger"
)
const (
ErrCodeUnauthorized api.ErrorCode = "unauthorized"
ErrCodeForbidden api.ErrorCode = "forbidden"
)
type contextKey string
const (
contextKeyUser contextKey = "user"
)
func CtxUser(ctx context.Context) (*User, error) {
user, ok := ctx.Value(contextKeyUser).(*User)
if !ok {
return nil, errors.Errorf("unexpected user type: expected '%T', got '%T'", new(User), ctx.Value(contextKeyUser))
}
return user, nil
}
var ErrUnauthenticated = errors.New("unauthenticated")
type User interface {
Subject() string
}
type Authenticator interface {
Authenticate(context.Context, *http.Request) (User, error)
}
func Middleware(authenticators ...Authenticator) func(http.Handler) http.Handler {
return func(h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
ctx := logger.With(r.Context(), logger.F("remoteAddr", r.RemoteAddr))
var (
user User
err error
)
for _, auth := range authenticators {
user, err = auth.Authenticate(ctx, r)
if err != nil {
logger.Debug(ctx, "could not authenticate request", logger.E(errors.WithStack(err)))
continue
}
if user != nil {
break
}
}
if user == nil {
api.ErrorResponse(w, http.StatusUnauthorized, ErrCodeUnauthorized, nil)
return
}
ctx = logger.With(ctx, logger.F("user", user.Subject()))
ctx = context.WithValue(ctx, contextKeyUser, user)
h.ServeHTTP(w, r.WithContext(ctx))
}
return http.HandlerFunc(fn)
}
}

View File

@ -0,0 +1,67 @@
package user
import (
"context"
"net/http"
"strings"
"forge.cadoles.com/Cadoles/emissary/internal/auth"
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type Authenticator struct {
keys jwk.Set
issuer string
}
// Authenticate implements auth.Authenticator.
func (a *Authenticator) Authenticate(ctx context.Context, r *http.Request) (auth.User, error) {
ctx = logger.With(r.Context(), logger.F("remoteAddr", r.RemoteAddr))
authorization := r.Header.Get("Authorization")
if authorization == "" {
return nil, errors.WithStack(auth.ErrUnauthenticated)
}
rawToken := strings.TrimPrefix(authorization, "Bearer ")
if rawToken == "" {
return nil, errors.WithStack(auth.ErrUnauthenticated)
}
token, err := parseToken(ctx, a.keys, a.issuer, rawToken)
if err != nil {
return nil, errors.WithStack(err)
}
rawRole, exists := token.Get(keyRole)
if !exists {
return nil, errors.New("could not find 'thumbprint' claim")
}
role, ok := rawRole.(string)
if !ok {
return nil, errors.Errorf("unexpected '%s' claim value: '%v'", keyRole, rawRole)
}
if !isValidRole(role) {
return nil, errors.Errorf("invalid role '%s'", role)
}
user := &User{
subject: token.Subject(),
role: Role(role),
}
return user, nil
}
func NewAuthenticator(keys jwk.Set, issuer string) *Authenticator {
return &Authenticator{
keys: keys,
issuer: issuer,
}
}
var _ auth.Authenticator = &Authenticator{}

61
internal/auth/user/jwt.go Normal file
View File

@ -0,0 +1,61 @@
package user
import (
"context"
"time"
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jws"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/pkg/errors"
)
const keyRole = "role"
func parseToken(ctx context.Context, keys jwk.Set, issuer string, rawToken string) (jwt.Token, error) {
token, err := jwt.Parse(
[]byte(rawToken),
jwt.WithKeySet(keys, jws.WithRequireKid(false)),
jwt.WithIssuer(issuer),
jwt.WithValidate(true),
)
if err != nil {
return nil, errors.WithStack(err)
}
return token, nil
}
func GenerateToken(ctx context.Context, key jwk.Key, issuer, subject string, role Role) (string, error) {
token := jwt.New()
if err := token.Set(jwt.SubjectKey, subject); err != nil {
return "", errors.WithStack(err)
}
if err := token.Set(jwt.IssuerKey, issuer); err != nil {
return "", errors.WithStack(err)
}
if err := token.Set(keyRole, role); err != nil {
return "", errors.WithStack(err)
}
now := time.Now()
if err := token.Set(jwt.NotBeforeKey, now); err != nil {
return "", errors.WithStack(err)
}
if err := token.Set(jwt.IssuedAtKey, now); err != nil {
return "", errors.WithStack(err)
}
rawToken, err := jwt.Sign(token, jwt.WithKey(jwa.RS256, key))
if err != nil {
return "", errors.WithStack(err)
}
return string(rawToken), nil
}

View File

@ -0,0 +1,32 @@
package user
import "forge.cadoles.com/Cadoles/emissary/internal/auth"
type Role string
const (
RoleWriter Role = "writer"
RoleReader Role = "reader"
)
func isValidRole(r string) bool {
rr := Role(r)
return rr == RoleWriter || rr == RoleReader
}
type User struct {
subject string
role Role
}
// Subject implements auth.User
func (u *User) Subject() string {
return u.subject
}
func (u *User) Role() Role {
return u.role
}
var _ auth.User = &User{}

View File

@ -13,44 +13,49 @@ import (
) )
type Client struct { type Client struct {
http *http.Client http *http.Client
token string defaultOpts Options
serverURL string serverURL string
} }
func (c *Client) apiGet(ctx context.Context, path string, result any) error { func (c *Client) apiGet(ctx context.Context, path string, result any, funcs ...OptionFunc) error {
if err := c.apiDo(ctx, http.MethodGet, path, nil, result); err != nil { if err := c.apiDo(ctx, http.MethodGet, path, nil, result, funcs...); err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
return nil return nil
} }
func (c *Client) apiPost(ctx context.Context, path string, payload any, result any) error { func (c *Client) apiPost(ctx context.Context, path string, payload any, result any, funcs ...OptionFunc) error {
if err := c.apiDo(ctx, http.MethodPost, path, payload, result); err != nil { if err := c.apiDo(ctx, http.MethodPost, path, payload, result, funcs...); err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
return nil return nil
} }
func (c *Client) apiPut(ctx context.Context, path string, payload any, result any) error { func (c *Client) apiPut(ctx context.Context, path string, payload any, result any, funcs ...OptionFunc) error {
if err := c.apiDo(ctx, http.MethodPut, path, payload, result); err != nil { if err := c.apiDo(ctx, http.MethodPut, path, payload, result, funcs...); err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
return nil return nil
} }
func (c *Client) apiDelete(ctx context.Context, path string, payload any, result any) error { func (c *Client) apiDelete(ctx context.Context, path string, payload any, result any, funcs ...OptionFunc) error {
if err := c.apiDo(ctx, http.MethodDelete, path, payload, result); err != nil { if err := c.apiDo(ctx, http.MethodDelete, path, payload, result, funcs...); err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
return nil return nil
} }
func (c *Client) apiDo(ctx context.Context, method string, path string, payload any, response any) error { func (c *Client) apiDo(ctx context.Context, method string, path string, payload any, response any, funcs ...OptionFunc) error {
opts := c.defaultOptions()
for _, fn := range funcs {
fn(opts)
}
url := c.serverURL + path url := c.serverURL + path
logger.Debug( logger.Debug(
@ -73,6 +78,12 @@ func (c *Client) apiDo(ctx context.Context, method string, path string, payload
return errors.WithStack(err) return errors.WithStack(err)
} }
for key, values := range opts.Headers {
for _, v := range values {
req.Header.Add(key, v)
}
}
res, err := c.http.Do(req) res, err := c.http.Do(req)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
@ -89,6 +100,12 @@ func (c *Client) apiDo(ctx context.Context, method string, path string, payload
return nil return nil
} }
func (c *Client) defaultOptions() *Options {
return &Options{
Headers: c.defaultOpts.Headers,
}
}
func withResponse[T any]() struct { func withResponse[T any]() struct {
Data T Data T
Error *api.Error Error *api.Error
@ -113,9 +130,15 @@ func joinSlice[T any](items []T) string {
return str return str
} }
func New(serverURL string) *Client { func New(serverURL string, funcs ...OptionFunc) *Client {
opts := Options{}
for _, fn := range funcs {
fn(&opts)
}
return &Client{ return &Client{
serverURL: serverURL, serverURL: serverURL,
http: &http.Client{}, http: &http.Client{},
defaultOpts: opts,
} }
} }

View File

@ -8,14 +8,14 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func (c *Client) GetAgent(ctx context.Context, agentID datastore.AgentID) (*datastore.Agent, error) { func (c *Client) GetAgent(ctx context.Context, agentID datastore.AgentID, funcs ...OptionFunc) (*datastore.Agent, error) {
response := withResponse[struct { response := withResponse[struct {
Agent *datastore.Agent `json:"agent"` Agent *datastore.Agent `json:"agent"`
}]() }]()
path := fmt.Sprintf("/api/v1/agents/%d", agentID) path := fmt.Sprintf("/api/v1/agents/%d", agentID)
if err := c.apiGet(ctx, path, &response); err != nil { if err := c.apiGet(ctx, path, &response, funcs...); err != nil {
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
} }

View File

@ -9,14 +9,14 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func (c *Client) GetAgentSpecs(ctx context.Context, agentID datastore.AgentID) ([]spec.Spec, error) { func (c *Client) GetAgentSpecs(ctx context.Context, agentID datastore.AgentID, funcs ...OptionFunc) ([]spec.Spec, error) {
response := withResponse[struct { response := withResponse[struct {
Specs []*spec.RawSpec `json:"specs"` Specs []*spec.RawSpec `json:"specs"`
}]() }]()
path := fmt.Sprintf("/api/v1/agents/%d/specs", agentID) path := fmt.Sprintf("/api/v1/agents/%d/specs", agentID)
if err := c.apiGet(ctx, path, &response); err != nil { if err := c.apiGet(ctx, path, &response, funcs...); err != nil {
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
} }

View File

@ -0,0 +1,24 @@
package client
import "net/http"
type Options struct {
Headers http.Header
}
type OptionFunc func(*Options)
func WithToken(token string) OptionFunc {
return func(o *Options) {
if o.Headers == nil {
o.Headers = http.Header{}
}
o.Headers.Set("Authorization", "Bearer "+token)
}
}
func WithHeaders(headers http.Header) OptionFunc {
return func(o *Options) {
o.Headers = headers
}
}

View File

@ -12,6 +12,7 @@ import (
type QueryAgentsOptionFunc func(*QueryAgentsOptions) type QueryAgentsOptionFunc func(*QueryAgentsOptions)
type QueryAgentsOptions struct { type QueryAgentsOptions struct {
Options []OptionFunc
Limit *int Limit *int
Offset *int Offset *int
Thumbprints []string Thumbprints []string
@ -19,6 +20,12 @@ type QueryAgentsOptions struct {
Statuses []datastore.AgentStatus Statuses []datastore.AgentStatus
} }
func WithQueryAgentsOptions(funcs ...OptionFunc) QueryAgentsOptionFunc {
return func(opts *QueryAgentsOptions) {
opts.Options = funcs
}
}
func WithQueryAgentsLimit(limit int) QueryAgentsOptionFunc { func WithQueryAgentsLimit(limit int) QueryAgentsOptionFunc {
return func(opts *QueryAgentsOptions) { return func(opts *QueryAgentsOptions) {
opts.Limit = &limit opts.Limit = &limit
@ -76,7 +83,11 @@ func (c *Client) QueryAgents(ctx context.Context, funcs ...QueryAgentsOptionFunc
Total int `json:"total"` Total int `json:"total"`
}]() }]()
if err := c.apiGet(ctx, path, &response); err != nil { if options.Options == nil {
options.Options = make([]OptionFunc, 0)
}
if err := c.apiGet(ctx, path, &response, options.Options...); err != nil {
return nil, 0, errors.WithStack(err) return nil, 0, errors.WithStack(err)
} }

View File

@ -9,7 +9,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func (c *Client) RegisterAgent(ctx context.Context, key jwk.Key, thumbprint string, meta []metadata.Tuple) (*datastore.Agent, error) { func (c *Client) RegisterAgent(ctx context.Context, key jwk.Key, thumbprint string, meta []metadata.Tuple, funcs ...OptionFunc) (*datastore.Agent, error) {
keySet, err := jwk.PublicKeySet(key) keySet, err := jwk.PublicKeySet(key)
if err != nil { if err != nil {
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
@ -36,7 +36,7 @@ func (c *Client) RegisterAgent(ctx context.Context, key jwk.Key, thumbprint stri
Agent *datastore.Agent `json:"agent"` Agent *datastore.Agent `json:"agent"`
}]() }]()
if err := c.apiPost(ctx, "/api/v1/register", payload, &response); err != nil { if err := c.apiPost(ctx, "/api/v1/register", payload, &response, funcs...); err != nil {
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
} }

View File

@ -9,7 +9,8 @@ import (
) )
type UpdateAgentOptions struct { type UpdateAgentOptions struct {
Status *int Status *int
Options []OptionFunc
} }
type UpdateAgentOptionFunc func(*UpdateAgentOptions) type UpdateAgentOptionFunc func(*UpdateAgentOptions)
@ -20,6 +21,12 @@ func WithAgentStatus(status int) UpdateAgentOptionFunc {
} }
} }
func WithUpdateAgentsOptions(funcs ...OptionFunc) UpdateAgentOptionFunc {
return func(opts *UpdateAgentOptions) {
opts.Options = funcs
}
}
func (c *Client) UpdateAgent(ctx context.Context, agentID datastore.AgentID, funcs ...UpdateAgentOptionFunc) (*datastore.Agent, error) { func (c *Client) UpdateAgent(ctx context.Context, agentID datastore.AgentID, funcs ...UpdateAgentOptionFunc) (*datastore.Agent, error) {
opts := &UpdateAgentOptions{} opts := &UpdateAgentOptions{}
for _, fn := range funcs { for _, fn := range funcs {
@ -38,7 +45,11 @@ func (c *Client) UpdateAgent(ctx context.Context, agentID datastore.AgentID, fun
path := fmt.Sprintf("/api/v1/agents/%d", agentID) path := fmt.Sprintf("/api/v1/agents/%d", agentID)
if err := c.apiPut(ctx, path, payload, &response); err != nil { if opts.Options == nil {
opts.Options = make([]OptionFunc, 0)
}
if err := c.apiPut(ctx, path, payload, &response, opts.Options...); err != nil {
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
} }

View File

@ -10,7 +10,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func (c *Client) UpdateAgentSpec(ctx context.Context, agentID datastore.AgentID, spc spec.Spec) (*datastore.Spec, error) { func (c *Client) UpdateAgentSpec(ctx context.Context, agentID datastore.AgentID, spc spec.Spec, funcs ...OptionFunc) (*datastore.Spec, error) {
payload := struct { payload := struct {
Name spec.Name `json:"name"` Name spec.Name `json:"name"`
Revision int `json:"revision"` Revision int `json:"revision"`
@ -27,7 +27,7 @@ func (c *Client) UpdateAgentSpec(ctx context.Context, agentID datastore.AgentID,
path := fmt.Sprintf("/api/v1/agents/%d/specs", agentID) path := fmt.Sprintf("/api/v1/agents/%d/specs", agentID)
if err := c.apiPost(ctx, path, payload, &response); err != nil { if err := c.apiPost(ctx, path, payload, &response, funcs...); err != nil {
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
} }

View File

@ -2,6 +2,7 @@ package agent
import ( import (
"forge.cadoles.com/Cadoles/emissary/internal/command/agent/openwrt" "forge.cadoles.com/Cadoles/emissary/internal/command/agent/openwrt"
"forge.cadoles.com/Cadoles/emissary/internal/command/config"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -11,6 +12,7 @@ func Root() *cli.Command {
Usage: "Agent related commands", Usage: "Agent related commands",
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
openwrt.Root(), openwrt.Root(),
config.Root(),
RunCommand(), RunCommand(),
}, },
} }

View File

@ -4,6 +4,7 @@ import (
"time" "time"
"forge.cadoles.com/Cadoles/emissary/internal/agent" "forge.cadoles.com/Cadoles/emissary/internal/agent"
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app"
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/gateway" "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/gateway"
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/openwrt" "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/openwrt"
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/persistence" "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/persistence"
@ -16,7 +17,6 @@ import (
"forge.cadoles.com/Cadoles/emissary/internal/jwk" "forge.cadoles.com/Cadoles/emissary/internal/jwk"
"forge.cadoles.com/Cadoles/emissary/internal/machineid" "forge.cadoles.com/Cadoles/emissary/internal/machineid"
"github.com/pkg/errors" "github.com/pkg/errors"
_ "github.com/santhosh-tekuri/jsonschema/v5/httploader"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"gitlab.com/wpetit/goweb/logger" "gitlab.com/wpetit/goweb/logger"
) )
@ -59,6 +59,13 @@ func RunCommand() *cli.Command {
)) ))
} }
if ctrlConf.App.Enabled {
controllers = append(controllers, app.NewController(
app.WithDataDir(string(ctrlConf.App.DataDir)),
app.WithDownloadDir(string(ctrlConf.App.DownloadDir)),
))
}
key, err := jwk.LoadOrGenerate(string(conf.Agent.PrivateKeyPath), jwk.DefaultKeySize) key, err := jwk.LoadOrGenerate(string(conf.Agent.PrivateKeyPath), jwk.DefaultKeySize)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)

View File

@ -18,7 +18,13 @@ func CountCommand() *cli.Command {
Flags: clientFlag.ComposeFlags(), Flags: clientFlag.ComposeFlags(),
Action: func(ctx *cli.Context) error { Action: func(ctx *cli.Context) error {
baseFlags := clientFlag.GetBaseFlags(ctx) baseFlags := clientFlag.GetBaseFlags(ctx)
client := client.New(baseFlags.ServerURL)
token, err := clientFlag.GetToken(baseFlags)
if err != nil {
return errors.WithStack(apierr.Wrap(err))
}
client := client.New(baseFlags.ServerURL, client.WithToken(token))
_, total, err := client.QueryAgents(ctx.Context) _, total, err := client.QueryAgents(ctx.Context)
if err != nil { if err != nil {

View File

@ -20,12 +20,17 @@ func GetCommand() *cli.Command {
Action: func(ctx *cli.Context) error { Action: func(ctx *cli.Context) error {
baseFlags := clientFlag.GetBaseFlags(ctx) baseFlags := clientFlag.GetBaseFlags(ctx)
token, err := clientFlag.GetToken(baseFlags)
if err != nil {
return errors.WithStack(apierr.Wrap(err))
}
agentID, err := agentFlag.AssertAgentID(ctx) agentID, err := agentFlag.AssertAgentID(ctx)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
client := client.New(baseFlags.ServerURL) client := client.New(baseFlags.ServerURL, client.WithToken(token))
agent, err := client.GetAgent(ctx.Context, agentID) agent, err := client.GetAgent(ctx.Context, agentID)
if err != nil { if err != nil {

View File

@ -18,7 +18,13 @@ func QueryCommand() *cli.Command {
Flags: clientFlag.ComposeFlags(), Flags: clientFlag.ComposeFlags(),
Action: func(ctx *cli.Context) error { Action: func(ctx *cli.Context) error {
baseFlags := clientFlag.GetBaseFlags(ctx) baseFlags := clientFlag.GetBaseFlags(ctx)
client := client.New(baseFlags.ServerURL)
token, err := clientFlag.GetToken(baseFlags)
if err != nil {
return errors.WithStack(apierr.Wrap(err))
}
client := client.New(baseFlags.ServerURL, client.WithToken(token))
agents, _, err := client.QueryAgents(ctx.Context) agents, _, err := client.QueryAgents(ctx.Context)
if err != nil { if err != nil {

View File

@ -24,7 +24,12 @@ func GetCommand() *cli.Command {
return errors.WithStack(err) return errors.WithStack(err)
} }
client := client.New(baseFlags.ServerURL) token, err := clientFlag.GetToken(baseFlags)
if err != nil {
return errors.WithStack(apierr.Wrap(err))
}
client := client.New(baseFlags.ServerURL, client.WithToken(token))
specs, err := client.GetAgentSpecs(ctx.Context, agentID) specs, err := client.GetAgentSpecs(ctx.Context, agentID)
if err != nil { if err != nil {

View File

@ -13,6 +13,11 @@ import (
jsonpatch "github.com/evanphx/json-patch/v5" jsonpatch "github.com/evanphx/json-patch/v5"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
// Import specs
_ "forge.cadoles.com/Cadoles/emissary/internal/spec/app"
_ "forge.cadoles.com/Cadoles/emissary/internal/spec/gateway"
_ "forge.cadoles.com/Cadoles/emissary/internal/spec/uci"
) )
func UpdateCommand() *cli.Command { func UpdateCommand() *cli.Command {
@ -56,7 +61,12 @@ func UpdateCommand() *cli.Command {
noPatch := ctx.Bool("no-patch") noPatch := ctx.Bool("no-patch")
client := client.New(baseFlags.ServerURL) token, err := clientFlag.GetToken(baseFlags)
if err != nil {
return errors.WithStack(apierr.Wrap(err))
}
client := client.New(baseFlags.ServerURL, client.WithToken(token))
specs, err := client.GetAgentSpecs(ctx.Context, agentID) specs, err := client.GetAgentSpecs(ctx.Context, agentID)
if err != nil { if err != nil {

View File

@ -26,6 +26,11 @@ func UpdateCommand() *cli.Command {
Action: func(ctx *cli.Context) error { Action: func(ctx *cli.Context) error {
baseFlags := clientFlag.GetBaseFlags(ctx) baseFlags := clientFlag.GetBaseFlags(ctx)
token, err := clientFlag.GetToken(baseFlags)
if err != nil {
return errors.WithStack(apierr.Wrap(err))
}
agentID, err := agentFlag.AssertAgentID(ctx) agentID, err := agentFlag.AssertAgentID(ctx)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
@ -38,7 +43,7 @@ func UpdateCommand() *cli.Command {
options = append(options, client.WithAgentStatus(status)) options = append(options, client.WithAgentStatus(status))
} }
client := client.New(baseFlags.ServerURL) client := client.New(baseFlags.ServerURL, client.WithToken(token))
agent, err := client.UpdateAgent(ctx.Context, agentID, options...) agent, err := client.UpdateAgent(ctx.Context, agentID, options...)
if err != nil { if err != nil {

View File

@ -2,9 +2,13 @@ package flag
import ( import (
"fmt" "fmt"
"io/ioutil"
"os"
"strings"
"forge.cadoles.com/Cadoles/emissary/internal/format" "forge.cadoles.com/Cadoles/emissary/internal/format"
"forge.cadoles.com/Cadoles/emissary/internal/format/table" "forge.cadoles.com/Cadoles/emissary/internal/format/table"
"github.com/pkg/errors"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -28,6 +32,17 @@ func ComposeFlags(flags ...cli.Flag) []cli.Flag {
Usage: fmt.Sprintf("use `MODE` as output mode (available: %s)", []format.OutputMode{format.OutputModeCompact, format.OutputModeWide}), Usage: fmt.Sprintf("use `MODE` as output mode (available: %s)", []format.OutputMode{format.OutputModeCompact, format.OutputModeWide}),
Value: string(format.OutputModeCompact), Value: string(format.OutputModeCompact),
}, },
&cli.StringFlag{
Name: "token",
Aliases: []string{"t"},
Usage: "use `TOKEN` as authentification token",
},
&cli.StringFlag{
Name: "token-file",
Usage: "use `TOKEN_FILE` as file containing the authentification token",
Value: ".emissary-token",
TakesFile: true,
},
} }
flags = append(flags, baseFlags...) flags = append(flags, baseFlags...)
@ -39,16 +54,43 @@ type BaseFlags struct {
ServerURL string ServerURL string
Format format.Format Format format.Format
OutputMode format.OutputMode OutputMode format.OutputMode
Token string
TokenFile string
} }
func GetBaseFlags(ctx *cli.Context) *BaseFlags { func GetBaseFlags(ctx *cli.Context) *BaseFlags {
serverURL := ctx.String("server") serverURL := ctx.String("server")
rawFormat := ctx.String("format") rawFormat := ctx.String("format")
rawOutputMode := ctx.String("output-mode") rawOutputMode := ctx.String("output-mode")
tokenFile := ctx.String("token-file")
token := ctx.String("token")
return &BaseFlags{ return &BaseFlags{
ServerURL: serverURL, ServerURL: serverURL,
Format: format.Format(rawFormat), Format: format.Format(rawFormat),
OutputMode: format.OutputMode(rawOutputMode), OutputMode: format.OutputMode(rawOutputMode),
Token: token,
TokenFile: tokenFile,
} }
} }
func GetToken(flags *BaseFlags) (string, error) {
if flags.Token != "" {
return flags.Token, nil
}
if flags.TokenFile == "" {
return "", nil
}
rawToken, err := ioutil.ReadFile(flags.TokenFile)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return "", errors.WithStack(err)
}
if rawToken == nil {
return "", nil
}
return strings.TrimSpace(string(rawToken)), nil
}

View File

@ -0,0 +1,54 @@
package auth
import (
"fmt"
"forge.cadoles.com/Cadoles/emissary/internal/auth/user"
"forge.cadoles.com/Cadoles/emissary/internal/command/common"
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
"github.com/lithammer/shortuuid/v4"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
)
func CreateTokenCommand() *cli.Command {
return &cli.Command{
Name: "create-token",
Usage: "Create a new authentification token",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "role",
Usage: fmt.Sprintf("associate `ROLE` to the token (available: %v)", []user.Role{user.RoleReader, user.RoleWriter}),
Value: string(user.RoleReader),
},
&cli.StringFlag{
Name: "subject",
Usage: "associate `SUBJECT` to the token",
Value: fmt.Sprintf("user-%s", shortuuid.New()),
},
},
Action: func(ctx *cli.Context) error {
conf, err := common.LoadConfig(ctx)
if err != nil {
return errors.Wrap(err, "Could not load configuration")
}
subject := ctx.String("subject")
role := ctx.String("role")
key, err := jwk.LoadOrGenerate(string(conf.Server.PrivateKeyPath), jwk.DefaultKeySize)
if err != nil {
return errors.WithStack(err)
}
token, err := user.GenerateToken(ctx.Context, key, string(conf.Server.Issuer), subject, user.Role(role))
if err != nil {
return errors.WithStack(err)
}
fmt.Println(token)
return nil
},
}
}

View File

@ -0,0 +1,15 @@
package auth
import (
"github.com/urfave/cli/v2"
)
func Root() *cli.Command {
return &cli.Command{
Name: "auth",
Usage: "Authentication related commands",
Subcommands: []*cli.Command{
CreateTokenCommand(),
},
}
}

View File

@ -36,8 +36,8 @@ func MigrateCommand() *cli.Command {
return errors.Wrap(err, "Could not load configuration") return errors.Wrap(err, "Could not load configuration")
} }
driver := string(conf.Database.Driver) driver := string(conf.Server.Database.Driver)
dsn := string(conf.Database.DSN) dsn := string(conf.Server.Database.DSN)
migr, err := migrate.New("migrations", driver, dsn) migr, err := migrate.New("migrations", driver, dsn)
if err != nil { if err != nil {

View File

@ -20,10 +20,10 @@ func PingCommand() *cli.Command {
return errors.Wrap(err, "Could not load configuration") return errors.Wrap(err, "Could not load configuration")
} }
logger.Info(ctx.Context, "connecting to database", logger.F("dsn", conf.Database.DSN)) logger.Info(ctx.Context, "connecting to database", logger.F("dsn", conf.Server.Database.DSN))
driver := string(conf.Database.Driver) driver := string(conf.Server.Database.Driver)
dsn := string(conf.Database.DSN) dsn := string(conf.Server.Database.DSN)
db, err := sql.Open(driver, dsn) db, err := sql.Open(driver, dsn)
if err != nil { if err != nil {
@ -40,7 +40,7 @@ func PingCommand() *cli.Command {
return errors.WithStack(err) return errors.WithStack(err)
} }
logger.Info(ctx.Context, "connection succeeded", logger.F("dsn", conf.Database.DSN)) logger.Info(ctx.Context, "connection succeeded", logger.F("dsn", conf.Server.Database.DSN))
return nil return nil
}, },

View File

@ -18,8 +18,8 @@ func ResetCommand() *cli.Command {
return errors.Wrap(err, "Could not load configuration") return errors.Wrap(err, "Could not load configuration")
} }
driver := string(conf.Database.Driver) driver := string(conf.Server.Database.Driver)
dsn := string(conf.Database.DSN) dsn := string(conf.Server.Database.DSN)
migr, err := migrate.New("migrations", driver, dsn) migr, err := migrate.New("migrations", driver, dsn)
if err != nil { if err != nil {

View File

@ -2,6 +2,7 @@ package server
import ( import (
"forge.cadoles.com/Cadoles/emissary/internal/command/config" "forge.cadoles.com/Cadoles/emissary/internal/command/config"
"forge.cadoles.com/Cadoles/emissary/internal/command/server/auth"
"forge.cadoles.com/Cadoles/emissary/internal/command/server/database" "forge.cadoles.com/Cadoles/emissary/internal/command/server/database"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -14,6 +15,7 @@ func Root() *cli.Command {
RunCommand(), RunCommand(),
database.Root(), database.Root(),
config.Root(), config.Root(),
auth.Root(),
}, },
} }
} }

View File

@ -29,7 +29,7 @@ func RunCommand() *cli.Command {
logger.SetLevel(logger.Level(conf.Logger.Level)) logger.SetLevel(logger.Level(conf.Logger.Level))
srv := server.New( srv := server.New(
server.WithConfig(conf), server.WithConfig(conf.Server),
) )
addrs, srvErrs := srv.Start(ctx.Context) addrs, srvErrs := srv.Start(ctx.Context)

View File

@ -19,6 +19,7 @@ type ControllersConfig struct {
Spec SpecControllerConfig `yaml:"spec"` Spec SpecControllerConfig `yaml:"spec"`
Gateway GatewayControllerConfig `yaml:"gateway"` Gateway GatewayControllerConfig `yaml:"gateway"`
UCI UCIControllerConfig `yaml:"uci"` UCI UCIControllerConfig `yaml:"uci"`
App AppControllerConfig `yaml:"app"`
} }
type PersistenceControllerConfig struct { type PersistenceControllerConfig struct {
@ -39,6 +40,12 @@ type UCIControllerConfig struct {
ConfigBackupFile InterpolatedString `yaml:"configBackupFile"` ConfigBackupFile InterpolatedString `yaml:"configBackupFile"`
} }
type AppControllerConfig struct {
Enabled InterpolatedBool `yaml:"enabled"`
DataDir InterpolatedString `yaml:"dataDir"`
DownloadDir InterpolatedString `yaml:"downloadDir"`
}
func NewDefaultAgentConfig() AgentConfig { func NewDefaultAgentConfig() AgentConfig {
return AgentConfig{ return AgentConfig{
ServerURL: "http://127.0.0.1:3000", ServerURL: "http://127.0.0.1:3000",
@ -60,6 +67,11 @@ func NewDefaultAgentConfig() AgentConfig {
ConfigBackupFile: "uci-backup.conf", ConfigBackupFile: "uci-backup.conf",
BinPath: "uci", BinPath: "uci",
}, },
App: AppControllerConfig{
Enabled: true,
DataDir: "apps/data",
DownloadDir: "apps/bundles",
},
}, },
Collectors: []ShellCollectorConfig{ Collectors: []ShellCollectorConfig{
{ {

View File

@ -10,11 +10,9 @@ import (
// Config definition // Config definition
type Config struct { type Config struct {
HTTP HTTPConfig `yaml:"http"` Logger LoggerConfig `yaml:"logger"`
Logger LoggerConfig `yaml:"logger"` Server ServerConfig `yaml:"server"`
Database DatabaseConfig `yaml:"database"` Agent AgentConfig `yaml:"agent"`
CORS CORSConfig `yaml:"cors"`
Agent AgentConfig `yaml:"agent"`
} }
// NewFromFile retrieves the configuration from the given file // NewFromFile retrieves the configuration from the given file
@ -43,11 +41,9 @@ func NewDumpDefault() *Config {
// NewDefault return new default configuration // NewDefault return new default configuration
func NewDefault() *Config { func NewDefault() *Config {
return &Config{ return &Config{
HTTP: NewDefaultHTTPConfig(), Logger: NewDefaultLoggerConfig(),
Logger: NewDefaultLoggerConfig(), Agent: NewDefaultAgentConfig(),
Database: NewDefaultDatabaseConfig(), Server: NewDefaultServerConfig(),
CORS: NewDefaultCORSConfig(),
Agent: NewDefaultAgentConfig(),
} }
} }

19
internal/config/server.go Normal file
View File

@ -0,0 +1,19 @@
package config
type ServerConfig struct {
PrivateKeyPath InterpolatedString `yaml:"privateKeyPath"`
Issuer InterpolatedString `yaml:"issuer"`
HTTP HTTPConfig `yaml:"http"`
Database DatabaseConfig `yaml:"database"`
CORS CORSConfig `yaml:"cors"`
}
func NewDefaultServerConfig() ServerConfig {
return ServerConfig{
PrivateKeyPath: "server-key.json",
Issuer: "http://127.0.0.1:3000",
HTTP: NewDefaultHTTPConfig(),
Database: NewDefaultDatabaseConfig(),
CORS: NewDefaultCORSConfig(),
}
}

View File

@ -8,7 +8,7 @@ import (
) )
func (s *Server) initRepositories(ctx context.Context) error { func (s *Server) initRepositories(ctx context.Context) error {
agentRepo, err := setup.NewAgentRepository(ctx, s.conf) agentRepo, err := setup.NewAgentRepository(ctx, s.conf.Database)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }

View File

@ -1,20 +1,22 @@
package server package server
import "forge.cadoles.com/Cadoles/emissary/internal/config" import (
"forge.cadoles.com/Cadoles/emissary/internal/config"
)
type Option struct { type Option struct {
Config *config.Config Config config.ServerConfig
} }
type OptionFunc func(*Option) type OptionFunc func(*Option)
func defaultOption() *Option { func defaultOption() *Option {
return &Option{ return &Option{
Config: config.NewDefault(), Config: config.NewDefaultServerConfig(),
} }
} }
func WithConfig(conf *config.Config) OptionFunc { func WithConfig(conf config.ServerConfig) OptionFunc {
return func(opt *Option) { return func(opt *Option) {
opt.Config = conf opt.Config = conf
} }

View File

@ -7,8 +7,12 @@ import (
"net" "net"
"net/http" "net/http"
"forge.cadoles.com/Cadoles/emissary/internal/auth"
"forge.cadoles.com/Cadoles/emissary/internal/auth/agent"
"forge.cadoles.com/Cadoles/emissary/internal/auth/user"
"forge.cadoles.com/Cadoles/emissary/internal/config" "forge.cadoles.com/Cadoles/emissary/internal/config"
"forge.cadoles.com/Cadoles/emissary/internal/datastore" "forge.cadoles.com/Cadoles/emissary/internal/datastore"
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
"github.com/go-chi/chi" "github.com/go-chi/chi"
"github.com/go-chi/chi/middleware" "github.com/go-chi/chi/middleware"
"github.com/go-chi/cors" "github.com/go-chi/cors"
@ -17,7 +21,7 @@ import (
) )
type Server struct { type Server struct {
conf *config.Config conf config.ServerConfig
agentRepo datastore.AgentRepository agentRepo datastore.AgentRepository
} }
@ -68,6 +72,20 @@ func (s *Server) run(parentCtx context.Context, addrs chan net.Addr, errs chan e
} }
}() }()
key, err := jwk.LoadOrGenerate(string(s.conf.PrivateKeyPath), jwk.DefaultKeySize)
if err != nil {
errs <- errors.WithStack(err)
return
}
keys, err := jwk.PublicKeySet(key)
if err != nil {
errs <- errors.WithStack(err)
return
}
router := chi.NewRouter() router := chi.NewRouter()
router.Use(middleware.Logger) router.Use(middleware.Logger)
@ -85,15 +103,22 @@ func (s *Server) run(parentCtx context.Context, addrs chan net.Addr, errs chan e
router.Route("/api/v1", func(r chi.Router) { router.Route("/api/v1", func(r chi.Router) {
r.Post("/register", s.registerAgent) r.Post("/register", s.registerAgent)
r.Route("/agents", func(r chi.Router) { r.Group(func(r chi.Router) {
r.Get("/", s.queryAgents) r.Use(auth.Middleware(
r.Get("/{agentID}", s.getAgent) user.NewAuthenticator(keys, string(s.conf.Issuer)),
r.Put("/{agentID}", s.updateAgent) agent.NewAuthenticator(s.agentRepo),
r.Delete("/{agentID}", s.deleteAgent) ))
r.Get("/{agentID}/specs", s.getAgentSpecs) r.Route("/agents", func(r chi.Router) {
r.Post("/{agentID}/specs", s.updateSpec) r.Get("/", s.queryAgents)
r.Delete("/{agentID}/specs", s.deleteSpec) r.Get("/{agentID}", s.getAgent)
r.Put("/{agentID}", s.updateAgent)
r.Delete("/{agentID}", s.deleteAgent)
r.Get("/{agentID}/specs", s.getAgentSpecs)
r.Post("/{agentID}/specs", s.updateSpec)
r.Delete("/{agentID}/specs", s.deleteSpec)
})
}) })
}) })

View File

@ -10,6 +10,11 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"gitlab.com/wpetit/goweb/api" "gitlab.com/wpetit/goweb/api"
"gitlab.com/wpetit/goweb/logger" "gitlab.com/wpetit/goweb/logger"
// Import specs
_ "forge.cadoles.com/Cadoles/emissary/internal/spec/app"
_ "forge.cadoles.com/Cadoles/emissary/internal/spec/gateway"
_ "forge.cadoles.com/Cadoles/emissary/internal/spec/uci"
) )
const ( const (

View File

@ -31,9 +31,9 @@ func openPostgresPool(ctx context.Context, dsn string) (*pgxpool.Pool, error) {
return postgresPool, nil return postgresPool, nil
} }
func NewAgentRepository(ctx context.Context, conf *config.Config) (datastore.AgentRepository, error) { func NewAgentRepository(ctx context.Context, conf config.DatabaseConfig) (datastore.AgentRepository, error) {
driver := string(conf.Database.Driver) driver := string(conf.Driver)
dsn := string(conf.Database.DSN) dsn := string(conf.DSN)
var agentRepository datastore.AgentRepository var agentRepository datastore.AgentRepository

17
internal/spec/app/init.go Normal file
View File

@ -0,0 +1,17 @@
package app
import (
_ "embed"
"forge.cadoles.com/Cadoles/emissary/internal/spec"
"github.com/pkg/errors"
)
//go:embed schema.json
var schema []byte
func init() {
if err := spec.Register(NameApp, schema); err != nil {
panic(errors.WithStack(err))
}
}

View File

@ -0,0 +1,36 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://app.emissary.cadoles.com/spec.json",
"title": "AppSpec",
"description": "Emissary 'App' specification",
"type": "object",
"properties": {
"apps": {
"type": "object",
"patternProperties": {
".*": {
"type": "object",
"properties": {
"url": {
"type": "string"
},
"sha256sum": {
"type": "string"
},
"address": {
"type": "string"
},
"format": {
"type": "string",
"enum": ["zip", "tar.gz"]
}
},
"required": ["url", "sha256sum", "address", "format"],
"additionalProperties": false
}
}
}
},
"required": ["apps"],
"additionalProperties": false
}

39
internal/spec/app/spec.go Normal file
View File

@ -0,0 +1,39 @@
package app
import (
"forge.cadoles.com/Cadoles/emissary/internal/spec"
)
const NameApp spec.Name = "app.emissary.cadoles.com"
type Spec struct {
Revision int `json:"revisions"`
Apps map[string]AppEntry
}
type AppEntry struct {
URL string `json:"url"`
SHA256Sum string `json:"sha256sum"`
Address string `json:"address"`
Format string `json:"format"`
}
func (s *Spec) SpecName() spec.Name {
return NameApp
}
func (s *Spec) SpecRevision() int {
return s.Revision
}
func (s *Spec) SpecData() map[string]any {
return map[string]any{
"apps": s.Apps,
}
}
func NewSpec() *Spec {
return &Spec{}
}
var _ spec.Spec = &Spec{}

View File

@ -0,0 +1,7 @@
{
"name": "app.emissary.cadoles.com",
"data": {
"apps": {}
},
"revision": 0
}

View File

@ -0,0 +1,65 @@
package app
import (
"context"
"encoding/json"
"io/ioutil"
"testing"
"forge.cadoles.com/Cadoles/emissary/internal/spec"
"github.com/pkg/errors"
)
type validatorTestCase struct {
Name string
Source string
ShouldFail bool
}
var validatorTestCases = []validatorTestCase{
{
Name: "SpecOK",
Source: "testdata/spec-ok.json",
ShouldFail: false,
},
}
func TestValidator(t *testing.T) {
t.Parallel()
validator := spec.NewValidator()
if err := validator.Register(NameApp, schema); err != nil {
t.Fatalf("+%v", errors.WithStack(err))
}
for _, tc := range validatorTestCases {
func(tc validatorTestCase) {
t.Run(tc.Name, func(t *testing.T) {
t.Parallel()
rawSpec, err := ioutil.ReadFile(tc.Source)
if err != nil {
t.Fatalf("+%v", errors.WithStack(err))
}
var spec spec.RawSpec
if err := json.Unmarshal(rawSpec, &spec); err != nil {
t.Fatalf("+%v", errors.WithStack(err))
}
ctx := context.Background()
err = validator.Validate(ctx, &spec)
if !tc.ShouldFail && err != nil {
t.Errorf("+%v", errors.WithStack(err))
}
if tc.ShouldFail && err == nil {
t.Error("validation should have failed")
}
})
}(tc)
}
}

View File

@ -24,10 +24,10 @@ func (s *Spec) SpecRevision() int {
return s.Revision return s.Revision
} }
func (s *Spec) SpecData() any { func (s *Spec) SpecData() map[string]any {
return struct { return map[string]any{
Gateways map[ID]GatewayEntry "gateways": s.Gateways,
}{Gateways: s.Gateways} }
} }
func NewSpec() *Spec { func NewSpec() *Spec {
@ -35,3 +35,5 @@ func NewSpec() *Spec {
Gateways: make(map[ID]GatewayEntry), Gateways: make(map[ID]GatewayEntry),
} }
} }
var _ spec.Spec = &Spec{}

View File

@ -1,17 +1,15 @@
package spec package spec
import "forge.cadoles.com/Cadoles/emissary/internal/agent/metadata"
type Spec interface { type Spec interface {
SpecName() Name SpecName() Name
SpecRevision() int SpecRevision() int
SpecData() metadata.Metadata SpecData() map[string]any
} }
type RawSpec struct { type RawSpec struct {
Name Name `json:"name"` Name Name `json:"name"`
Revision int `json:"revision"` Revision int `json:"revision"`
Data metadata.Metadata `json:"data"` Data map[string]any `json:"data"`
} }
func (s *RawSpec) SpecName() Name { func (s *RawSpec) SpecName() Name {
@ -22,6 +20,8 @@ func (s *RawSpec) SpecRevision() int {
return s.Revision return s.Revision
} }
func (s *RawSpec) SpecData() metadata.Metadata { func (s *RawSpec) SpecData() map[string]any {
return s.Data return s.Data
} }
var _ Spec = &RawSpec{}

View File

@ -67,13 +67,18 @@
"type": "string" "type": "string"
}, },
"options": { "options": {
"type": "array", "anyOf": [
"items": { {
"$ref": "#/$defs/option" "type": "array",
} "items": {
"$ref": "#/$defs/option"
}
},
{ "type": "null" }
]
} }
}, },
"required": ["name", "section", "options"], "required": ["name"],
"additionalProperties": false "additionalProperties": false
}, },
"option": { "option": {

View File

@ -26,11 +26,11 @@ func (s *Spec) SpecRevision() int {
return s.Revision return s.Revision
} }
func (s *Spec) SpecData() any { func (s *Spec) SpecData() map[string]any {
return struct { return map[string]any{
Config *uci.UCI `json:"config"` "config": s.Config,
PostImportCommands []*UCIPostImportCommand `json:"postImportCommands"` "postImportCommands": s.PostImportCommands,
}{Config: s.Config, PostImportCommands: s.PostImportCommands} }
} }
func NewSpec() *Spec { func NewSpec() *Spec {
@ -38,3 +38,5 @@ func NewSpec() *Spec {
PostImportCommands: make([]*UCIPostImportCommand, 0), PostImportCommands: make([]*UCIPostImportCommand, 0),
} }
} }
var _ spec.Spec = &Spec{}

View File

@ -3,6 +3,1475 @@
"data": { "data": {
"config": { "config": {
"packages": [ "packages": [
{
"name": "dhcp",
"configs": [
{
"name": "dnsmasq",
"options": [
{
"type": "option",
"name": "domainneeded",
"value": "1"
},
{
"type": "option",
"name": "boguspriv",
"value": "1"
},
{
"type": "option",
"name": "filterwin2k",
"value": "0"
},
{
"type": "option",
"name": "localise_queries",
"value": "1"
},
{
"type": "option",
"name": "rebind_protection",
"value": "1"
},
{
"type": "option",
"name": "rebind_localhost",
"value": "1"
},
{
"type": "option",
"name": "local",
"value": "/lan/"
},
{
"type": "option",
"name": "domain",
"value": "lan"
},
{
"type": "option",
"name": "expandhosts",
"value": "1"
},
{
"type": "option",
"name": "nonegcache",
"value": "0"
},
{
"type": "option",
"name": "authoritative",
"value": "1"
},
{
"type": "option",
"name": "readethers",
"value": "1"
},
{
"type": "option",
"name": "leasefile",
"value": "/tmp/dhcp.leases"
},
{
"type": "option",
"name": "resolvfile",
"value": "/tmp/resolv.conf.d/resolv.conf.auto"
},
{
"type": "option",
"name": "nonwildcard",
"value": "1"
},
{
"type": "option",
"name": "localservice",
"value": "1"
},
{
"type": "option",
"name": "ednspacket_max",
"value": "1232"
}
]
},
{
"name": "dhcp",
"section": "lan",
"options": [
{
"type": "option",
"name": "interface",
"value": "lan"
},
{
"type": "option",
"name": "start",
"value": "100"
},
{
"type": "option",
"name": "limit",
"value": "150"
},
{
"type": "option",
"name": "leasetime",
"value": "12h"
},
{
"type": "option",
"name": "dhcpv4",
"value": "server"
},
{
"type": "option",
"name": "dhcpv6",
"value": "server"
},
{
"type": "option",
"name": "ra",
"value": "server"
},
{
"type": "option",
"name": "ra_slaac",
"value": "1"
},
{
"type": "list",
"name": "ra_flags",
"value": "managed-config"
},
{
"type": "list",
"name": "ra_flags",
"value": "other-config"
}
]
},
{
"name": "dhcp",
"section": "wan",
"options": [
{
"type": "option",
"name": "interface",
"value": "wan"
},
{
"type": "option",
"name": "ignore",
"value": "1"
}
]
},
{
"name": "odhcpd",
"section": "odhcpd",
"options": [
{
"type": "option",
"name": "maindhcp",
"value": "0"
},
{
"type": "option",
"name": "leasefile",
"value": "/tmp/hosts/odhcpd"
},
{
"type": "option",
"name": "leasetrigger",
"value": "/usr/sbin/odhcpd-update"
},
{
"type": "option",
"name": "loglevel",
"value": "4"
}
]
}
]
},
{
"name": "dropbear",
"configs": [
{
"name": "dropbear",
"options": [
{
"type": "option",
"name": "PasswordAuth",
"value": "on"
},
{
"type": "option",
"name": "RootPasswordAuth",
"value": "on"
},
{
"type": "option",
"name": "Port",
"value": "22"
}
]
}
]
},
{
"name": "emissary",
"configs": [
{
"name": "main",
"section": "agent",
"options": [
{
"type": "option",
"name": "server_url",
"value": "http://192.168.30.15:3000"
},
{
"type": "option",
"name": "reconciliation_interval",
"value": "30"
}
]
}
]
},
{
"name": "firewall",
"configs": [
{
"name": "defaults",
"options": [
{
"type": "option",
"name": "syn_flood",
"value": "1"
},
{
"type": "option",
"name": "input",
"value": "ACCEPT"
},
{
"type": "option",
"name": "output",
"value": "ACCEPT"
},
{
"type": "option",
"name": "forward",
"value": "REJECT"
}
]
},
{
"name": "zone",
"options": [
{
"type": "option",
"name": "name",
"value": "lan"
},
{
"type": "list",
"name": "network",
"value": "lan"
},
{
"type": "option",
"name": "input",
"value": "ACCEPT"
},
{
"type": "option",
"name": "output",
"value": "ACCEPT"
},
{
"type": "option",
"name": "forward",
"value": "ACCEPT"
}
]
},
{
"name": "zone",
"options": [
{
"type": "option",
"name": "name",
"value": "wan"
},
{
"type": "list",
"name": "network",
"value": "wan"
},
{
"type": "list",
"name": "network",
"value": "wan6"
},
{
"type": "option",
"name": "input",
"value": "REJECT"
},
{
"type": "option",
"name": "output",
"value": "ACCEPT"
},
{
"type": "option",
"name": "forward",
"value": "REJECT"
},
{
"type": "option",
"name": "masq",
"value": "1"
},
{
"type": "option",
"name": "mtu_fix",
"value": "1"
}
]
},
{
"name": "forwarding",
"options": [
{
"type": "option",
"name": "src",
"value": "lan"
},
{
"type": "option",
"name": "dest",
"value": "wan"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow-DHCP-Renew"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "proto",
"value": "udp"
},
{
"type": "option",
"name": "dest_port",
"value": "68"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
},
{
"type": "option",
"name": "family",
"value": "ipv4"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow-Ping"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "proto",
"value": "icmp"
},
{
"type": "option",
"name": "icmp_type",
"value": "echo-request"
},
{
"type": "option",
"name": "family",
"value": "ipv4"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow-IGMP"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "proto",
"value": "igmp"
},
{
"type": "option",
"name": "family",
"value": "ipv4"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow-DHCPv6"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "proto",
"value": "udp"
},
{
"type": "option",
"name": "dest_port",
"value": "546"
},
{
"type": "option",
"name": "family",
"value": "ipv6"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow-MLD"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "proto",
"value": "icmp"
},
{
"type": "option",
"name": "src_ip",
"value": "fe80::/10"
},
{
"type": "list",
"name": "icmp_type",
"value": "130/0"
},
{
"type": "list",
"name": "icmp_type",
"value": "131/0"
},
{
"type": "list",
"name": "icmp_type",
"value": "132/0"
},
{
"type": "list",
"name": "icmp_type",
"value": "143/0"
},
{
"type": "option",
"name": "family",
"value": "ipv6"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow-ICMPv6-Input"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "proto",
"value": "icmp"
},
{
"type": "list",
"name": "icmp_type",
"value": "echo-request"
},
{
"type": "list",
"name": "icmp_type",
"value": "echo-reply"
},
{
"type": "list",
"name": "icmp_type",
"value": "destination-unreachable"
},
{
"type": "list",
"name": "icmp_type",
"value": "packet-too-big"
},
{
"type": "list",
"name": "icmp_type",
"value": "time-exceeded"
},
{
"type": "list",
"name": "icmp_type",
"value": "bad-header"
},
{
"type": "list",
"name": "icmp_type",
"value": "unknown-header-type"
},
{
"type": "list",
"name": "icmp_type",
"value": "router-solicitation"
},
{
"type": "list",
"name": "icmp_type",
"value": "neighbour-solicitation"
},
{
"type": "list",
"name": "icmp_type",
"value": "router-advertisement"
},
{
"type": "list",
"name": "icmp_type",
"value": "neighbour-advertisement"
},
{
"type": "option",
"name": "limit",
"value": "1000/sec"
},
{
"type": "option",
"name": "family",
"value": "ipv6"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow-ICMPv6-Forward"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "dest",
"value": "*"
},
{
"type": "option",
"name": "proto",
"value": "icmp"
},
{
"type": "list",
"name": "icmp_type",
"value": "echo-request"
},
{
"type": "list",
"name": "icmp_type",
"value": "echo-reply"
},
{
"type": "list",
"name": "icmp_type",
"value": "destination-unreachable"
},
{
"type": "list",
"name": "icmp_type",
"value": "packet-too-big"
},
{
"type": "list",
"name": "icmp_type",
"value": "time-exceeded"
},
{
"type": "list",
"name": "icmp_type",
"value": "bad-header"
},
{
"type": "list",
"name": "icmp_type",
"value": "unknown-header-type"
},
{
"type": "option",
"name": "limit",
"value": "1000/sec"
},
{
"type": "option",
"name": "family",
"value": "ipv6"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow-IPSec-ESP"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "dest",
"value": "lan"
},
{
"type": "option",
"name": "proto",
"value": "esp"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow-ISAKMP"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "dest",
"value": "lan"
},
{
"type": "option",
"name": "dest_port",
"value": "500"
},
{
"type": "option",
"name": "proto",
"value": "udp"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow SSH on WAN"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "proto",
"value": "tcp"
},
{
"type": "option",
"name": "dest_port",
"value": "22"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow HTTP on WAN"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "proto",
"value": "tcp"
},
{
"type": "option",
"name": "dest_port",
"value": "80"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow HTTPS on WAN"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "proto",
"value": "tcp"
},
{
"type": "option",
"name": "dest_port",
"value": "443"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow 8080 on WAN"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "proto",
"value": "tcp"
},
{
"type": "option",
"name": "dest_port",
"value": "8080"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
}
]
},
{
"name": "rule",
"options": [
{
"type": "option",
"name": "name",
"value": "Allow 8443 on WAN"
},
{
"type": "option",
"name": "src",
"value": "wan"
},
{
"type": "option",
"name": "proto",
"value": "tcp"
},
{
"type": "option",
"name": "dest_port",
"value": "8443"
},
{
"type": "option",
"name": "target",
"value": "ACCEPT"
}
]
}
]
},
{
"name": "luci",
"configs": [
{
"name": "core",
"section": "main",
"options": [
{
"type": "option",
"name": "lang",
"value": "auto"
},
{
"type": "option",
"name": "mediaurlbase",
"value": "/luci-static/bootstrap"
},
{
"type": "option",
"name": "resourcebase",
"value": "/luci-static/resources"
},
{
"type": "option",
"name": "ubuspath",
"value": "/ubus/"
}
]
},
{
"name": "extern",
"section": "flash_keep",
"options": [
{
"type": "option",
"name": "uci",
"value": "/etc/config/"
},
{
"type": "option",
"name": "dropbear",
"value": "/etc/dropbear/"
},
{
"type": "option",
"name": "openvpn",
"value": "/etc/openvpn/"
},
{
"type": "option",
"name": "passwd",
"value": "/etc/passwd"
},
{
"type": "option",
"name": "opkg",
"value": "/etc/opkg.conf"
},
{
"type": "option",
"name": "firewall",
"value": "/etc/firewall.user"
},
{
"type": "option",
"name": "uploads",
"value": "/lib/uci/upload/"
}
]
},
{
"name": "internal",
"section": "languages",
"options": null
},
{
"name": "internal",
"section": "sauth",
"options": [
{
"type": "option",
"name": "sessionpath",
"value": "/tmp/luci-sessions"
},
{
"type": "option",
"name": "sessiontime",
"value": "3600"
}
]
},
{
"name": "internal",
"section": "ccache",
"options": [
{
"type": "option",
"name": "enable",
"value": "1"
}
]
},
{
"name": "internal",
"section": "themes",
"options": [
{
"type": "option",
"name": "Bootstrap",
"value": "/luci-static/bootstrap"
},
{
"type": "option",
"name": "BootstrapDark",
"value": "/luci-static/bootstrap-dark"
},
{
"type": "option",
"name": "BootstrapLight",
"value": "/luci-static/bootstrap-light"
}
]
},
{
"name": "internal",
"section": "apply",
"options": [
{
"type": "option",
"name": "rollback",
"value": "90"
},
{
"type": "option",
"name": "holdoff",
"value": "4"
},
{
"type": "option",
"name": "timeout",
"value": "5"
},
{
"type": "option",
"name": "display",
"value": "1.5"
}
]
},
{
"name": "internal",
"section": "diag",
"options": [
{
"type": "option",
"name": "dns",
"value": "openwrt.org"
},
{
"type": "option",
"name": "ping",
"value": "openwrt.org"
},
{
"type": "option",
"name": "route",
"value": "openwrt.org"
}
]
}
]
},
{
"name": "network",
"configs": [
{
"name": "interface",
"section": "loopback",
"options": [
{
"type": "option",
"name": "ifname",
"value": "lo"
},
{
"type": "option",
"name": "proto",
"value": "static"
},
{
"type": "option",
"name": "ipaddr",
"value": "127.0.0.1"
},
{
"type": "option",
"name": "netmask",
"value": "255.0.0.0"
}
]
},
{
"name": "interface",
"section": "wan",
"options": [
{
"type": "option",
"name": "ifname",
"value": "eth0"
},
{
"type": "option",
"name": "proto",
"value": "dhcp"
}
]
}
]
},
{
"name": "rpcd",
"configs": [
{
"name": "rpcd",
"options": [
{
"type": "option",
"name": "socket",
"value": "/var/run/ubus/ubus.sock"
},
{
"type": "option",
"name": "timeout",
"value": "30"
}
]
},
{
"name": "login",
"options": [
{
"type": "option",
"name": "username",
"value": "root"
},
{
"type": "option",
"name": "password",
"value": "$p$root"
},
{
"type": "list",
"name": "read",
"value": "*"
},
{
"type": "list",
"name": "write",
"value": "*"
}
]
}
]
},
{
"name": "system",
"configs": [
{
"name": "system",
"options": [
{
"type": "option",
"name": "hostname",
"value": "OpenWrt"
},
{
"type": "option",
"name": "timezone",
"value": "UTC"
},
{
"type": "option",
"name": "ttylogin",
"value": "0"
},
{
"type": "option",
"name": "log_size",
"value": "64"
},
{
"type": "option",
"name": "urandom_seed",
"value": "0"
}
]
},
{
"name": "timeserver",
"section": "ntp",
"options": [
{
"type": "option",
"name": "enabled",
"value": "1"
},
{
"type": "option",
"name": "enable_server",
"value": "0"
},
{
"type": "list",
"name": "server",
"value": "0.openwrt.pool.ntp.org"
},
{
"type": "list",
"name": "server",
"value": "1.openwrt.pool.ntp.org"
},
{
"type": "list",
"name": "server",
"value": "2.openwrt.pool.ntp.org"
},
{
"type": "list",
"name": "server",
"value": "3.openwrt.pool.ntp.org"
}
]
}
]
},
{
"name": "ucitrack",
"configs": [
{
"name": "network",
"options": [
{
"type": "option",
"name": "init",
"value": "network"
},
{
"type": "list",
"name": "affects",
"value": "dhcp"
}
]
},
{
"name": "wireless",
"options": [
{
"type": "list",
"name": "affects",
"value": "network"
}
]
},
{
"name": "firewall",
"options": [
{
"type": "option",
"name": "init",
"value": "firewall"
},
{
"type": "list",
"name": "affects",
"value": "luci-splash"
},
{
"type": "list",
"name": "affects",
"value": "qos"
},
{
"type": "list",
"name": "affects",
"value": "miniupnpd"
}
]
},
{
"name": "olsr",
"options": [
{
"type": "option",
"name": "init",
"value": "olsrd"
}
]
},
{
"name": "dhcp",
"options": [
{
"type": "option",
"name": "init",
"value": "dnsmasq"
},
{
"type": "list",
"name": "affects",
"value": "odhcpd"
}
]
},
{
"name": "odhcpd",
"options": [
{
"type": "option",
"name": "init",
"value": "odhcpd"
}
]
},
{
"name": "dropbear",
"options": [
{
"type": "option",
"name": "init",
"value": "dropbear"
}
]
},
{
"name": "httpd",
"options": [
{
"type": "option",
"name": "init",
"value": "httpd"
}
]
},
{
"name": "fstab",
"options": [
{
"type": "option",
"name": "exec",
"value": "/sbin/block mount"
}
]
},
{
"name": "qos",
"options": [
{
"type": "option",
"name": "init",
"value": "qos"
}
]
},
{
"name": "system",
"options": [
{
"type": "option",
"name": "init",
"value": "led"
},
{
"type": "option",
"name": "exec",
"value": "/etc/init.d/log reload"
},
{
"type": "list",
"name": "affects",
"value": "luci_statistics"
},
{
"type": "list",
"name": "affects",
"value": "dhcp"
}
]
},
{
"name": "luci_splash",
"options": [
{
"type": "option",
"name": "init",
"value": "luci_splash"
}
]
},
{
"name": "upnpd",
"options": [
{
"type": "option",
"name": "init",
"value": "miniupnpd"
}
]
},
{
"name": "ntpclient",
"options": [
{
"type": "option",
"name": "init",
"value": "ntpclient"
}
]
},
{
"name": "samba",
"options": [
{
"type": "option",
"name": "init",
"value": "samba"
}
]
},
{
"name": "tinyproxy",
"options": [
{
"type": "option",
"name": "init",
"value": "tinyproxy"
}
]
}
]
},
{ {
"name": "uhttpd", "name": "uhttpd",
"configs": [ "configs": [
@ -23,12 +1492,12 @@
{ {
"type": "list", "type": "list",
"name": "listen_https", "name": "listen_https",
"value": "0.0.0.0:8443" "value": "0.0.0.0:4443"
}, },
{ {
"type": "list", "type": "list",
"name": "listen_https", "name": "listen_https",
"value": "[::]:8443" "value": "[::]:4443"
}, },
{ {
"type": "option", "type": "option",

View File

@ -1,4 +1,9 @@
logger:
level: 1
format: human
agent: agent:
serverUrl: http://127.0.0.1:3000
privateKeyPath: /var/lib/emissary/agent-key.json
reconciliationInterval: 5 reconciliationInterval: 5
controllers: controllers:
persistence: persistence:
@ -6,10 +11,14 @@ agent:
stateFile: /var/lib/emissary/state.json stateFile: /var/lib/emissary/state.json
spec: spec:
enabled: true enabled: true
serverUrl: http://192.168.0.45:3000
gateway: gateway:
enabled: true enabled: true
uci: uci:
enabled: true enabled: true
binPath: uci binPath: uci
configBackupFile: /var/lib/emissary/uci-backup.conf configBackupFile: /var/lib/emissary/uci-backup.conf
collectors:
- name: uname
command: uname
args:
- -a

View File

@ -1,24 +1,27 @@
http:
host: 0.0.0.0
port: 3000
logger: logger:
level: 1 level: 1
format: human format: human
database: server:
driver: sqlite privateKeyPath: /var/lib/emissary/server-key.json
dsn: sqlite:///var/lib/emissary/data.sqlite issuer: http://127.0.0.1:3000
cors: http:
allowedOrigins: [] host: 0.0.0.0
allowCredentials: true port: 3000
allowMethods: database:
- POST driver: sqlite
- GET dsn: sqlite:///var/lib/emissary/data.sqlite
- PUT cors:
- DELETE allowedOrigins: []
allowedHeaders: allowCredentials: true
- Origin allowMethods:
- Accept - POST
- Content-Type - GET
- Authorization - PUT
- Sentry-Trace - DELETE
allowedHeaders:
- Origin
- Accept
- Content-Type
- Authorization
- Sentry-Trace
debug: false debug: false

View File

@ -1,9 +1,10 @@
#!/sbin/openrc-run #!/sbin/openrc-run
command="/usr/bin/emissary" command="/usr/bin/emissary"
command_args="--config /etc/emissary/config.yml agent run" command_args="--workdir /usr/share/emissary --config /etc/emissary/agent.yml agent run"
start_stop_daemon_args='--chdir /usr/share/emissary'
supervisor=supervise-daemon supervisor=supervise-daemon
output_log="/var/log/emissary/agent.log"
error_log="$output_log"
depend() { depend() {
need net need net

View File

@ -1,9 +1,14 @@
#!/sbin/openrc-run #!/sbin/openrc-run
command="/usr/bin/emissary" command="/usr/bin/emissary"
command_args="--config /etc/emissary/config.yml server run" command_args="--workdir /usr/share/emissary --config /etc/emissary/server.yml server run"
start_stop_daemon_args='--chdir /usr/share/emissary'
supervisor=supervise-daemon supervisor=supervise-daemon
output_log="/var/log/emissary/server.log"
error_log="$output_log"
start_pre() {
/usr/bin/emissary --workdir /usr/share/emissary --config /etc/emissary/server.yml server database migrate
}
depend() { depend() {
need net need net

View File

@ -0,0 +1,10 @@
{
"apps": {
"edge.sdk.client.test": {
"url": "http://localhost:3001/edge.sdk.client.test_0.0.0.zip",
"sha256sum": "58019192dacdae17755707719707db007e26dac856102280583fbd18427dd352",
"format": "zip",
"address": "127.0.0.1:8081"
}
}
}

View File

@ -6,7 +6,8 @@ tmp/config.yml
prep: make build-emissary prep: make build-emissary
prep: make tmp/server.yml prep: make tmp/server.yml
prep: make tmp/agent.yml prep: make tmp/agent.yml
prep: make run-emissary-server EMISSARY_CMD="--debug --config tmp/agent.yml server database migrate" prep: make run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml server database migrate"
prep: make .emissary-token
daemon: make run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml server run" daemon: make run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml server run"
daemon: make run-emissary-agent EMISSARY_CMD="--debug --config tmp/agent.yml agent run" daemon: make run-emissary-agent EMISSARY_CMD="--debug --config tmp/agent.yml agent run"
} }