mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-31 04:57:45 +09:00 
			
		
		
		
	Use tailscale key types instead of strings (#1609)
* upgrade tailscale Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> * make Node object use actualy tailscale key types This commit changes the Node struct to have both a field for strings to store the keys in the database and a dedicated Key for each type of key. The keys are populated and stored with Gorm hooks to ensure the data is stored in the db. Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> * use key types throughout the code Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> * make sure machinekey is concistently used Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> * use machine key in auth url Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> * fix web register Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> * use key type in notifier Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> * fix relogin with webauth Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> --------- Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
		| @@ -4,10 +4,10 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
|  |  | ||||||
| 	v1 "github.com/juanfont/headscale/gen/go/headscale/v1" | 	v1 "github.com/juanfont/headscale/gen/go/headscale/v1" | ||||||
| 	"github.com/juanfont/headscale/hscontrol/util" |  | ||||||
| 	"github.com/rs/zerolog/log" | 	"github.com/rs/zerolog/log" | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
| 	"google.golang.org/grpc/status" | 	"google.golang.org/grpc/status" | ||||||
|  | 	"tailscale.com/types/key" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -93,11 +93,13 @@ var createNodeCmd = &cobra.Command{ | |||||||
|  |  | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		if !util.NodePublicKeyRegex.Match([]byte(machineKey)) { |  | ||||||
| 			err = errPreAuthKeyMalformed | 		var mkey key.MachinePublic | ||||||
|  | 		err = mkey.UnmarshalText([]byte(machineKey)) | ||||||
|  | 		if err != nil { | ||||||
| 			ErrorOutput( | 			ErrorOutput( | ||||||
| 				err, | 				err, | ||||||
| 				fmt.Sprintf("Error: %s", err), | 				fmt.Sprintf("Failed to parse machine key from flag: %s", err), | ||||||
| 				output, | 				output, | ||||||
| 			) | 			) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -33,7 +33,7 @@ | |||||||
|  |  | ||||||
|           # When updating go.mod or go.sum, a new sha will need to be calculated, |           # When updating go.mod or go.sum, a new sha will need to be calculated, | ||||||
|           # update this if you have a mismatch after doing a change to thos files. |           # update this if you have a mismatch after doing a change to thos files. | ||||||
|           vendorSha256 = "sha256-Q6eySc8lXYhkWka7Y+qOM6viv7QhdjFZDX8PttaLfr4="; |           vendorSha256 = "sha256-SYb2LCCZT/p1UHwB1b0IHPfk6Sxh3UYkR4r+KjkL4F8="; | ||||||
|  |  | ||||||
|           ldflags = ["-s" "-w" "-X github.com/juanfont/headscale/cmd/headscale/cli.Version=v${version}"]; |           ldflags = ["-s" "-w" "-X github.com/juanfont/headscale/cmd/headscale/cli.Version=v${version}"]; | ||||||
|         }; |         }; | ||||||
|   | |||||||
							
								
								
									
										67
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								go.mod
									
									
									
									
									
								
							| @@ -16,14 +16,14 @@ require ( | |||||||
| 	github.com/gorilla/mux v1.8.0 | 	github.com/gorilla/mux v1.8.0 | ||||||
| 	github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 | 	github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 | ||||||
| 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 | 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 | ||||||
| 	github.com/klauspost/compress v1.16.7 | 	github.com/klauspost/compress v1.17.0 | ||||||
| 	github.com/oauth2-proxy/mockoidc v0.0.0-20220308204021-b9169deeb282 | 	github.com/oauth2-proxy/mockoidc v0.0.0-20220308204021-b9169deeb282 | ||||||
| 	github.com/ory/dockertest/v3 v3.9.1 | 	github.com/ory/dockertest/v3 v3.9.1 | ||||||
| 	github.com/patrickmn/go-cache v2.1.0+incompatible | 	github.com/patrickmn/go-cache v2.1.0+incompatible | ||||||
| 	github.com/philip-bui/grpc-zerolog v1.0.1 | 	github.com/philip-bui/grpc-zerolog v1.0.1 | ||||||
| 	github.com/pkg/profile v1.7.0 | 	github.com/pkg/profile v1.7.0 | ||||||
| 	github.com/prometheus/client_golang v1.15.1 | 	github.com/prometheus/client_golang v1.17.0 | ||||||
| 	github.com/prometheus/common v0.42.0 | 	github.com/prometheus/common v0.44.0 | ||||||
| 	github.com/pterm/pterm v0.12.58 | 	github.com/pterm/pterm v0.12.58 | ||||||
| 	github.com/puzpuzpuz/xsync/v2 v2.4.0 | 	github.com/puzpuzpuz/xsync/v2 v2.4.0 | ||||||
| 	github.com/rs/zerolog v1.29.0 | 	github.com/rs/zerolog v1.29.0 | ||||||
| @@ -33,19 +33,19 @@ require ( | |||||||
| 	github.com/stretchr/testify v1.8.4 | 	github.com/stretchr/testify v1.8.4 | ||||||
| 	github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a | 	github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a | ||||||
| 	github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e | 	github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e | ||||||
| 	go4.org/netipx v0.0.0-20230728180743-ad4cb58a6516 | 	go4.org/netipx v0.0.0-20230824141953-6213f710f925 | ||||||
| 	golang.org/x/crypto v0.12.0 | 	golang.org/x/crypto v0.14.0 | ||||||
| 	golang.org/x/net v0.14.0 | 	golang.org/x/net v0.17.0 | ||||||
| 	golang.org/x/oauth2 v0.7.0 | 	golang.org/x/oauth2 v0.12.0 | ||||||
| 	golang.org/x/sync v0.2.0 | 	golang.org/x/sync v0.3.0 | ||||||
| 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 | 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 | ||||||
| 	google.golang.org/grpc v1.55.0 | 	google.golang.org/grpc v1.55.0 | ||||||
| 	google.golang.org/protobuf v1.30.0 | 	google.golang.org/protobuf v1.31.0 | ||||||
| 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c | 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c | ||||||
| 	gopkg.in/yaml.v3 v3.0.1 | 	gopkg.in/yaml.v3 v3.0.1 | ||||||
| 	gorm.io/driver/postgres v1.4.8 | 	gorm.io/driver/postgres v1.4.8 | ||||||
| 	gorm.io/gorm v1.24.6 | 	gorm.io/gorm v1.24.6 | ||||||
| 	tailscale.com v1.50.0 | 	tailscale.com v1.54.0 | ||||||
| ) | ) | ||||||
|  |  | ||||||
| require ( | require ( | ||||||
| @@ -56,22 +56,22 @@ require ( | |||||||
| 	github.com/Microsoft/go-winio v0.6.1 // indirect | 	github.com/Microsoft/go-winio v0.6.1 // indirect | ||||||
| 	github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect | 	github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect | ||||||
| 	github.com/akutz/memconn v0.1.0 // indirect | 	github.com/akutz/memconn v0.1.0 // indirect | ||||||
| 	github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 // indirect | 	github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect | ||||||
| 	github.com/beorn7/perks v1.0.1 // indirect | 	github.com/beorn7/perks v1.0.1 // indirect | ||||||
| 	github.com/cenkalti/backoff/v4 v4.2.0 // indirect | 	github.com/cenkalti/backoff/v4 v4.2.0 // indirect | ||||||
| 	github.com/cespare/xxhash/v2 v2.2.0 // indirect | 	github.com/cespare/xxhash/v2 v2.2.0 // indirect | ||||||
| 	github.com/containerd/console v1.0.3 // indirect | 	github.com/containerd/console v1.0.3 // indirect | ||||||
| 	github.com/containerd/continuity v0.3.0 // indirect | 	github.com/containerd/continuity v0.3.0 // indirect | ||||||
| 	github.com/coreos/go-iptables v0.6.0 // indirect | 	github.com/coreos/go-iptables v0.7.0 // indirect | ||||||
| 	github.com/dblohm7/wingoes v0.0.0-20230821191801-fc76608aecf0 // indirect | 	github.com/dblohm7/wingoes v0.0.0-20230929194252-e994401fc077 // indirect | ||||||
| 	github.com/docker/cli v23.0.5+incompatible // indirect | 	github.com/docker/cli v24.0.6+incompatible // indirect | ||||||
| 	github.com/docker/docker v24.0.4+incompatible // indirect | 	github.com/docker/docker v24.0.7+incompatible // indirect | ||||||
| 	github.com/docker/go-connections v0.4.0 // indirect | 	github.com/docker/go-connections v0.4.0 // indirect | ||||||
| 	github.com/docker/go-units v0.5.0 // indirect | 	github.com/docker/go-units v0.5.0 // indirect | ||||||
| 	github.com/dustin/go-humanize v1.0.1 // indirect | 	github.com/dustin/go-humanize v1.0.1 // indirect | ||||||
| 	github.com/felixge/fgprof v0.9.3 // indirect | 	github.com/felixge/fgprof v0.9.3 // indirect | ||||||
| 	github.com/fsnotify/fsnotify v1.6.0 // indirect | 	github.com/fsnotify/fsnotify v1.6.0 // indirect | ||||||
| 	github.com/fxamacker/cbor/v2 v2.4.0 // indirect | 	github.com/fxamacker/cbor/v2 v2.5.0 // indirect | ||||||
| 	github.com/glebarez/go-sqlite v1.20.3 // indirect | 	github.com/glebarez/go-sqlite v1.20.3 // indirect | ||||||
| 	github.com/go-jose/go-jose/v3 v3.0.0 // indirect | 	github.com/go-jose/go-jose/v3 v3.0.0 // indirect | ||||||
| 	github.com/gogo/protobuf v1.3.2 // indirect | 	github.com/gogo/protobuf v1.3.2 // indirect | ||||||
| @@ -83,7 +83,7 @@ require ( | |||||||
| 	github.com/google/nftables v0.1.1-0.20230115205135-9aa6fdf5a28c // indirect | 	github.com/google/nftables v0.1.1-0.20230115205135-9aa6fdf5a28c // indirect | ||||||
| 	github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 // indirect | 	github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 // indirect | ||||||
| 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect | 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect | ||||||
| 	github.com/google/uuid v1.3.0 // indirect | 	github.com/google/uuid v1.3.1 // indirect | ||||||
| 	github.com/gookit/color v1.5.3 // indirect | 	github.com/gookit/color v1.5.3 // indirect | ||||||
| 	github.com/hashicorp/go-version v1.6.0 // indirect | 	github.com/hashicorp/go-version v1.6.0 // indirect | ||||||
| 	github.com/hashicorp/hcl v1.0.0 // indirect | 	github.com/hashicorp/hcl v1.0.0 // indirect | ||||||
| @@ -96,7 +96,7 @@ require ( | |||||||
| 	github.com/jinzhu/inflection v1.0.0 // indirect | 	github.com/jinzhu/inflection v1.0.0 // indirect | ||||||
| 	github.com/jinzhu/now v1.1.5 // indirect | 	github.com/jinzhu/now v1.1.5 // indirect | ||||||
| 	github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect | 	github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect | ||||||
| 	github.com/jsimonetti/rtnetlink v1.3.2 // indirect | 	github.com/jsimonetti/rtnetlink v1.3.5 // 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/kr/pretty v0.3.1 // indirect | 	github.com/kr/pretty v0.3.1 // indirect | ||||||
| 	github.com/kr/text v0.2.0 // indirect | 	github.com/kr/text v0.2.0 // indirect | ||||||
| @@ -104,33 +104,34 @@ require ( | |||||||
| 	github.com/lithammer/fuzzysearch v1.1.5 // indirect | 	github.com/lithammer/fuzzysearch v1.1.5 // indirect | ||||||
| 	github.com/magiconair/properties v1.8.7 // indirect | 	github.com/magiconair/properties v1.8.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.18 // indirect | 	github.com/mattn/go-isatty v0.0.19 // indirect | ||||||
| 	github.com/mattn/go-runewidth v0.0.14 // indirect | 	github.com/mattn/go-runewidth v0.0.14 // indirect | ||||||
| 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect | 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect | ||||||
| 	github.com/mdlayher/netlink v1.7.2 // indirect | 	github.com/mdlayher/netlink v1.7.2 // indirect | ||||||
| 	github.com/mdlayher/socket v0.4.1 // indirect | 	github.com/mdlayher/socket v0.5.0 // indirect | ||||||
| 	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect | 	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect | ||||||
| 	github.com/miekg/dns v1.1.55 // indirect | 	github.com/miekg/dns v1.1.56 // indirect | ||||||
| 	github.com/mitchellh/go-ps v1.0.0 // indirect | 	github.com/mitchellh/go-ps v1.0.0 // indirect | ||||||
| 	github.com/mitchellh/mapstructure v1.5.0 // indirect | 	github.com/mitchellh/mapstructure v1.5.0 // indirect | ||||||
| 	github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect | 	github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect | ||||||
| 	github.com/opencontainers/go-digest v1.0.0 // indirect | 	github.com/opencontainers/go-digest v1.0.0 // indirect | ||||||
| 	github.com/opencontainers/image-spec v1.1.0-rc3 // indirect | 	github.com/opencontainers/image-spec v1.1.0-rc5 // indirect | ||||||
| 	github.com/opencontainers/runc v1.1.4 // indirect | 	github.com/opencontainers/runc v1.1.4 // indirect | ||||||
| 	github.com/pelletier/go-toml/v2 v2.0.8 // indirect | 	github.com/pelletier/go-toml/v2 v2.0.8 // indirect | ||||||
| 	github.com/pkg/errors v0.9.1 // indirect | 	github.com/pkg/errors v0.9.1 // indirect | ||||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||||
| 	github.com/prometheus/client_model v0.4.0 // indirect | 	github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect | ||||||
| 	github.com/prometheus/procfs v0.9.0 // indirect | 	github.com/prometheus/procfs v0.12.0 // indirect | ||||||
| 	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect | 	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect | ||||||
| 	github.com/rivo/uniseg v0.4.4 // indirect | 	github.com/rivo/uniseg v0.4.4 // indirect | ||||||
| 	github.com/rogpeppe/go-internal v1.10.0 // indirect | 	github.com/rogpeppe/go-internal v1.11.0 // indirect | ||||||
| 	github.com/sirupsen/logrus v1.9.0 // indirect | 	github.com/sirupsen/logrus v1.9.3 // indirect | ||||||
| 	github.com/spf13/afero v1.9.5 // indirect | 	github.com/spf13/afero v1.9.5 // indirect | ||||||
| 	github.com/spf13/cast v1.5.1 // indirect | 	github.com/spf13/cast v1.5.1 // indirect | ||||||
| 	github.com/spf13/jwalterweatherman v1.1.0 // indirect | 	github.com/spf13/jwalterweatherman v1.1.0 // indirect | ||||||
| 	github.com/spf13/pflag v1.0.5 // indirect | 	github.com/spf13/pflag v1.0.5 // indirect | ||||||
| 	github.com/subosito/gotenv v1.4.2 // indirect | 	github.com/subosito/gotenv v1.4.2 // indirect | ||||||
|  | 	github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect | ||||||
| 	github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85 // indirect | 	github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85 // indirect | ||||||
| 	github.com/vishvananda/netlink v1.2.1-beta.2 // indirect | 	github.com/vishvananda/netlink v1.2.1-beta.2 // indirect | ||||||
| 	github.com/vishvananda/netns v0.0.4 // indirect | 	github.com/vishvananda/netns v0.0.4 // indirect | ||||||
| @@ -140,15 +141,15 @@ require ( | |||||||
| 	github.com/xeipuuv/gojsonschema v1.2.0 // indirect | 	github.com/xeipuuv/gojsonschema v1.2.0 // indirect | ||||||
| 	github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect | 	github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect | ||||||
| 	go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect | 	go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect | ||||||
| 	golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect | 	golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect | ||||||
| 	golang.org/x/mod v0.11.0 // indirect | 	golang.org/x/mod v0.12.0 // indirect | ||||||
| 	golang.org/x/sys v0.11.0 // indirect | 	golang.org/x/sys v0.13.0 // indirect | ||||||
| 	golang.org/x/term v0.11.0 // indirect | 	golang.org/x/term v0.13.0 // indirect | ||||||
| 	golang.org/x/text v0.12.0 // indirect | 	golang.org/x/text v0.13.0 // indirect | ||||||
| 	golang.org/x/time v0.3.0 // indirect | 	golang.org/x/time v0.3.0 // indirect | ||||||
| 	golang.org/x/tools v0.9.1 // indirect | 	golang.org/x/tools v0.13.0 // indirect | ||||||
| 	golang.zx2c4.com/wireguard/windows v0.5.3 // indirect | 	golang.zx2c4.com/wireguard/windows v0.5.3 // indirect | ||||||
| 	google.golang.org/appengine v1.6.7 // indirect | 	google.golang.org/appengine v1.6.8 // indirect | ||||||
| 	gopkg.in/ini.v1 v1.67.0 // indirect | 	gopkg.in/ini.v1 v1.67.0 // indirect | ||||||
| 	gopkg.in/square/go-jose.v2 v2.6.0 // indirect | 	gopkg.in/square/go-jose.v2 v2.6.0 // indirect | ||||||
| 	gopkg.in/yaml.v2 v2.4.0 // indirect | 	gopkg.in/yaml.v2 v2.4.0 // indirect | ||||||
|   | |||||||
							
								
								
									
										142
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								go.sum
									
									
									
									
									
								
							| @@ -70,8 +70,8 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEV | |||||||
| github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= | github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= | ||||||
| github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A= | github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A= | ||||||
| github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw= | github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw= | ||||||
| github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= | github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= | ||||||
| github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= | github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= | ||||||
| github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= | github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= | ||||||
| github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= | github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= | ||||||
| github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= | ||||||
| @@ -86,8 +86,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR | |||||||
| github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= | ||||||
| github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= | ||||||
| github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= | github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= | ||||||
| github.com/cilium/ebpf v0.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ= | github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= | ||||||
| github.com/cilium/ebpf v0.10.0/go.mod h1:DPiVdY/kT534dgc9ERmvP8mWA+9gvwgKfRvk4nNWnoE= | github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= | ||||||
| github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | ||||||
| github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= | ||||||
| github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= | ||||||
| @@ -96,8 +96,8 @@ github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARu | |||||||
| github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= | github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= | ||||||
| github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= | github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= | ||||||
| github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= | github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= | ||||||
| github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= | github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= | ||||||
| github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= | github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= | ||||||
| github.com/coreos/go-oidc/v3 v3.5.0 h1:VxKtbccHZxs8juq7RdJntSqtXFtde9YpNpGn0yqgEHw= | github.com/coreos/go-oidc/v3 v3.5.0 h1:VxKtbccHZxs8juq7RdJntSqtXFtde9YpNpGn0yqgEHw= | ||||||
| github.com/coreos/go-oidc/v3 v3.5.0/go.mod h1:ecXRtV4romGPeO6ieExAsUK9cb/3fp9hXNz1tlv8PIM= | github.com/coreos/go-oidc/v3 v3.5.0/go.mod h1:ecXRtV4romGPeO6ieExAsUK9cb/3fp9hXNz1tlv8PIM= | ||||||
| github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= | github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= | ||||||
| @@ -112,14 +112,14 @@ github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxG | |||||||
| 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= | ||||||
| github.com/dblohm7/wingoes v0.0.0-20230821191801-fc76608aecf0 h1:/dgKwHVTI0J+A0zd/BHOF2CTn1deN0735cJrb+w2hbE= | github.com/dblohm7/wingoes v0.0.0-20230929194252-e994401fc077 h1:WphxHslVftszsr0oZOHPaOjpmN/BsgNYF+gW/hxZXXc= | ||||||
| github.com/dblohm7/wingoes v0.0.0-20230821191801-fc76608aecf0/go.mod h1:6NCrWM5jRefaG7iN0iMShPalLsljHWBh9v1zxM2f8Xs= | github.com/dblohm7/wingoes v0.0.0-20230929194252-e994401fc077/go.mod h1:6NCrWM5jRefaG7iN0iMShPalLsljHWBh9v1zxM2f8Xs= | ||||||
| github.com/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g= | github.com/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g= | ||||||
| github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= | github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= | ||||||
| github.com/docker/cli v23.0.5+incompatible h1:ufWmAOuD3Vmr7JP2G5K3cyuNC4YZWiAsuDEvFVVDafE= | github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= | ||||||
| github.com/docker/cli v23.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= | github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= | ||||||
| github.com/docker/docker v24.0.4+incompatible h1:s/LVDftw9hjblvqIeTiGYXBCD95nOEEl7qRsRrIOuQI= | github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= | ||||||
| github.com/docker/docker v24.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= | github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= | ||||||
| github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= | github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= | ||||||
| github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= | ||||||
| github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= | github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= | ||||||
| @@ -142,8 +142,8 @@ github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx | |||||||
| github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= | github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= | ||||||
| github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= | ||||||
| github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= | github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= | ||||||
| github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= | github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= | ||||||
| github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= | github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= | ||||||
| github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= | ||||||
| github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= | ||||||
| github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= | github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= | ||||||
| @@ -258,8 +258,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 | |||||||
| github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= | ||||||
| github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= | ||||||
| github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||||
| github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= | github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= | ||||||
| github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||||
| github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= | ||||||
| github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= | ||||||
| github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= | github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= | ||||||
| @@ -306,8 +306,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= | |||||||
| github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= | github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= | ||||||
| github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 h1:elKwZS1OcdQ0WwEDBeqxKwb7WB62QX8bvZ/FJnVXIfk= | github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 h1:elKwZS1OcdQ0WwEDBeqxKwb7WB62QX8bvZ/FJnVXIfk= | ||||||
| github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86/go.mod h1:aFAMtuldEgx/4q7iSGazk22+IcgvtiC+HIimFO9XlS8= | github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86/go.mod h1:aFAMtuldEgx/4q7iSGazk22+IcgvtiC+HIimFO9XlS8= | ||||||
| github.com/jsimonetti/rtnetlink v1.3.2 h1:dcn0uWkfxycEEyNy0IGfx3GrhQ38LH7odjxAghimsVI= | github.com/jsimonetti/rtnetlink v1.3.5 h1:hVlNQNRlLDGZz31gBPicsG7Q53rnlsz1l1Ix/9XlpVA= | ||||||
| github.com/jsimonetti/rtnetlink v1.3.2/go.mod h1:BBu4jZCpTjP6Gk0/wfrO8qcqymnN3g0hoFqObRmUo6U= | github.com/jsimonetti/rtnetlink v1.3.5/go.mod h1:0LFedyiTkebnd43tE4YAkWGIq9jQphow4CcwxaT2Y00= | ||||||
| github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | ||||||
| github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= | ||||||
| github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= | ||||||
| @@ -318,8 +318,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C | |||||||
| github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= | ||||||
| github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | ||||||
| github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= | github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= | ||||||
| github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= | github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= | ||||||
| github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= | github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= | ||||||
| github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= | ||||||
| github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= | github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= | ||||||
| github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= | github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= | ||||||
| @@ -353,8 +353,8 @@ github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcME | |||||||
| 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.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.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= | ||||||
| github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | ||||||
| github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= | ||||||
| github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= | github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= | ||||||
| github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= | github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= | ||||||
| @@ -362,13 +362,13 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zk | |||||||
| github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= | github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= | ||||||
| github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= | github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= | ||||||
| github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= | github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= | ||||||
| github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= | github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI= | ||||||
| github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= | github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI= | ||||||
| github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= | ||||||
| github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= | ||||||
| github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= | ||||||
| github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= | github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= | ||||||
| github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= | github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= | ||||||
| github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= | github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= | ||||||
| github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= | github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= | ||||||
| github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= | github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= | ||||||
| @@ -387,8 +387,8 @@ github.com/oauth2-proxy/mockoidc v0.0.0-20220308204021-b9169deeb282 h1:TQMyrpijt | |||||||
| github.com/oauth2-proxy/mockoidc v0.0.0-20220308204021-b9169deeb282/go.mod h1:rW25Kyd08Wdn3UVn0YBsDTSvReu0jqpmJKzxITPSjks= | github.com/oauth2-proxy/mockoidc v0.0.0-20220308204021-b9169deeb282/go.mod h1:rW25Kyd08Wdn3UVn0YBsDTSvReu0jqpmJKzxITPSjks= | ||||||
| github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= | github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= | ||||||
| github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= | github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= | ||||||
| github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8= | github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= | ||||||
| github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= | github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= | ||||||
| github.com/opencontainers/runc v1.1.4 h1:nRCz/8sKg6K6jgYAFLDlXzPeITBZJyX28DBVhWD+5dg= | github.com/opencontainers/runc v1.1.4 h1:nRCz/8sKg6K6jgYAFLDlXzPeITBZJyX28DBVhWD+5dg= | ||||||
| github.com/opencontainers/runc v1.1.4/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= | github.com/opencontainers/runc v1.1.4/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= | ||||||
| github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= | github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= | ||||||
| @@ -411,15 +411,15 @@ github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDj | |||||||
| github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= | github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= | ||||||
| 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/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= | github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= | ||||||
| github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= | github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= | ||||||
| github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | ||||||
| github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= | github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= | ||||||
| github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= | github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= | ||||||
| github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= | github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= | ||||||
| github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= | github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= | ||||||
| github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= | github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= | ||||||
| github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= | github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= | ||||||
| github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= | github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= | ||||||
| github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= | github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= | ||||||
| github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= | github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= | ||||||
| @@ -440,8 +440,8 @@ github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc | |||||||
| 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.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= | ||||||
| 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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= | github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= | ||||||
| github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= | github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= | ||||||
| github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= | github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= | ||||||
| github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= | github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= | ||||||
| github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= | github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= | ||||||
| @@ -456,8 +456,8 @@ github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NF | |||||||
| github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= | ||||||
| github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= | ||||||
| github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= | github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= | ||||||
| github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= | ||||||
| github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= | ||||||
| github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= | github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= | ||||||
| github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= | github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= | ||||||
| github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= | github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= | ||||||
| @@ -490,6 +490,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl | |||||||
| github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= | github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= | ||||||
| github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= | github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= | ||||||
| github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= | github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= | ||||||
|  | github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4= | ||||||
|  | github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55/go.mod h1:4k4QO+dQ3R5FofL+SanAUZe+/QfeK0+OIuwDIRu2vSg= | ||||||
| github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw= | github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw= | ||||||
| github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8= | github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8= | ||||||
| github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85 h1:zrsUcqrG2uQSPhaUPjUQwozcRdDdSxxqhNgNZ3drZFk= | github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85 h1:zrsUcqrG2uQSPhaUPjUQwozcRdDdSxxqhNgNZ3drZFk= | ||||||
| @@ -537,8 +539,8 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i | |||||||
| go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= | go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= | ||||||
| go4.org/mem v0.0.0-20220726221520-4f986261bf13 h1:CbZeCBZ0aZj8EfVgnqQcYZgf0lpZ3H9rmp5nkDTAst8= | go4.org/mem v0.0.0-20220726221520-4f986261bf13 h1:CbZeCBZ0aZj8EfVgnqQcYZgf0lpZ3H9rmp5nkDTAst8= | ||||||
| go4.org/mem v0.0.0-20220726221520-4f986261bf13/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= | go4.org/mem v0.0.0-20220726221520-4f986261bf13/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= | ||||||
| go4.org/netipx v0.0.0-20230728180743-ad4cb58a6516 h1:X66ZEoMN2SuaoI/dfZVYobB6E5zjZyyHUMWlCA7MgGE= | go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ= | ||||||
| go4.org/netipx v0.0.0-20230728180743-ad4cb58a6516/go.mod h1:TQvodOM+hJTioNQJilmLXu08JNb8i+ccq418+KWu1/Y= | go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= | ||||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||||
| golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||||
| golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||||
| @@ -550,8 +552,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y | |||||||
| golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | ||||||
| golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | ||||||
| golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= | golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= | ||||||
| golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= | golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= | ||||||
| golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= | golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= | ||||||
| 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= | ||||||
| golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | ||||||
| golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= | ||||||
| @@ -562,8 +564,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 | |||||||
| golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= | ||||||
| golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= | ||||||
| golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= | ||||||
| golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= | golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= | ||||||
| golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= | golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= | ||||||
| golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= | ||||||
| golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= | ||||||
| golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | ||||||
| @@ -588,8 +590,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |||||||
| golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | 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.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.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= | golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= | ||||||
| golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | ||||||
| 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= | ||||||
| golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||||
| golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||||
| @@ -626,8 +628,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug | |||||||
| golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= | golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= | ||||||
| golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= | golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= | ||||||
| golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= | ||||||
| golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= | golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= | ||||||
| golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= | golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= | ||||||
| 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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | ||||||
| golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | ||||||
| @@ -638,8 +640,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ | |||||||
| golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | ||||||
| golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | ||||||
| golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= | golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= | ||||||
| golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= | golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= | ||||||
| golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= | golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= | ||||||
| golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| @@ -652,8 +654,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ | |||||||
| 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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= | golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= | ||||||
| golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= | ||||||
| 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= | ||||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
| golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
| @@ -720,8 +722,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||||||
| golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= | golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= | ||||||
| golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| 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-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= | golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= | ||||||
| @@ -729,8 +731,8 @@ golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuX | |||||||
| 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.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= | golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= | ||||||
| golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= | ||||||
| golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= | golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= | ||||||
| golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= | golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= | ||||||
| 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= | ||||||
| @@ -739,10 +741,11 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | |||||||
| golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | golang.org/x/text v0.3.4/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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= | ||||||
| golang.org/x/text v0.5.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/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= | ||||||
| golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= | golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= | ||||||
| golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= | ||||||
| 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= | ||||||
| golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||||
| @@ -799,8 +802,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f | |||||||
| golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | ||||||
| golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= | ||||||
| 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.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= | golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= | ||||||
| golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= | golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= | ||||||
| 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= | ||||||
| golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
| golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
| @@ -832,8 +835,9 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 | |||||||
| google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= | ||||||
| google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= | ||||||
| google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= | ||||||
| google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= |  | ||||||
| google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= | ||||||
|  | google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= | ||||||
|  | google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= | ||||||
| google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | ||||||
| google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | ||||||
| google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | ||||||
| @@ -905,8 +909,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 | |||||||
| google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= | ||||||
| google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= | ||||||
| google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= | google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= | ||||||
| google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= | google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= | ||||||
| google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= | google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
| gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
| gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
| @@ -955,7 +959,7 @@ nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0 | |||||||
| rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= | ||||||
| rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= | ||||||
| rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= | ||||||
| software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE= | software.sslmate.com/src/go-pkcs12 v0.2.1 h1:tbT1jjaeFOF230tzOIRJ6U5S1jNqpsSyNjzDd58H3J8= | ||||||
| software.sslmate.com/src/go-pkcs12 v0.2.0/go.mod h1:23rNcYsMabIc1otwLpTkCCPwUq6kQsTyowttG/as0kQ= | software.sslmate.com/src/go-pkcs12 v0.2.1/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= | ||||||
| tailscale.com v1.50.0 h1:98infw8rznkdntRgcnlrAC5JuZfDH0bqKLyg8ZKfwMk= | tailscale.com v1.54.0 h1:Dri5BTKkHYpl+/t8ofY+tyvoTDbH/FpP7iB4B0cAQOY= | ||||||
| tailscale.com v1.50.0/go.mod h1:lBw7+Mw2d7rea3kefGjYWN8IJkB5dyaakMNMOinNGDo= | tailscale.com v1.54.0/go.mod h1:MnLFoCRwzFWr3qtkSW2nZdQpK7wQRZEk1KtcEGAuZYw= | ||||||
|   | |||||||
| @@ -449,10 +449,10 @@ func (h *Headscale) createRouter(grpcMux *grpcRuntime.ServeMux) *mux.Router { | |||||||
|  |  | ||||||
| 	router.HandleFunc("/health", h.HealthHandler).Methods(http.MethodGet) | 	router.HandleFunc("/health", h.HealthHandler).Methods(http.MethodGet) | ||||||
| 	router.HandleFunc("/key", h.KeyHandler).Methods(http.MethodGet) | 	router.HandleFunc("/key", h.KeyHandler).Methods(http.MethodGet) | ||||||
| 	router.HandleFunc("/register/{nkey}", h.RegisterWebAPI).Methods(http.MethodGet) | 	router.HandleFunc("/register/{mkey}", h.RegisterWebAPI).Methods(http.MethodGet) | ||||||
| 	h.addLegacyHandlers(router) | 	h.addLegacyHandlers(router) | ||||||
|  |  | ||||||
| 	router.HandleFunc("/oidc/register/{nkey}", h.RegisterOIDC).Methods(http.MethodGet) | 	router.HandleFunc("/oidc/register/{mkey}", h.RegisterOIDC).Methods(http.MethodGet) | ||||||
| 	router.HandleFunc("/oidc/callback", h.OIDCCallback).Methods(http.MethodGet) | 	router.HandleFunc("/oidc/callback", h.OIDCCallback).Methods(http.MethodGet) | ||||||
| 	router.HandleFunc("/apple", h.AppleConfigMessage).Methods(http.MethodGet) | 	router.HandleFunc("/apple", h.AppleConfigMessage).Methods(http.MethodGet) | ||||||
| 	router.HandleFunc("/apple/{platform}", h.ApplePlatformConfig). | 	router.HandleFunc("/apple/{platform}", h.ApplePlatformConfig). | ||||||
|   | |||||||
| @@ -45,7 +45,7 @@ func (h *Headscale) handleRegister( | |||||||
| 		// is that the client will hammer headscale with requests until it gets a | 		// is that the client will hammer headscale with requests until it gets a | ||||||
| 		// successful RegisterResponse. | 		// successful RegisterResponse. | ||||||
| 		if registerRequest.Followup != "" { | 		if registerRequest.Followup != "" { | ||||||
| 			if _, ok := h.registrationCache.Get(registerRequest.NodeKey.String()); ok { | 			if _, ok := h.registrationCache.Get(machineKey.String()); ok { | ||||||
| 				log.Debug(). | 				log.Debug(). | ||||||
| 					Caller(). | 					Caller(). | ||||||
| 					Str("node", registerRequest.Hostinfo.Hostname). | 					Str("node", registerRequest.Hostinfo.Hostname). | ||||||
| @@ -78,7 +78,7 @@ func (h *Headscale) handleRegister( | |||||||
| 			Msg("New node not yet in the database") | 			Msg("New node not yet in the database") | ||||||
|  |  | ||||||
| 		givenName, err := h.db.GenerateGivenName( | 		givenName, err := h.db.GenerateGivenName( | ||||||
| 			machineKey.String(), | 			machineKey, | ||||||
| 			registerRequest.Hostinfo.Hostname, | 			registerRequest.Hostinfo.Hostname, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @@ -97,10 +97,10 @@ func (h *Headscale) handleRegister( | |||||||
| 		// We create the node and then keep it around until a callback | 		// We create the node and then keep it around until a callback | ||||||
| 		// happens | 		// happens | ||||||
| 		newNode := types.Node{ | 		newNode := types.Node{ | ||||||
| 			MachineKey: machineKey.String(), | 			MachineKey: machineKey, | ||||||
| 			Hostname:   registerRequest.Hostinfo.Hostname, | 			Hostname:   registerRequest.Hostinfo.Hostname, | ||||||
| 			GivenName:  givenName, | 			GivenName:  givenName, | ||||||
| 			NodeKey:    registerRequest.NodeKey.String(), | 			NodeKey:    registerRequest.NodeKey, | ||||||
| 			LastSeen:   &now, | 			LastSeen:   &now, | ||||||
| 			Expiry:     &time.Time{}, | 			Expiry:     &time.Time{}, | ||||||
| 		} | 		} | ||||||
| @@ -116,7 +116,7 @@ func (h *Headscale) handleRegister( | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		h.registrationCache.Set( | 		h.registrationCache.Set( | ||||||
| 			newNode.NodeKey, | 			machineKey.String(), | ||||||
| 			newNode, | 			newNode, | ||||||
| 			registerCacheExpiration, | 			registerCacheExpiration, | ||||||
| 		) | 		) | ||||||
| @@ -134,11 +134,7 @@ func (h *Headscale) handleRegister( | |||||||
| 		// (juan): For a while we had a bug where we were not storing the MachineKey for the nodes using the TS2021, | 		// (juan): For a while we had a bug where we were not storing the MachineKey for the nodes using the TS2021, | ||||||
| 		// due to a misunderstanding of the protocol https://github.com/juanfont/headscale/issues/1054 | 		// due to a misunderstanding of the protocol https://github.com/juanfont/headscale/issues/1054 | ||||||
| 		// So if we have a not valid MachineKey (but we were able to fetch the node with the NodeKeys), we update it. | 		// So if we have a not valid MachineKey (but we were able to fetch the node with the NodeKeys), we update it. | ||||||
| 		var storedMachineKey key.MachinePublic | 		if err != nil || node.MachineKey.IsZero() { | ||||||
| 		err = storedMachineKey.UnmarshalText( |  | ||||||
| 			[]byte(node.MachineKey), |  | ||||||
| 		) |  | ||||||
| 		if err != nil || storedMachineKey.IsZero() { |  | ||||||
| 			if err := h.db.NodeSetMachineKey(node, machineKey); err != nil { | 			if err := h.db.NodeSetMachineKey(node, machineKey); err != nil { | ||||||
| 				log.Error(). | 				log.Error(). | ||||||
| 					Caller(). | 					Caller(). | ||||||
| @@ -156,7 +152,7 @@ func (h *Headscale) handleRegister( | |||||||
| 		// - Trying to log out (sending a expiry in the past) | 		// - Trying to log out (sending a expiry in the past) | ||||||
| 		// - A valid, registered node, looking for /map | 		// - A valid, registered node, looking for /map | ||||||
| 		// - Expired node wanting to reauthenticate | 		// - Expired node wanting to reauthenticate | ||||||
| 		if node.NodeKey == registerRequest.NodeKey.String() { | 		if node.NodeKey.String() == registerRequest.NodeKey.String() { | ||||||
| 			// The client sends an Expiry in the past if the client is requesting to expire the key (aka logout) | 			// The client sends an Expiry in the past if the client is requesting to expire the key (aka logout) | ||||||
| 			//   https://github.com/tailscale/tailscale/blob/main/tailcfg/tailcfg.go#L648 | 			//   https://github.com/tailscale/tailscale/blob/main/tailcfg/tailcfg.go#L648 | ||||||
| 			if !registerRequest.Expiry.IsZero() && | 			if !registerRequest.Expiry.IsZero() && | ||||||
| @@ -176,7 +172,7 @@ func (h *Headscale) handleRegister( | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// The NodeKey we have matches OldNodeKey, which means this is a refresh after a key expiration | 		// The NodeKey we have matches OldNodeKey, which means this is a refresh after a key expiration | ||||||
| 		if node.NodeKey == registerRequest.OldNodeKey.String() && | 		if node.NodeKey.String() == registerRequest.OldNodeKey.String() && | ||||||
| 			!node.IsExpired() { | 			!node.IsExpired() { | ||||||
| 			h.handleNodeKeyRefresh( | 			h.handleNodeKeyRefresh( | ||||||
| 				writer, | 				writer, | ||||||
| @@ -207,9 +203,9 @@ func (h *Headscale) handleRegister( | |||||||
| 		// we need to make sure the NodeKey matches the one in the request | 		// we need to make sure the NodeKey matches the one in the request | ||||||
| 		// TODO(juan): What happens when using fast user switching between two | 		// TODO(juan): What happens when using fast user switching between two | ||||||
| 		// headscale-managed tailnets? | 		// headscale-managed tailnets? | ||||||
| 		node.NodeKey = registerRequest.NodeKey.String() | 		node.NodeKey = registerRequest.NodeKey | ||||||
| 		h.registrationCache.Set( | 		h.registrationCache.Set( | ||||||
| 			registerRequest.NodeKey.String(), | 			machineKey.String(), | ||||||
| 			*node, | 			*node, | ||||||
| 			registerCacheExpiration, | 			registerCacheExpiration, | ||||||
| 		) | 		) | ||||||
| @@ -294,7 +290,7 @@ func (h *Headscale) handleAuthKey( | |||||||
| 		Str("node", registerRequest.Hostinfo.Hostname). | 		Str("node", registerRequest.Hostinfo.Hostname). | ||||||
| 		Msg("Authentication key was valid, proceeding to acquire IP addresses") | 		Msg("Authentication key was valid, proceeding to acquire IP addresses") | ||||||
|  |  | ||||||
| 	nodeKey := registerRequest.NodeKey.String() | 	nodeKey := registerRequest.NodeKey | ||||||
|  |  | ||||||
| 	// retrieve node information if it exist | 	// retrieve node information if it exist | ||||||
| 	// The error is not important, because if it does not | 	// The error is not important, because if it does not | ||||||
| @@ -342,7 +338,7 @@ func (h *Headscale) handleAuthKey( | |||||||
| 	} else { | 	} else { | ||||||
| 		now := time.Now().UTC() | 		now := time.Now().UTC() | ||||||
|  |  | ||||||
| 		givenName, err := h.db.GenerateGivenName(machineKey.String(), registerRequest.Hostinfo.Hostname) | 		givenName, err := h.db.GenerateGivenName(machineKey, registerRequest.Hostinfo.Hostname) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.Error(). | 			log.Error(). | ||||||
| 				Caller(). | 				Caller(). | ||||||
| @@ -359,7 +355,7 @@ func (h *Headscale) handleAuthKey( | |||||||
| 			Hostname:       registerRequest.Hostinfo.Hostname, | 			Hostname:       registerRequest.Hostinfo.Hostname, | ||||||
| 			GivenName:      givenName, | 			GivenName:      givenName, | ||||||
| 			UserID:         pak.User.ID, | 			UserID:         pak.User.ID, | ||||||
| 			MachineKey:     machineKey.String(), | 			MachineKey:     machineKey, | ||||||
| 			RegisterMethod: util.RegisterMethodAuthKey, | 			RegisterMethod: util.RegisterMethodAuthKey, | ||||||
| 			Expiry:         ®isterRequest.Expiry, | 			Expiry:         ®isterRequest.Expiry, | ||||||
| 			NodeKey:        nodeKey, | 			NodeKey:        nodeKey, | ||||||
| @@ -460,12 +456,12 @@ func (h *Headscale) handleNewNode( | |||||||
| 		resp.AuthURL = fmt.Sprintf( | 		resp.AuthURL = fmt.Sprintf( | ||||||
| 			"%s/oidc/register/%s", | 			"%s/oidc/register/%s", | ||||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | ||||||
| 			registerRequest.NodeKey, | 			machineKey.String(), | ||||||
| 		) | 		) | ||||||
| 	} else { | 	} else { | ||||||
| 		resp.AuthURL = fmt.Sprintf("%s/register/%s", | 		resp.AuthURL = fmt.Sprintf("%s/register/%s", | ||||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | ||||||
| 			registerRequest.NodeKey) | 			machineKey.String()) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey) | 	respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey) | ||||||
| @@ -715,11 +711,11 @@ func (h *Headscale) handleNodeExpiredOrLoggedOut( | |||||||
| 	if h.oauth2Config != nil { | 	if h.oauth2Config != nil { | ||||||
| 		resp.AuthURL = fmt.Sprintf("%s/oidc/register/%s", | 		resp.AuthURL = fmt.Sprintf("%s/oidc/register/%s", | ||||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | ||||||
| 			registerRequest.NodeKey) | 			machineKey.String()) | ||||||
| 	} else { | 	} else { | ||||||
| 		resp.AuthURL = fmt.Sprintf("%s/register/%s", | 		resp.AuthURL = fmt.Sprintf("%s/register/%s", | ||||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | ||||||
| 			registerRequest.NodeKey) | 			machineKey.String()) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey) | 	respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey) | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ package db | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"database/sql" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/netip" | 	"net/netip" | ||||||
| @@ -99,7 +100,7 @@ func NewHeadscaleDatabase( | |||||||
| 	// node was registered. | 	// node was registered. | ||||||
| 	_ = dbConn.Migrator().RenameColumn(&types.Node{}, "nickname", "given_name") | 	_ = dbConn.Migrator().RenameColumn(&types.Node{}, "nickname", "given_name") | ||||||
|  |  | ||||||
| 	// If the MacNodehine table has a column for registered, | 	// If the Node table has a column for registered, | ||||||
| 	// find all occourences of "false" and drop them. Then | 	// find all occourences of "false" and drop them. Then | ||||||
| 	// remove the column. | 	// remove the column. | ||||||
| 	if dbConn.Migrator().HasColumn(&types.Node{}, "registered") { | 	if dbConn.Migrator().HasColumn(&types.Node{}, "registered") { | ||||||
| @@ -114,13 +115,13 @@ func NewHeadscaleDatabase( | |||||||
| 		for _, node := range nodes { | 		for _, node := range nodes { | ||||||
| 			log.Info(). | 			log.Info(). | ||||||
| 				Str("node", node.Hostname). | 				Str("node", node.Hostname). | ||||||
| 				Str("machine_key", node.MachineKey). | 				Str("machine_key", node.MachineKey.ShortString()). | ||||||
| 				Msg("Deleting unregistered node") | 				Msg("Deleting unregistered node") | ||||||
| 			if err := dbConn.Delete(&types.Node{}, node.ID).Error; err != nil { | 			if err := dbConn.Delete(&types.Node{}, node.ID).Error; err != nil { | ||||||
| 				log.Error(). | 				log.Error(). | ||||||
| 					Err(err). | 					Err(err). | ||||||
| 					Str("node", node.Hostname). | 					Str("node", node.Hostname). | ||||||
| 					Str("machine_key", node.MachineKey). | 					Str("machine_key", node.MachineKey.ShortString()). | ||||||
| 					Msg("Error deleting unregistered node") | 					Msg("Error deleting unregistered node") | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -136,6 +137,50 @@ func NewHeadscaleDatabase( | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	err = dbConn.AutoMigrate(&types.Node{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Ensure all keys have correct prefixes | ||||||
|  | 	// https://github.com/tailscale/tailscale/blob/main/types/key/node.go#L35 | ||||||
|  | 	type result struct { | ||||||
|  | 		ID         uint64 | ||||||
|  | 		MachineKey string | ||||||
|  | 		NodeKey    string | ||||||
|  | 		DiscoKey   string | ||||||
|  | 	} | ||||||
|  | 	var results []result | ||||||
|  | 	err = db.db.Raw("SELECT id, node_key, machine_key, disco_key FROM nodes").Find(&results).Error | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, node := range results { | ||||||
|  | 		mKey := node.MachineKey | ||||||
|  | 		if !strings.HasPrefix(node.MachineKey, "mkey:") { | ||||||
|  | 			mKey = "mkey:" + node.MachineKey | ||||||
|  | 		} | ||||||
|  | 		nKey := node.NodeKey | ||||||
|  | 		if !strings.HasPrefix(node.NodeKey, "nodekey:") { | ||||||
|  | 			nKey = "nodekey:" + node.NodeKey | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		dKey := node.DiscoKey | ||||||
|  | 		if !strings.HasPrefix(node.DiscoKey, "discokey:") { | ||||||
|  | 			dKey = "discokey:" + node.DiscoKey | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		err := db.db.Exec("UPDATE nodes SET machine_key = @mKey, node_key = @nKey, disco_key = @dKey WHERE ID = @id", | ||||||
|  | 			sql.Named("mKey", mKey), | ||||||
|  | 			sql.Named("nKey", nKey), | ||||||
|  | 			sql.Named("dKey", dKey), | ||||||
|  | 			sql.Named("id", node.ID)).Error | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if dbConn.Migrator().HasColumn(&types.Node{}, "enabled_routes") { | 	if dbConn.Migrator().HasColumn(&types.Node{}, "enabled_routes") { | ||||||
| 		log.Info().Msgf("Database has legacy enabled_routes column in node, migrating...") | 		log.Info().Msgf("Database has legacy enabled_routes column in node, migrating...") | ||||||
|  |  | ||||||
| @@ -195,11 +240,6 @@ func NewHeadscaleDatabase( | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err = dbConn.AutoMigrate(&types.Node{}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if dbConn.Migrator().HasColumn(&types.Node{}, "given_name") { | 	if dbConn.Migrator().HasColumn(&types.Node{}, "given_name") { | ||||||
| 		nodes := types.Nodes{} | 		nodes := types.Nodes{} | ||||||
| 		if err := dbConn.Find(&nodes).Error; err != nil { | 		if err := dbConn.Find(&nodes).Error; err != nil { | ||||||
| @@ -253,27 +293,6 @@ func NewHeadscaleDatabase( | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Ensure all keys have correct prefixes |  | ||||||
| 	// https://github.com/tailscale/tailscale/blob/main/types/key/node.go#L35 |  | ||||||
| 	nodes := types.Nodes{} |  | ||||||
| 	if err := dbConn.Find(&nodes).Error; err != nil { |  | ||||||
| 		log.Error().Err(err).Msg("Error accessing db") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, node := range nodes { |  | ||||||
| 		if !strings.HasPrefix(node.DiscoKey, "discokey:") { |  | ||||||
| 			node.DiscoKey = "discokey:" + node.DiscoKey |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if !strings.HasPrefix(node.NodeKey, "nodekey:") { |  | ||||||
| 			node.NodeKey = "nodekey:" + node.NodeKey |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if !strings.HasPrefix(node.MachineKey, "mkey:") { |  | ||||||
| 			node.MachineKey = "mkey:" + node.MachineKey |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// TODO(kradalby): is this needed? | 	// TODO(kradalby): is this needed? | ||||||
| 	err = db.setValue("db_version", dbVersion) | 	err = db.setValue("db_version", dbVersion) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -55,7 +55,7 @@ func (hsdb *HSDatabase) listPeers(node *types.Node) (types.Nodes, error) { | |||||||
| 		Preload("User"). | 		Preload("User"). | ||||||
| 		Preload("Routes"). | 		Preload("Routes"). | ||||||
| 		Where("node_key <> ?", | 		Where("node_key <> ?", | ||||||
| 			node.NodeKey).Find(&nodes).Error; err != nil { | 			node.NodeKey.String()).Find(&nodes).Error; err != nil { | ||||||
| 		return types.Nodes{}, err | 		return types.Nodes{}, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -268,7 +268,7 @@ func (hsdb *HSDatabase) SetTags( | |||||||
| 	hsdb.notifier.NotifyWithIgnore(types.StateUpdate{ | 	hsdb.notifier.NotifyWithIgnore(types.StateUpdate{ | ||||||
| 		Type:    types.StatePeerChanged, | 		Type:    types.StatePeerChanged, | ||||||
| 		Changed: types.Nodes{node}, | 		Changed: types.Nodes{node}, | ||||||
| 	}, node.MachineKey) | 	}, node.MachineKey.String()) | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| @@ -304,7 +304,7 @@ func (hsdb *HSDatabase) RenameNode(node *types.Node, newName string) error { | |||||||
| 	hsdb.notifier.NotifyWithIgnore(types.StateUpdate{ | 	hsdb.notifier.NotifyWithIgnore(types.StateUpdate{ | ||||||
| 		Type:    types.StatePeerChanged, | 		Type:    types.StatePeerChanged, | ||||||
| 		Changed: types.Nodes{node}, | 		Changed: types.Nodes{node}, | ||||||
| 	}, node.MachineKey) | 	}, node.MachineKey.String()) | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| @@ -330,7 +330,7 @@ func (hsdb *HSDatabase) nodeSetExpiry(node *types.Node, expiry time.Time) error | |||||||
| 	hsdb.notifier.NotifyWithIgnore(types.StateUpdate{ | 	hsdb.notifier.NotifyWithIgnore(types.StateUpdate{ | ||||||
| 		Type:    types.StatePeerChanged, | 		Type:    types.StatePeerChanged, | ||||||
| 		Changed: types.Nodes{node}, | 		Changed: types.Nodes{node}, | ||||||
| 	}, node.MachineKey) | 	}, node.MachineKey.String()) | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| @@ -376,7 +376,7 @@ func (hsdb *HSDatabase) UpdateLastSeen(node *types.Node) error { | |||||||
|  |  | ||||||
| func (hsdb *HSDatabase) RegisterNodeFromAuthCallback( | func (hsdb *HSDatabase) RegisterNodeFromAuthCallback( | ||||||
| 	cache *cache.Cache, | 	cache *cache.Cache, | ||||||
| 	nodeKeyStr string, | 	mkey key.MachinePublic, | ||||||
| 	userName string, | 	userName string, | ||||||
| 	nodeExpiry *time.Time, | 	nodeExpiry *time.Time, | ||||||
| 	registrationMethod string, | 	registrationMethod string, | ||||||
| @@ -384,20 +384,14 @@ func (hsdb *HSDatabase) RegisterNodeFromAuthCallback( | |||||||
| 	hsdb.mu.Lock() | 	hsdb.mu.Lock() | ||||||
| 	defer hsdb.mu.Unlock() | 	defer hsdb.mu.Unlock() | ||||||
|  |  | ||||||
| 	nodeKey := key.NodePublic{} |  | ||||||
| 	err := nodeKey.UnmarshalText([]byte(nodeKeyStr)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	log.Debug(). | 	log.Debug(). | ||||||
| 		Str("nodeKey", nodeKey.ShortString()). | 		Str("machine_key", mkey.ShortString()). | ||||||
| 		Str("userName", userName). | 		Str("userName", userName). | ||||||
| 		Str("registrationMethod", registrationMethod). | 		Str("registrationMethod", registrationMethod). | ||||||
| 		Str("expiresAt", fmt.Sprintf("%v", nodeExpiry)). | 		Str("expiresAt", fmt.Sprintf("%v", nodeExpiry)). | ||||||
| 		Msg("Registering node from API/CLI or auth callback") | 		Msg("Registering node from API/CLI or auth callback") | ||||||
|  |  | ||||||
| 	if nodeInterface, ok := cache.Get(nodeKey.String()); ok { | 	if nodeInterface, ok := cache.Get(mkey.String()); ok { | ||||||
| 		if registrationNode, ok := nodeInterface.(types.Node); ok { | 		if registrationNode, ok := nodeInterface.(types.Node); ok { | ||||||
| 			user, err := hsdb.getUser(userName) | 			user, err := hsdb.getUser(userName) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| @@ -425,7 +419,7 @@ func (hsdb *HSDatabase) RegisterNodeFromAuthCallback( | |||||||
| 			) | 			) | ||||||
|  |  | ||||||
| 			if err == nil { | 			if err == nil { | ||||||
| 				cache.Delete(nodeKeyStr) | 				cache.Delete(mkey.String()) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			return node, err | 			return node, err | ||||||
| @@ -448,8 +442,8 @@ func (hsdb *HSDatabase) RegisterNode(node types.Node) (*types.Node, error) { | |||||||
| func (hsdb *HSDatabase) registerNode(node types.Node) (*types.Node, error) { | func (hsdb *HSDatabase) registerNode(node types.Node) (*types.Node, error) { | ||||||
| 	log.Debug(). | 	log.Debug(). | ||||||
| 		Str("node", node.Hostname). | 		Str("node", node.Hostname). | ||||||
| 		Str("machine_key", node.MachineKey). | 		Str("machine_key", node.MachineKey.ShortString()). | ||||||
| 		Str("node_key", node.NodeKey). | 		Str("node_key", node.NodeKey.ShortString()). | ||||||
| 		Str("user", node.User.Name). | 		Str("user", node.User.Name). | ||||||
| 		Msg("Registering node") | 		Msg("Registering node") | ||||||
|  |  | ||||||
| @@ -464,8 +458,8 @@ func (hsdb *HSDatabase) registerNode(node types.Node) (*types.Node, error) { | |||||||
| 		log.Trace(). | 		log.Trace(). | ||||||
| 			Caller(). | 			Caller(). | ||||||
| 			Str("node", node.Hostname). | 			Str("node", node.Hostname). | ||||||
| 			Str("machine_key", node.MachineKey). | 			Str("machine_key", node.MachineKey.ShortString()). | ||||||
| 			Str("node_key", node.NodeKey). | 			Str("node_key", node.NodeKey.ShortString()). | ||||||
| 			Str("user", node.User.Name). | 			Str("user", node.User.Name). | ||||||
| 			Msg("Node authorized again") | 			Msg("Node authorized again") | ||||||
|  |  | ||||||
| @@ -507,7 +501,7 @@ func (hsdb *HSDatabase) NodeSetNodeKey(node *types.Node, nodeKey key.NodePublic) | |||||||
| 	defer hsdb.mu.Unlock() | 	defer hsdb.mu.Unlock() | ||||||
|  |  | ||||||
| 	if err := hsdb.db.Model(node).Updates(types.Node{ | 	if err := hsdb.db.Model(node).Updates(types.Node{ | ||||||
| 		NodeKey: nodeKey.String(), | 		NodeKey: nodeKey, | ||||||
| 	}).Error; err != nil { | 	}).Error; err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @@ -524,7 +518,7 @@ func (hsdb *HSDatabase) NodeSetMachineKey( | |||||||
| 	defer hsdb.mu.Unlock() | 	defer hsdb.mu.Unlock() | ||||||
|  |  | ||||||
| 	if err := hsdb.db.Model(node).Updates(types.Node{ | 	if err := hsdb.db.Model(node).Updates(types.Node{ | ||||||
| 		MachineKey: machineKey.String(), | 		MachineKey: machineKey, | ||||||
| 	}).Error; err != nil { | 	}).Error; err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @@ -703,7 +697,7 @@ func (hsdb *HSDatabase) enableRoutes(node *types.Node, routeStrs ...string) erro | |||||||
| 	hsdb.notifier.NotifyWithIgnore(types.StateUpdate{ | 	hsdb.notifier.NotifyWithIgnore(types.StateUpdate{ | ||||||
| 		Type:    types.StatePeerChanged, | 		Type:    types.StatePeerChanged, | ||||||
| 		Changed: types.Nodes{node}, | 		Changed: types.Nodes{node}, | ||||||
| 	}, node.MachineKey) | 	}, node.MachineKey.String()) | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| @@ -734,7 +728,7 @@ func generateGivenName(suppliedName string, randomSuffix bool) (string, error) { | |||||||
| 	return normalizedHostname, nil | 	return normalizedHostname, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (hsdb *HSDatabase) GenerateGivenName(machineKey string, suppliedName string) (string, error) { | func (hsdb *HSDatabase) GenerateGivenName(mkey key.MachinePublic, suppliedName string) (string, error) { | ||||||
| 	hsdb.mu.RLock() | 	hsdb.mu.RLock() | ||||||
| 	defer hsdb.mu.RUnlock() | 	defer hsdb.mu.RUnlock() | ||||||
|  |  | ||||||
| @@ -749,8 +743,14 @@ func (hsdb *HSDatabase) GenerateGivenName(machineKey string, suppliedName string | |||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, node := range nodes { | 	var nodeFound *types.Node | ||||||
| 		if node.MachineKey != machineKey && node.GivenName == givenName { | 	for idx, node := range nodes { | ||||||
|  | 		if node.GivenName == givenName { | ||||||
|  | 			nodeFound = nodes[idx] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if nodeFound != nil && nodeFound.MachineKey.String() != mkey.String() { | ||||||
| 		postfixedName, err := generateGivenName(suppliedName, true) | 		postfixedName, err := generateGivenName(suppliedName, true) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return "", err | 			return "", err | ||||||
| @@ -758,7 +758,6 @@ func (hsdb *HSDatabase) GenerateGivenName(machineKey string, suppliedName string | |||||||
|  |  | ||||||
| 		givenName = postfixedName | 		givenName = postfixedName | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return givenName, nil | 	return givenName, nil | ||||||
| } | } | ||||||
|   | |||||||
| @@ -25,11 +25,13 @@ func (s *Suite) TestGetNode(c *check.C) { | |||||||
| 	_, err = db.GetNode("test", "testnode") | 	_, err = db.GetNode("test", "testnode") | ||||||
| 	c.Assert(err, check.NotNil) | 	c.Assert(err, check.NotNil) | ||||||
|  |  | ||||||
|  | 	nodeKey := key.NewNode() | ||||||
|  | 	machineKey := key.NewMachine() | ||||||
|  |  | ||||||
| 	node := &types.Node{ | 	node := &types.Node{ | ||||||
| 		ID:             0, | 		ID:             0, | ||||||
| 		MachineKey:     "foo", | 		MachineKey:     machineKey.Public(), | ||||||
| 		NodeKey:        "bar", | 		NodeKey:        nodeKey.Public(), | ||||||
| 		DiscoKey:       "faa", |  | ||||||
| 		Hostname:       "testnode", | 		Hostname:       "testnode", | ||||||
| 		UserID:         user.ID, | 		UserID:         user.ID, | ||||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | 		RegisterMethod: util.RegisterMethodAuthKey, | ||||||
| @@ -51,11 +53,13 @@ func (s *Suite) TestGetNodeByID(c *check.C) { | |||||||
| 	_, err = db.GetNodeByID(0) | 	_, err = db.GetNodeByID(0) | ||||||
| 	c.Assert(err, check.NotNil) | 	c.Assert(err, check.NotNil) | ||||||
|  |  | ||||||
|  | 	nodeKey := key.NewNode() | ||||||
|  | 	machineKey := key.NewMachine() | ||||||
|  |  | ||||||
| 	node := types.Node{ | 	node := types.Node{ | ||||||
| 		ID:             0, | 		ID:             0, | ||||||
| 		MachineKey:     "foo", | 		MachineKey:     machineKey.Public(), | ||||||
| 		NodeKey:        "bar", | 		NodeKey:        nodeKey.Public(), | ||||||
| 		DiscoKey:       "faa", |  | ||||||
| 		Hostname:       "testnode", | 		Hostname:       "testnode", | ||||||
| 		UserID:         user.ID, | 		UserID:         user.ID, | ||||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | 		RegisterMethod: util.RegisterMethodAuthKey, | ||||||
| @@ -82,9 +86,8 @@ func (s *Suite) TestGetNodeByNodeKey(c *check.C) { | |||||||
|  |  | ||||||
| 	node := types.Node{ | 	node := types.Node{ | ||||||
| 		ID:             0, | 		ID:             0, | ||||||
| 		MachineKey:     machineKey.Public().String(), | 		MachineKey:     machineKey.Public(), | ||||||
| 		NodeKey:        nodeKey.Public().String(), | 		NodeKey:        nodeKey.Public(), | ||||||
| 		DiscoKey:       "faa", |  | ||||||
| 		Hostname:       "testnode", | 		Hostname:       "testnode", | ||||||
| 		UserID:         user.ID, | 		UserID:         user.ID, | ||||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | 		RegisterMethod: util.RegisterMethodAuthKey, | ||||||
| @@ -113,9 +116,8 @@ func (s *Suite) TestGetNodeByAnyNodeKey(c *check.C) { | |||||||
|  |  | ||||||
| 	node := types.Node{ | 	node := types.Node{ | ||||||
| 		ID:             0, | 		ID:             0, | ||||||
| 		MachineKey:     machineKey.Public().String(), | 		MachineKey:     machineKey.Public(), | ||||||
| 		NodeKey:        nodeKey.Public().String(), | 		NodeKey:        nodeKey.Public(), | ||||||
| 		DiscoKey:       "faa", |  | ||||||
| 		Hostname:       "testnode", | 		Hostname:       "testnode", | ||||||
| 		UserID:         user.ID, | 		UserID:         user.ID, | ||||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | 		RegisterMethod: util.RegisterMethodAuthKey, | ||||||
| @@ -130,11 +132,14 @@ func (s *Suite) TestGetNodeByAnyNodeKey(c *check.C) { | |||||||
| func (s *Suite) TestHardDeleteNode(c *check.C) { | func (s *Suite) TestHardDeleteNode(c *check.C) { | ||||||
| 	user, err := db.CreateUser("test") | 	user, err := db.CreateUser("test") | ||||||
| 	c.Assert(err, check.IsNil) | 	c.Assert(err, check.IsNil) | ||||||
|  |  | ||||||
|  | 	nodeKey := key.NewNode() | ||||||
|  | 	machineKey := key.NewMachine() | ||||||
|  |  | ||||||
| 	node := types.Node{ | 	node := types.Node{ | ||||||
| 		ID:             0, | 		ID:             0, | ||||||
| 		MachineKey:     "foo", | 		MachineKey:     machineKey.Public(), | ||||||
| 		NodeKey:        "bar", | 		NodeKey:        nodeKey.Public(), | ||||||
| 		DiscoKey:       "faa", |  | ||||||
| 		Hostname:       "testnode3", | 		Hostname:       "testnode3", | ||||||
| 		UserID:         user.ID, | 		UserID:         user.ID, | ||||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | 		RegisterMethod: util.RegisterMethodAuthKey, | ||||||
| @@ -160,11 +165,13 @@ func (s *Suite) TestListPeers(c *check.C) { | |||||||
| 	c.Assert(err, check.NotNil) | 	c.Assert(err, check.NotNil) | ||||||
|  |  | ||||||
| 	for index := 0; index <= 10; index++ { | 	for index := 0; index <= 10; index++ { | ||||||
|  | 		nodeKey := key.NewNode() | ||||||
|  | 		machineKey := key.NewMachine() | ||||||
|  |  | ||||||
| 		node := types.Node{ | 		node := types.Node{ | ||||||
| 			ID:             uint64(index), | 			ID:             uint64(index), | ||||||
| 			MachineKey:     "foo" + strconv.Itoa(index), | 			MachineKey:     machineKey.Public(), | ||||||
| 			NodeKey:        "bar" + strconv.Itoa(index), | 			NodeKey:        nodeKey.Public(), | ||||||
| 			DiscoKey:       "faa" + strconv.Itoa(index), |  | ||||||
| 			Hostname:       "testnode" + strconv.Itoa(index), | 			Hostname:       "testnode" + strconv.Itoa(index), | ||||||
| 			UserID:         user.ID, | 			UserID:         user.ID, | ||||||
| 			RegisterMethod: util.RegisterMethodAuthKey, | 			RegisterMethod: util.RegisterMethodAuthKey, | ||||||
| @@ -205,11 +212,13 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) { | |||||||
| 	c.Assert(err, check.NotNil) | 	c.Assert(err, check.NotNil) | ||||||
|  |  | ||||||
| 	for index := 0; index <= 10; index++ { | 	for index := 0; index <= 10; index++ { | ||||||
|  | 		nodeKey := key.NewNode() | ||||||
|  | 		machineKey := key.NewMachine() | ||||||
|  |  | ||||||
| 		node := types.Node{ | 		node := types.Node{ | ||||||
| 			ID:         uint64(index), | 			ID:         uint64(index), | ||||||
| 			MachineKey: "foo" + strconv.Itoa(index), | 			MachineKey: machineKey.Public(), | ||||||
| 			NodeKey:    "bar" + strconv.Itoa(index), | 			NodeKey:    nodeKey.Public(), | ||||||
| 			DiscoKey:   "faa" + strconv.Itoa(index), |  | ||||||
| 			IPAddresses: types.NodeAddresses{ | 			IPAddresses: types.NodeAddresses{ | ||||||
| 				netip.MustParseAddr(fmt.Sprintf("100.64.0.%v", strconv.Itoa(index+1))), | 				netip.MustParseAddr(fmt.Sprintf("100.64.0.%v", strconv.Itoa(index+1))), | ||||||
| 			}, | 			}, | ||||||
| @@ -288,11 +297,13 @@ func (s *Suite) TestExpireNode(c *check.C) { | |||||||
| 	_, err = db.GetNode("test", "testnode") | 	_, err = db.GetNode("test", "testnode") | ||||||
| 	c.Assert(err, check.NotNil) | 	c.Assert(err, check.NotNil) | ||||||
|  |  | ||||||
|  | 	nodeKey := key.NewNode() | ||||||
|  | 	machineKey := key.NewMachine() | ||||||
|  |  | ||||||
| 	node := &types.Node{ | 	node := &types.Node{ | ||||||
| 		ID:             0, | 		ID:             0, | ||||||
| 		MachineKey:     "foo", | 		MachineKey:     machineKey.Public(), | ||||||
| 		NodeKey:        "bar", | 		NodeKey:        nodeKey.Public(), | ||||||
| 		DiscoKey:       "faa", |  | ||||||
| 		Hostname:       "testnode", | 		Hostname:       "testnode", | ||||||
| 		UserID:         user.ID, | 		UserID:         user.ID, | ||||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | 		RegisterMethod: util.RegisterMethodAuthKey, | ||||||
| @@ -345,11 +356,15 @@ func (s *Suite) TestGenerateGivenName(c *check.C) { | |||||||
| 	_, err = db.GetNode("user-1", "testnode") | 	_, err = db.GetNode("user-1", "testnode") | ||||||
| 	c.Assert(err, check.NotNil) | 	c.Assert(err, check.NotNil) | ||||||
|  |  | ||||||
|  | 	nodeKey := key.NewNode() | ||||||
|  | 	machineKey := key.NewMachine() | ||||||
|  |  | ||||||
|  | 	machineKey2 := key.NewMachine() | ||||||
|  |  | ||||||
| 	node := &types.Node{ | 	node := &types.Node{ | ||||||
| 		ID:             0, | 		ID:             0, | ||||||
| 		MachineKey:     "node-key-1", | 		MachineKey:     machineKey.Public(), | ||||||
| 		NodeKey:        "node-key-1", | 		NodeKey:        nodeKey.Public(), | ||||||
| 		DiscoKey:       "disco-key-1", |  | ||||||
| 		Hostname:       "hostname-1", | 		Hostname:       "hostname-1", | ||||||
| 		GivenName:      "hostname-1", | 		GivenName:      "hostname-1", | ||||||
| 		UserID:         user1.ID, | 		UserID:         user1.ID, | ||||||
| @@ -358,25 +373,20 @@ func (s *Suite) TestGenerateGivenName(c *check.C) { | |||||||
| 	} | 	} | ||||||
| 	db.db.Save(node) | 	db.db.Save(node) | ||||||
|  |  | ||||||
| 	givenName, err := db.GenerateGivenName("node-key-2", "hostname-2") | 	givenName, err := db.GenerateGivenName(machineKey2.Public(), "hostname-2") | ||||||
| 	comment := check.Commentf("Same user, unique nodes, unique hostnames, no conflict") | 	comment := check.Commentf("Same user, unique nodes, unique hostnames, no conflict") | ||||||
| 	c.Assert(err, check.IsNil, comment) | 	c.Assert(err, check.IsNil, comment) | ||||||
| 	c.Assert(givenName, check.Equals, "hostname-2", comment) | 	c.Assert(givenName, check.Equals, "hostname-2", comment) | ||||||
|  |  | ||||||
| 	givenName, err = db.GenerateGivenName("node-key-1", "hostname-1") | 	givenName, err = db.GenerateGivenName(machineKey.Public(), "hostname-1") | ||||||
| 	comment = check.Commentf("Same user, same node, same hostname, no conflict") | 	comment = check.Commentf("Same user, same node, same hostname, no conflict") | ||||||
| 	c.Assert(err, check.IsNil, comment) | 	c.Assert(err, check.IsNil, comment) | ||||||
| 	c.Assert(givenName, check.Equals, "hostname-1", comment) | 	c.Assert(givenName, check.Equals, "hostname-1", comment) | ||||||
|  |  | ||||||
| 	givenName, err = db.GenerateGivenName("node-key-2", "hostname-1") | 	givenName, err = db.GenerateGivenName(machineKey2.Public(), "hostname-1") | ||||||
| 	comment = check.Commentf("Same user, unique nodes, same hostname, conflict") | 	comment = check.Commentf("Same user, unique nodes, same hostname, conflict") | ||||||
| 	c.Assert(err, check.IsNil, comment) | 	c.Assert(err, check.IsNil, comment) | ||||||
| 	c.Assert(givenName, check.Matches, fmt.Sprintf("^hostname-1-[a-z0-9]{%d}$", NodeGivenNameHashLength), comment) | 	c.Assert(givenName, check.Matches, fmt.Sprintf("^hostname-1-[a-z0-9]{%d}$", NodeGivenNameHashLength), comment) | ||||||
|  |  | ||||||
| 	givenName, err = db.GenerateGivenName("node-key-2", "hostname-1") |  | ||||||
| 	comment = check.Commentf("Unique users, unique nodes, same hostname, conflict") |  | ||||||
| 	c.Assert(err, check.IsNil, comment) |  | ||||||
| 	c.Assert(givenName, check.Matches, fmt.Sprintf("^hostname-1-[a-z0-9]{%d}$", NodeGivenNameHashLength), comment) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *Suite) TestSetTags(c *check.C) { | func (s *Suite) TestSetTags(c *check.C) { | ||||||
| @@ -389,11 +399,13 @@ func (s *Suite) TestSetTags(c *check.C) { | |||||||
| 	_, err = db.GetNode("test", "testnode") | 	_, err = db.GetNode("test", "testnode") | ||||||
| 	c.Assert(err, check.NotNil) | 	c.Assert(err, check.NotNil) | ||||||
|  |  | ||||||
|  | 	nodeKey := key.NewNode() | ||||||
|  | 	machineKey := key.NewMachine() | ||||||
|  |  | ||||||
| 	node := &types.Node{ | 	node := &types.Node{ | ||||||
| 		ID:             0, | 		ID:             0, | ||||||
| 		MachineKey:     "foo", | 		MachineKey:     machineKey.Public(), | ||||||
| 		NodeKey:        "bar", | 		NodeKey:        nodeKey.Public(), | ||||||
| 		DiscoKey:       "faa", |  | ||||||
| 		Hostname:       "testnode", | 		Hostname:       "testnode", | ||||||
| 		UserID:         user.ID, | 		UserID:         user.ID, | ||||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | 		RegisterMethod: util.RegisterMethodAuthKey, | ||||||
| @@ -565,6 +577,7 @@ func (s *Suite) TestAutoApproveRoutes(c *check.C) { | |||||||
| 	c.Assert(err, check.IsNil) | 	c.Assert(err, check.IsNil) | ||||||
|  |  | ||||||
| 	nodeKey := key.NewNode() | 	nodeKey := key.NewNode() | ||||||
|  | 	machineKey := key.NewMachine() | ||||||
|  |  | ||||||
| 	defaultRouteV4 := netip.MustParsePrefix("0.0.0.0/0") | 	defaultRouteV4 := netip.MustParsePrefix("0.0.0.0/0") | ||||||
| 	defaultRouteV6 := netip.MustParsePrefix("::/0") | 	defaultRouteV6 := netip.MustParsePrefix("::/0") | ||||||
| @@ -574,9 +587,8 @@ func (s *Suite) TestAutoApproveRoutes(c *check.C) { | |||||||
|  |  | ||||||
| 	node := types.Node{ | 	node := types.Node{ | ||||||
| 		ID:             0, | 		ID:             0, | ||||||
| 		MachineKey:     "foo", | 		MachineKey:     machineKey.Public(), | ||||||
| 		NodeKey:        nodeKey.Public().String(), | 		NodeKey:        nodeKey.Public(), | ||||||
| 		DiscoKey:       "faa", |  | ||||||
| 		Hostname:       "test", | 		Hostname:       "test", | ||||||
| 		UserID:         user.ID, | 		UserID:         user.ID, | ||||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | 		RegisterMethod: util.RegisterMethodAuthKey, | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package db | package db | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"log" | ||||||
| 	"net/netip" | 	"net/netip" | ||||||
| 	"os" | 	"os" | ||||||
| 	"testing" | 	"testing" | ||||||
| @@ -27,19 +28,22 @@ func (s *Suite) SetUpTest(c *check.C) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (s *Suite) TearDownTest(c *check.C) { | func (s *Suite) TearDownTest(c *check.C) { | ||||||
| 	os.RemoveAll(tmpDir) | 	// os.RemoveAll(tmpDir) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *Suite) ResetDB(c *check.C) { | func (s *Suite) ResetDB(c *check.C) { | ||||||
| 	if len(tmpDir) != 0 { | 	// if len(tmpDir) != 0 { | ||||||
| 		os.RemoveAll(tmpDir) | 	// 	os.RemoveAll(tmpDir) | ||||||
| 	} | 	// } | ||||||
|  |  | ||||||
| 	var err error | 	var err error | ||||||
| 	tmpDir, err = os.MkdirTemp("", "autoygg-client-test") | 	tmpDir, err = os.MkdirTemp("", "headscale-db-test-*") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		c.Fatal(err) | 		c.Fatal(err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	log.Printf("database path: %s", tmpDir+"/headscale_test.db") | ||||||
|  |  | ||||||
| 	db, err = NewHeadscaleDatabase( | 	db, err = NewHeadscaleDatabase( | ||||||
| 		"sqlite3", | 		"sqlite3", | ||||||
| 		tmpDir+"/headscale_test.db", | 		tmpDir+"/headscale_test.db", | ||||||
|   | |||||||
| @@ -172,12 +172,18 @@ func (api headscaleV1APIServer) RegisterNode( | |||||||
| ) (*v1.RegisterNodeResponse, error) { | ) (*v1.RegisterNodeResponse, error) { | ||||||
| 	log.Trace(). | 	log.Trace(). | ||||||
| 		Str("user", request.GetUser()). | 		Str("user", request.GetUser()). | ||||||
| 		Str("node_key", request.GetKey()). | 		Str("machine_key", request.GetKey()). | ||||||
| 		Msg("Registering node") | 		Msg("Registering node") | ||||||
|  |  | ||||||
|  | 	var mkey key.MachinePublic | ||||||
|  | 	err := mkey.UnmarshalText([]byte(request.GetKey())) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	node, err := api.h.db.RegisterNodeFromAuthCallback( | 	node, err := api.h.db.RegisterNodeFromAuthCallback( | ||||||
| 		api.h.registrationCache, | 		api.h.registrationCache, | ||||||
| 		request.GetKey(), | 		mkey, | ||||||
| 		request.GetUser(), | 		request.GetUser(), | ||||||
| 		nil, | 		nil, | ||||||
| 		util.RegisterMethodCLI, | 		util.RegisterMethodCLI, | ||||||
| @@ -521,13 +527,22 @@ func (api headscaleV1APIServer) DebugCreateNode( | |||||||
| 		Hostname:    "DebugTestNode", | 		Hostname:    "DebugTestNode", | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	givenName, err := api.h.db.GenerateGivenName(request.GetKey(), request.GetName()) | 	var mkey key.MachinePublic | ||||||
|  | 	err = mkey.UnmarshalText([]byte(request.GetKey())) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	givenName, err := api.h.db.GenerateGivenName(mkey, request.GetName()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	nodeKey := key.NewNode() | ||||||
|  |  | ||||||
| 	newNode := types.Node{ | 	newNode := types.Node{ | ||||||
| 		MachineKey: request.GetKey(), | 		MachineKey: mkey, | ||||||
|  | 		NodeKey:    nodeKey.Public(), | ||||||
| 		Hostname:   request.GetName(), | 		Hostname:   request.GetName(), | ||||||
| 		GivenName:  givenName, | 		GivenName:  givenName, | ||||||
| 		User:       *user, | 		User:       *user, | ||||||
| @@ -538,14 +553,12 @@ func (api headscaleV1APIServer) DebugCreateNode( | |||||||
| 		HostInfo: types.HostInfo(hostinfo), | 		HostInfo: types.HostInfo(hostinfo), | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	nodeKey := key.NodePublic{} | 	log.Debug(). | ||||||
| 	err = nodeKey.UnmarshalText([]byte(request.GetKey())) | 		Str("machine_key", mkey.ShortString()). | ||||||
| 	if err != nil { | 		Msg("adding debug machine via CLI, appending to registration cache") | ||||||
| 		log.Panic().Msg("can not add node for debug. invalid node key") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	api.h.registrationCache.Set( | 	api.h.registrationCache.Set( | ||||||
| 		nodeKey.String(), | 		mkey.String(), | ||||||
| 		newNode, | 		newNode, | ||||||
| 		registerCacheExpiration, | 		registerCacheExpiration, | ||||||
| 	) | 	) | ||||||
|   | |||||||
| @@ -12,7 +12,6 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/gorilla/mux" | 	"github.com/gorilla/mux" | ||||||
| 	"github.com/juanfont/headscale/hscontrol/util" |  | ||||||
| 	"github.com/rs/zerolog/log" | 	"github.com/rs/zerolog/log" | ||||||
| 	"tailscale.com/tailcfg" | 	"tailscale.com/tailcfg" | ||||||
| 	"tailscale.com/types/key" | 	"tailscale.com/types/key" | ||||||
| @@ -207,33 +206,16 @@ func (h *Headscale) RegisterWebAPI( | |||||||
| 	req *http.Request, | 	req *http.Request, | ||||||
| ) { | ) { | ||||||
| 	vars := mux.Vars(req) | 	vars := mux.Vars(req) | ||||||
| 	nodeKeyStr, ok := vars["nkey"] | 	machineKeyStr := vars["mkey"] | ||||||
|  |  | ||||||
| 	if !util.NodePublicKeyRegex.Match([]byte(nodeKeyStr)) { |  | ||||||
| 		log.Warn().Str("node_key", nodeKeyStr).Msg("Invalid node key passed to registration url") |  | ||||||
|  |  | ||||||
| 		writer.Header().Set("Content-Type", "text/plain; charset=utf-8") |  | ||||||
| 		writer.WriteHeader(http.StatusUnauthorized) |  | ||||||
| 		_, err := writer.Write([]byte("Unauthorized")) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Error(). |  | ||||||
| 				Caller(). |  | ||||||
| 				Err(err). |  | ||||||
| 				Msg("Failed to write response") |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// We need to make sure we dont open for XSS style injections, if the parameter that | 	// We need to make sure we dont open for XSS style injections, if the parameter that | ||||||
| 	// is passed as a key is not parsable/validated as a NodePublic key, then fail to render | 	// is passed as a key is not parsable/validated as a NodePublic key, then fail to render | ||||||
| 	// the template and log an error. | 	// the template and log an error. | ||||||
| 	var nodeKey key.NodePublic | 	var machineKey key.MachinePublic | ||||||
| 	err := nodeKey.UnmarshalText( | 	err := machineKey.UnmarshalText( | ||||||
| 		[]byte(nodeKeyStr), | 		[]byte(machineKeyStr), | ||||||
| 	) | 	) | ||||||
|  | 	if err != nil { | ||||||
| 	if !ok || nodeKeyStr == "" || err != nil { |  | ||||||
| 		log.Warn().Err(err).Msg("Failed to parse incoming nodekey") | 		log.Warn().Err(err).Msg("Failed to parse incoming nodekey") | ||||||
|  |  | ||||||
| 		writer.Header().Set("Content-Type", "text/plain; charset=utf-8") | 		writer.Header().Set("Content-Type", "text/plain; charset=utf-8") | ||||||
| @@ -251,7 +233,7 @@ func (h *Headscale) RegisterWebAPI( | |||||||
|  |  | ||||||
| 	var content bytes.Buffer | 	var content bytes.Buffer | ||||||
| 	if err := registerWebAPITemplate.Execute(&content, registerWebAPITemplateConfig{ | 	if err := registerWebAPITemplate.Execute(&content, registerWebAPITemplateConfig{ | ||||||
| 		Key: nodeKeyStr, | 		Key: machineKey.String(), | ||||||
| 	}); err != nil { | 	}); err != nil { | ||||||
| 		log.Error(). | 		log.Error(). | ||||||
| 			Str("func", "RegisterWebAPI"). | 			Str("func", "RegisterWebAPI"). | ||||||
|   | |||||||
| @@ -368,17 +368,6 @@ func (m *Mapper) marshalMapResponse( | |||||||
| ) ([]byte, error) { | ) ([]byte, error) { | ||||||
| 	atomic.AddUint64(&m.seq, 1) | 	atomic.AddUint64(&m.seq, 1) | ||||||
|  |  | ||||||
| 	var machineKey key.MachinePublic |  | ||||||
| 	err := machineKey.UnmarshalText([]byte(node.MachineKey)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Error(). |  | ||||||
| 			Caller(). |  | ||||||
| 			Err(err). |  | ||||||
| 			Msg("Cannot parse client key") |  | ||||||
|  |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	jsonBody, err := json.Marshal(resp) | 	jsonBody, err := json.Marshal(resp) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Error(). | 		log.Error(). | ||||||
| @@ -426,11 +415,11 @@ func (m *Mapper) marshalMapResponse( | |||||||
| 	if compression == util.ZstdCompression { | 	if compression == util.ZstdCompression { | ||||||
| 		respBody = zstdEncode(jsonBody) | 		respBody = zstdEncode(jsonBody) | ||||||
| 		if !m.isNoise { // if legacy protocol | 		if !m.isNoise { // if legacy protocol | ||||||
| 			respBody = m.privateKey2019.SealTo(machineKey, respBody) | 			respBody = m.privateKey2019.SealTo(node.MachineKey, respBody) | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		if !m.isNoise { // if legacy protocol | 		if !m.isNoise { // if legacy protocol | ||||||
| 			respBody = m.privateKey2019.SealTo(machineKey, jsonBody) | 			respBody = m.privateKey2019.SealTo(node.MachineKey, jsonBody) | ||||||
| 		} else { | 		} else { | ||||||
| 			respBody = jsonBody | 			respBody = jsonBody | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -167,9 +167,15 @@ func Test_fullMapResponse(t *testing.T) { | |||||||
|  |  | ||||||
| 	mini := &types.Node{ | 	mini := &types.Node{ | ||||||
| 		ID: 0, | 		ID: 0, | ||||||
| 		MachineKey:  "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | 		MachineKey: mustMK( | ||||||
| 		NodeKey:     "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | 			"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||||
| 		DiscoKey:    "discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | 		), | ||||||
|  | 		NodeKey: mustNK( | ||||||
|  | 			"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||||
|  | 		), | ||||||
|  | 		DiscoKey: mustDK( | ||||||
|  | 			"discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||||
|  | 		), | ||||||
| 		IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")}, | 		IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")}, | ||||||
| 		Hostname:    "mini", | 		Hostname:    "mini", | ||||||
| 		GivenName:   "mini", | 		GivenName:   "mini", | ||||||
| @@ -226,7 +232,6 @@ func Test_fullMapResponse(t *testing.T) { | |||||||
| 			netip.MustParsePrefix("0.0.0.0/0"), | 			netip.MustParsePrefix("0.0.0.0/0"), | ||||||
| 			netip.MustParsePrefix("192.168.0.0/24"), | 			netip.MustParsePrefix("192.168.0.0/24"), | ||||||
| 		}, | 		}, | ||||||
| 		Endpoints:         []string{}, |  | ||||||
| 		DERP:              "127.3.3.40:0", | 		DERP:              "127.3.3.40:0", | ||||||
| 		Hostinfo:          hiview(tailcfg.Hostinfo{}), | 		Hostinfo:          hiview(tailcfg.Hostinfo{}), | ||||||
| 		Created:           created, | 		Created:           created, | ||||||
| @@ -245,9 +250,15 @@ func Test_fullMapResponse(t *testing.T) { | |||||||
|  |  | ||||||
| 	peer1 := &types.Node{ | 	peer1 := &types.Node{ | ||||||
| 		ID: 1, | 		ID: 1, | ||||||
| 		MachineKey:  "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | 		MachineKey: mustMK( | ||||||
| 		NodeKey:     "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | 			"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||||
| 		DiscoKey:    "discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | 		), | ||||||
|  | 		NodeKey: mustNK( | ||||||
|  | 			"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||||
|  | 		), | ||||||
|  | 		DiscoKey: mustDK( | ||||||
|  | 			"discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||||
|  | 		), | ||||||
| 		IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")}, | 		IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")}, | ||||||
| 		Hostname:    "peer1", | 		Hostname:    "peer1", | ||||||
| 		GivenName:   "peer1", | 		GivenName:   "peer1", | ||||||
| @@ -278,7 +289,6 @@ func Test_fullMapResponse(t *testing.T) { | |||||||
| 		), | 		), | ||||||
| 		Addresses:         []netip.Prefix{netip.MustParsePrefix("100.64.0.2/32")}, | 		Addresses:         []netip.Prefix{netip.MustParsePrefix("100.64.0.2/32")}, | ||||||
| 		AllowedIPs:        []netip.Prefix{netip.MustParsePrefix("100.64.0.2/32")}, | 		AllowedIPs:        []netip.Prefix{netip.MustParsePrefix("100.64.0.2/32")}, | ||||||
| 		Endpoints:         []string{}, |  | ||||||
| 		DERP:              "127.3.3.40:0", | 		DERP:              "127.3.3.40:0", | ||||||
| 		Hostinfo:          hiview(tailcfg.Hostinfo{}), | 		Hostinfo:          hiview(tailcfg.Hostinfo{}), | ||||||
| 		Created:           created, | 		Created:           created, | ||||||
| @@ -297,9 +307,15 @@ func Test_fullMapResponse(t *testing.T) { | |||||||
|  |  | ||||||
| 	peer2 := &types.Node{ | 	peer2 := &types.Node{ | ||||||
| 		ID: 2, | 		ID: 2, | ||||||
| 		MachineKey:  "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | 		MachineKey: mustMK( | ||||||
| 		NodeKey:     "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | 			"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||||
| 		DiscoKey:    "discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | 		), | ||||||
|  | 		NodeKey: mustNK( | ||||||
|  | 			"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||||
|  | 		), | ||||||
|  | 		DiscoKey: mustDK( | ||||||
|  | 			"discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||||
|  | 		), | ||||||
| 		IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")}, | 		IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")}, | ||||||
| 		Hostname:    "peer2", | 		Hostname:    "peer2", | ||||||
| 		GivenName:   "peer2", | 		GivenName:   "peer2", | ||||||
|   | |||||||
| @@ -52,21 +52,6 @@ func tailNode( | |||||||
| 	baseDomain string, | 	baseDomain string, | ||||||
| 	randomClientPort bool, | 	randomClientPort bool, | ||||||
| ) (*tailcfg.Node, error) { | ) (*tailcfg.Node, error) { | ||||||
| 	nodeKey, err := node.NodePublicKey() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	machineKey, err := node.MachinePublicKey() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	discoKey, err := node.DiscoPublicKey() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	addrs := node.IPAddresses.Prefixes() | 	addrs := node.IPAddresses.Prefixes() | ||||||
|  |  | ||||||
| 	allowedIPs := append( | 	allowedIPs := append( | ||||||
| @@ -112,6 +97,11 @@ func tailNode( | |||||||
| 	tags, _ := pol.TagsOfNode(node) | 	tags, _ := pol.TagsOfNode(node) | ||||||
| 	tags = lo.Uniq(append(tags, node.ForcedTags...)) | 	tags = lo.Uniq(append(tags, node.ForcedTags...)) | ||||||
|  |  | ||||||
|  | 	endpoints, err := node.EndpointsToAddrPort() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	tNode := tailcfg.Node{ | 	tNode := tailcfg.Node{ | ||||||
| 		ID: tailcfg.NodeID(node.ID), // this is the actual ID | 		ID: tailcfg.NodeID(node.ID), // this is the actual ID | ||||||
| 		StableID: tailcfg.StableNodeID( | 		StableID: tailcfg.StableNodeID( | ||||||
| @@ -121,14 +111,14 @@ func tailNode( | |||||||
|  |  | ||||||
| 		User: tailcfg.UserID(node.UserID), | 		User: tailcfg.UserID(node.UserID), | ||||||
|  |  | ||||||
| 		Key:       nodeKey, | 		Key:       node.NodeKey, | ||||||
| 		KeyExpiry: keyExpiry, | 		KeyExpiry: keyExpiry, | ||||||
|  |  | ||||||
| 		Machine:    machineKey, | 		Machine:    node.MachineKey, | ||||||
| 		DiscoKey:   discoKey, | 		DiscoKey:   node.DiscoKey, | ||||||
| 		Addresses:  addrs, | 		Addresses:  addrs, | ||||||
| 		AllowedIPs: allowedIPs, | 		AllowedIPs: allowedIPs, | ||||||
| 		Endpoints:  node.Endpoints, | 		Endpoints:  endpoints, | ||||||
| 		DERP:       derp, | 		DERP:       derp, | ||||||
| 		Hostinfo:   hostInfo.View(), | 		Hostinfo:   hostInfo.View(), | ||||||
| 		Created:    node.CreatedAt, | 		Created:    node.CreatedAt, | ||||||
|   | |||||||
| @@ -58,16 +58,36 @@ func TestTailNode(t *testing.T) { | |||||||
| 			pol:        &policy.ACLPolicy{}, | 			pol:        &policy.ACLPolicy{}, | ||||||
| 			dnsConfig:  &tailcfg.DNSConfig{}, | 			dnsConfig:  &tailcfg.DNSConfig{}, | ||||||
| 			baseDomain: "", | 			baseDomain: "", | ||||||
| 			want:       nil, | 			want: &tailcfg.Node{ | ||||||
| 			wantErr:    true, | 				StableID:          "0", | ||||||
|  | 				Addresses:         []netip.Prefix{}, | ||||||
|  | 				AllowedIPs:        []netip.Prefix{}, | ||||||
|  | 				DERP:              "127.3.3.40:0", | ||||||
|  | 				Hostinfo:          hiview(tailcfg.Hostinfo{}), | ||||||
|  | 				Tags:              []string{}, | ||||||
|  | 				PrimaryRoutes:     []netip.Prefix{}, | ||||||
|  | 				Online:            new(bool), | ||||||
|  | 				MachineAuthorized: true, | ||||||
|  | 				Capabilities: []tailcfg.NodeCapability{ | ||||||
|  | 					"https://tailscale.com/cap/file-sharing", "https://tailscale.com/cap/is-admin", | ||||||
|  | 					"https://tailscale.com/cap/ssh", "debug-disable-upnp", | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			wantErr: false, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "minimal-node", | 			name: "minimal-node", | ||||||
| 			node: &types.Node{ | 			node: &types.Node{ | ||||||
| 				ID: 0, | 				ID: 0, | ||||||
| 				MachineKey: "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | 				MachineKey: mustMK( | ||||||
| 				NodeKey:    "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | 					"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||||
| 				DiscoKey:   "discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | 				), | ||||||
|  | 				NodeKey: mustNK( | ||||||
|  | 					"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||||
|  | 				), | ||||||
|  | 				DiscoKey: mustDK( | ||||||
|  | 					"discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||||
|  | 				), | ||||||
| 				IPAddresses: []netip.Addr{ | 				IPAddresses: []netip.Addr{ | ||||||
| 					netip.MustParseAddr("100.64.0.1"), | 					netip.MustParseAddr("100.64.0.1"), | ||||||
| 				}, | 				}, | ||||||
| @@ -133,7 +153,6 @@ func TestTailNode(t *testing.T) { | |||||||
| 					netip.MustParsePrefix("0.0.0.0/0"), | 					netip.MustParsePrefix("0.0.0.0/0"), | ||||||
| 					netip.MustParsePrefix("192.168.0.0/24"), | 					netip.MustParsePrefix("192.168.0.0/24"), | ||||||
| 				}, | 				}, | ||||||
| 				Endpoints: []string{}, |  | ||||||
| 				DERP:     "127.3.3.40:0", | 				DERP:     "127.3.3.40:0", | ||||||
| 				Hostinfo: hiview(tailcfg.Hostinfo{}), | 				Hostinfo: hiview(tailcfg.Hostinfo{}), | ||||||
| 				Created:  created, | 				Created:  created, | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import ( | |||||||
| 	"github.com/juanfont/headscale/hscontrol/types" | 	"github.com/juanfont/headscale/hscontrol/types" | ||||||
| 	"github.com/juanfont/headscale/hscontrol/util" | 	"github.com/juanfont/headscale/hscontrol/util" | ||||||
| 	"github.com/rs/zerolog/log" | 	"github.com/rs/zerolog/log" | ||||||
|  | 	"tailscale.com/types/key" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Notifier struct { | type Notifier struct { | ||||||
| @@ -17,9 +18,9 @@ func NewNotifier() *Notifier { | |||||||
| 	return &Notifier{} | 	return &Notifier{} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (n *Notifier) AddNode(machineKey string, c chan<- types.StateUpdate) { | func (n *Notifier) AddNode(machineKey key.MachinePublic, c chan<- types.StateUpdate) { | ||||||
| 	log.Trace().Caller().Str("key", machineKey).Msg("acquiring lock to add node") | 	log.Trace().Caller().Str("key", machineKey.ShortString()).Msg("acquiring lock to add node") | ||||||
| 	defer log.Trace().Caller().Str("key", machineKey).Msg("releasing lock to add node") | 	defer log.Trace().Caller().Str("key", machineKey.ShortString()).Msg("releasing lock to add node") | ||||||
|  |  | ||||||
| 	n.l.Lock() | 	n.l.Lock() | ||||||
| 	defer n.l.Unlock() | 	defer n.l.Unlock() | ||||||
| @@ -28,17 +29,17 @@ func (n *Notifier) AddNode(machineKey string, c chan<- types.StateUpdate) { | |||||||
| 		n.nodes = make(map[string]chan<- types.StateUpdate) | 		n.nodes = make(map[string]chan<- types.StateUpdate) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	n.nodes[machineKey] = c | 	n.nodes[machineKey.String()] = c | ||||||
|  |  | ||||||
| 	log.Trace(). | 	log.Trace(). | ||||||
| 		Str("machine_key", machineKey). | 		Str("machine_key", machineKey.ShortString()). | ||||||
| 		Int("open_chans", len(n.nodes)). | 		Int("open_chans", len(n.nodes)). | ||||||
| 		Msg("Added new channel") | 		Msg("Added new channel") | ||||||
| } | } | ||||||
|  |  | ||||||
| func (n *Notifier) RemoveNode(machineKey string) { | func (n *Notifier) RemoveNode(machineKey key.MachinePublic) { | ||||||
| 	log.Trace().Caller().Str("key", machineKey).Msg("acquiring lock to remove node") | 	log.Trace().Caller().Str("key", machineKey.ShortString()).Msg("acquiring lock to remove node") | ||||||
| 	defer log.Trace().Caller().Str("key", machineKey).Msg("releasing lock to remove node") | 	defer log.Trace().Caller().Str("key", machineKey.ShortString()).Msg("releasing lock to remove node") | ||||||
|  |  | ||||||
| 	n.l.Lock() | 	n.l.Lock() | ||||||
| 	defer n.l.Unlock() | 	defer n.l.Unlock() | ||||||
| @@ -47,10 +48,10 @@ func (n *Notifier) RemoveNode(machineKey string) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	delete(n.nodes, machineKey) | 	delete(n.nodes, machineKey.String()) | ||||||
|  |  | ||||||
| 	log.Trace(). | 	log.Trace(). | ||||||
| 		Str("machine_key", machineKey). | 		Str("machine_key", machineKey.ShortString()). | ||||||
| 		Int("open_chans", len(n.nodes)). | 		Int("open_chans", len(n.nodes)). | ||||||
| 		Msg("Removed channel") | 		Msg("Removed channel") | ||||||
| } | } | ||||||
|   | |||||||
| @@ -90,42 +90,28 @@ func (h *Headscale) determineTokenExpiration(idTokenExpiration time.Time) time.T | |||||||
|  |  | ||||||
| // RegisterOIDC redirects to the OIDC provider for authentication | // RegisterOIDC redirects to the OIDC provider for authentication | ||||||
| // Puts NodeKey in cache so the callback can retrieve it using the oidc state param | // Puts NodeKey in cache so the callback can retrieve it using the oidc state param | ||||||
| // Listens in /oidc/register/:nKey. | // Listens in /oidc/register/:mKey. | ||||||
| func (h *Headscale) RegisterOIDC( | func (h *Headscale) RegisterOIDC( | ||||||
| 	writer http.ResponseWriter, | 	writer http.ResponseWriter, | ||||||
| 	req *http.Request, | 	req *http.Request, | ||||||
| ) { | ) { | ||||||
| 	vars := mux.Vars(req) | 	vars := mux.Vars(req) | ||||||
| 	nodeKeyStr, ok := vars["nkey"] | 	machineKeyStr, ok := vars["mkey"] | ||||||
|  |  | ||||||
| 	log.Debug(). | 	log.Debug(). | ||||||
| 		Caller(). | 		Caller(). | ||||||
| 		Str("node_key", nodeKeyStr). | 		Str("machine_key", machineKeyStr). | ||||||
| 		Bool("ok", ok). | 		Bool("ok", ok). | ||||||
| 		Msg("Received oidc register call") | 		Msg("Received oidc register call") | ||||||
|  |  | ||||||
| 	if !util.NodePublicKeyRegex.Match([]byte(nodeKeyStr)) { |  | ||||||
| 		log.Warn().Str("node_key", nodeKeyStr).Msg("Invalid node key passed to registration url") |  | ||||||
|  |  | ||||||
| 		writer.Header().Set("Content-Type", "text/plain; charset=utf-8") |  | ||||||
| 		writer.WriteHeader(http.StatusUnauthorized) |  | ||||||
| 		_, err := writer.Write([]byte("Unauthorized")) |  | ||||||
| 		if err != nil { |  | ||||||
| 			util.LogErr(err, "Failed to write response") |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// We need to make sure we dont open for XSS style injections, if the parameter that | 	// We need to make sure we dont open for XSS style injections, if the parameter that | ||||||
| 	// is passed as a key is not parsable/validated as a NodePublic key, then fail to render | 	// is passed as a key is not parsable/validated as a NodePublic key, then fail to render | ||||||
| 	// the template and log an error. | 	// the template and log an error. | ||||||
| 	var nodeKey key.NodePublic | 	var machineKey key.MachinePublic | ||||||
| 	err := nodeKey.UnmarshalText( | 	err := machineKey.UnmarshalText( | ||||||
| 		[]byte(nodeKeyStr), | 		[]byte(machineKeyStr), | ||||||
| 	) | 	) | ||||||
|  | 	if err != nil { | ||||||
| 	if !ok || nodeKeyStr == "" || err != nil { |  | ||||||
| 		log.Warn(). | 		log.Warn(). | ||||||
| 			Err(err). | 			Err(err). | ||||||
| 			Msg("Failed to parse incoming nodekey in OIDC registration") | 			Msg("Failed to parse incoming nodekey in OIDC registration") | ||||||
| @@ -154,7 +140,7 @@ func (h *Headscale) RegisterOIDC( | |||||||
| 	// place the node key into the state cache, so it can be retrieved later | 	// place the node key into the state cache, so it can be retrieved later | ||||||
| 	h.registrationCache.Set( | 	h.registrationCache.Set( | ||||||
| 		stateStr, | 		stateStr, | ||||||
| 		nodeKey, | 		machineKey, | ||||||
| 		registerCacheExpiration, | 		registerCacheExpiration, | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
| @@ -232,7 +218,7 @@ func (h *Headscale) OIDCCallback( | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	nodeKey, nodeExists, err := h.validateNodeForOIDCCallback( | 	machineKey, nodeExists, err := h.validateNodeForOIDCCallback( | ||||||
| 		writer, | 		writer, | ||||||
| 		state, | 		state, | ||||||
| 		claims, | 		claims, | ||||||
| @@ -255,7 +241,7 @@ func (h *Headscale) OIDCCallback( | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err := h.registerNodeForOIDCCallback(writer, user, nodeKey, idTokenExpiry); err != nil { | 	if err := h.registerNodeForOIDCCallback(writer, user, machineKey, idTokenExpiry); err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -462,10 +448,10 @@ func (h *Headscale) validateNodeForOIDCCallback( | |||||||
| 	state string, | 	state string, | ||||||
| 	claims *IDTokenClaims, | 	claims *IDTokenClaims, | ||||||
| 	expiry time.Time, | 	expiry time.Time, | ||||||
| ) (*key.NodePublic, bool, error) { | ) (*key.MachinePublic, bool, error) { | ||||||
| 	// retrieve nodekey from state cache | 	// retrieve nodekey from state cache | ||||||
| 	nodeKeyIf, nodeKeyFound := h.registrationCache.Get(state) | 	machineKeyIf, machineKeyFound := h.registrationCache.Get(state) | ||||||
| 	if !nodeKeyFound { | 	if !machineKeyFound { | ||||||
| 		log.Trace(). | 		log.Trace(). | ||||||
| 			Msg("requested node state key expired before authorisation completed") | 			Msg("requested node state key expired before authorisation completed") | ||||||
| 		writer.Header().Set("Content-Type", "text/plain; charset=utf-8") | 		writer.Header().Set("Content-Type", "text/plain; charset=utf-8") | ||||||
| @@ -478,11 +464,11 @@ func (h *Headscale) validateNodeForOIDCCallback( | |||||||
| 		return nil, false, errOIDCNodeKeyMissing | 		return nil, false, errOIDCNodeKeyMissing | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var nodeKey key.NodePublic | 	var machineKey key.MachinePublic | ||||||
| 	nodeKey, nodeKeyOK := nodeKeyIf.(key.NodePublic) | 	machineKey, machineKeyOK := machineKeyIf.(key.MachinePublic) | ||||||
| 	if !nodeKeyOK { | 	if !machineKeyOK { | ||||||
| 		log.Trace(). | 		log.Trace(). | ||||||
| 			Interface("got", nodeKeyIf). | 			Interface("got", machineKeyIf). | ||||||
| 			Msg("requested node state key is not a nodekey") | 			Msg("requested node state key is not a nodekey") | ||||||
| 		writer.Header().Set("Content-Type", "text/plain; charset=utf-8") | 		writer.Header().Set("Content-Type", "text/plain; charset=utf-8") | ||||||
| 		writer.WriteHeader(http.StatusBadRequest) | 		writer.WriteHeader(http.StatusBadRequest) | ||||||
| @@ -498,7 +484,7 @@ func (h *Headscale) validateNodeForOIDCCallback( | |||||||
| 	// The error is not important, because if it does not | 	// The error is not important, because if it does not | ||||||
| 	// exist, then this is a new node and we will move | 	// exist, then this is a new node and we will move | ||||||
| 	// on to registration. | 	// on to registration. | ||||||
| 	node, _ := h.db.GetNodeByNodeKey(nodeKey) | 	node, _ := h.db.GetNodeByMachineKey(machineKey) | ||||||
|  |  | ||||||
| 	if node != nil { | 	if node != nil { | ||||||
| 		log.Trace(). | 		log.Trace(). | ||||||
| @@ -553,7 +539,7 @@ func (h *Headscale) validateNodeForOIDCCallback( | |||||||
| 		return nil, true, nil | 		return nil, true, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return &nodeKey, false, nil | 	return &machineKey, false, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func getUserName( | func getUserName( | ||||||
| @@ -624,13 +610,13 @@ func (h *Headscale) findOrCreateNewUserForOIDCCallback( | |||||||
| func (h *Headscale) registerNodeForOIDCCallback( | func (h *Headscale) registerNodeForOIDCCallback( | ||||||
| 	writer http.ResponseWriter, | 	writer http.ResponseWriter, | ||||||
| 	user *types.User, | 	user *types.User, | ||||||
| 	nodeKey *key.NodePublic, | 	machineKey *key.MachinePublic, | ||||||
| 	expiry time.Time, | 	expiry time.Time, | ||||||
| ) error { | ) error { | ||||||
| 	if _, err := h.db.RegisterNodeFromAuthCallback( | 	if _, err := h.db.RegisterNodeFromAuthCallback( | ||||||
| 		// TODO(kradalby): find a better way to use the cache across modules | 		// TODO(kradalby): find a better way to use the cache across modules | ||||||
| 		h.registrationCache, | 		h.registrationCache, | ||||||
| 		nodeKey.String(), | 		*machineKey, | ||||||
| 		user.Name, | 		user.Name, | ||||||
| 		&expiry, | 		&expiry, | ||||||
| 		util.RegisterMethodOIDC, | 		util.RegisterMethodOIDC, | ||||||
|   | |||||||
| @@ -14,12 +14,29 @@ import ( | |||||||
| 	"go4.org/netipx" | 	"go4.org/netipx" | ||||||
| 	"gopkg.in/check.v1" | 	"gopkg.in/check.v1" | ||||||
| 	"tailscale.com/tailcfg" | 	"tailscale.com/tailcfg" | ||||||
|  | 	"tailscale.com/types/key" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ipComparer = cmp.Comparer(func(x, y netip.Addr) bool { | var ipComparer = cmp.Comparer(func(x, y netip.Addr) bool { | ||||||
| 	return x.Compare(y) == 0 | 	return x.Compare(y) == 0 | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  | var mkeyComparer = cmp.Comparer(func(x, y key.MachinePublic) bool { | ||||||
|  | 	return x.String() == y.String() | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | var nkeyComparer = cmp.Comparer(func(x, y key.NodePublic) bool { | ||||||
|  | 	return x.String() == y.String() | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | var dkeyComparer = cmp.Comparer(func(x, y key.DiscoPublic) bool { | ||||||
|  | 	return x.String() == y.String() | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | var keyComparers []cmp.Option = []cmp.Option{ | ||||||
|  | 	mkeyComparer, nkeyComparer, dkeyComparer, | ||||||
|  | } | ||||||
|  |  | ||||||
| func Test(t *testing.T) { | func Test(t *testing.T) { | ||||||
| 	check.TestingT(t) | 	check.TestingT(t) | ||||||
| } | } | ||||||
| @@ -951,7 +968,7 @@ func Test_listNodesInUser(t *testing.T) { | |||||||
| 		t.Run(test.name, func(t *testing.T) { | 		t.Run(test.name, func(t *testing.T) { | ||||||
| 			got := filterNodesByUser(test.args.nodes, test.args.user) | 			got := filterNodesByUser(test.args.nodes, test.args.user) | ||||||
|  |  | ||||||
| 			if diff := cmp.Diff(test.want, got); diff != "" { | 			if diff := cmp.Diff(test.want, got, keyComparers...); diff != "" { | ||||||
| 				t.Errorf("listNodesInUser() = (-want +got):\n%s", diff) | 				t.Errorf("listNodesInUser() = (-want +got):\n%s", diff) | ||||||
| 			} | 			} | ||||||
| 		}) | 		}) | ||||||
| @@ -1704,7 +1721,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) { | |||||||
| 				test.args.nodes, | 				test.args.nodes, | ||||||
| 				test.args.user, | 				test.args.user, | ||||||
| 			) | 			) | ||||||
| 			if diff := cmp.Diff(test.want, got, ipComparer); diff != "" { | 			if diff := cmp.Diff(test.want, got, ipComparer, mkeyComparer, nkeyComparer, dkeyComparer); diff != "" { | ||||||
| 				t.Errorf("excludeCorrectlyTaggedNodes() (-want +got):\n%s", diff) | 				t.Errorf("excludeCorrectlyTaggedNodes() (-want +got):\n%s", diff) | ||||||
| 			} | 			} | ||||||
| 		}) | 		}) | ||||||
| @@ -2723,7 +2740,7 @@ func Test_getFilteredByACLPeers(t *testing.T) { | |||||||
| 				tt.args.nodes, | 				tt.args.nodes, | ||||||
| 				tt.args.rules, | 				tt.args.rules, | ||||||
| 			) | 			) | ||||||
| 			if diff := cmp.Diff(tt.want, got, ipComparer); diff != "" { | 			if diff := cmp.Diff(tt.want, got, ipComparer, mkeyComparer, nkeyComparer, dkeyComparer); diff != "" { | ||||||
| 				t.Errorf("FilterNodesByACL() unexpected result (-want +got):\n%s", diff) | 				t.Errorf("FilterNodesByACL() unexpected result (-want +got):\n%s", diff) | ||||||
| 			} | 			} | ||||||
| 		}) | 		}) | ||||||
| @@ -2986,9 +3003,6 @@ func TestValidExpandTagOwnersInSources(t *testing.T) { | |||||||
|  |  | ||||||
| 	node := &types.Node{ | 	node := &types.Node{ | ||||||
| 		ID:          0, | 		ID:          0, | ||||||
| 		MachineKey:  "foo", |  | ||||||
| 		NodeKey:     "bar", |  | ||||||
| 		DiscoKey:    "faa", |  | ||||||
| 		Hostname:    "testnodes", | 		Hostname:    "testnodes", | ||||||
| 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.1")}, | 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.1")}, | ||||||
| 		UserID:      0, | 		UserID:      0, | ||||||
| @@ -3041,9 +3055,6 @@ func TestInvalidTagValidUser(t *testing.T) { | |||||||
|  |  | ||||||
| 	node := &types.Node{ | 	node := &types.Node{ | ||||||
| 		ID:          1, | 		ID:          1, | ||||||
| 		MachineKey:  "12345", |  | ||||||
| 		NodeKey:     "bar", |  | ||||||
| 		DiscoKey:    "faa", |  | ||||||
| 		Hostname:    "testnodes", | 		Hostname:    "testnodes", | ||||||
| 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.1")}, | 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.1")}, | ||||||
| 		UserID:      1, | 		UserID:      1, | ||||||
| @@ -3095,9 +3106,6 @@ func TestValidExpandTagOwnersInDestinations(t *testing.T) { | |||||||
|  |  | ||||||
| 	node := &types.Node{ | 	node := &types.Node{ | ||||||
| 		ID:          1, | 		ID:          1, | ||||||
| 		MachineKey:  "12345", |  | ||||||
| 		NodeKey:     "bar", |  | ||||||
| 		DiscoKey:    "faa", |  | ||||||
| 		Hostname:    "testnodes", | 		Hostname:    "testnodes", | ||||||
| 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.1")}, | 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.1")}, | ||||||
| 		UserID:      1, | 		UserID:      1, | ||||||
| @@ -3159,9 +3167,6 @@ func TestValidTagInvalidUser(t *testing.T) { | |||||||
|  |  | ||||||
| 	node := &types.Node{ | 	node := &types.Node{ | ||||||
| 		ID:          1, | 		ID:          1, | ||||||
| 		MachineKey:  "12345", |  | ||||||
| 		NodeKey:     "bar", |  | ||||||
| 		DiscoKey:    "faa", |  | ||||||
| 		Hostname:    "webserver", | 		Hostname:    "webserver", | ||||||
| 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.1")}, | 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.1")}, | ||||||
| 		UserID:      1, | 		UserID:      1, | ||||||
| @@ -3179,9 +3184,6 @@ func TestValidTagInvalidUser(t *testing.T) { | |||||||
|  |  | ||||||
| 	nodes2 := &types.Node{ | 	nodes2 := &types.Node{ | ||||||
| 		ID:          2, | 		ID:          2, | ||||||
| 		MachineKey:  "56789", |  | ||||||
| 		NodeKey:     "bar2", |  | ||||||
| 		DiscoKey:    "faab", |  | ||||||
| 		Hostname:    "user", | 		Hostname:    "user", | ||||||
| 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.2")}, | 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.2")}, | ||||||
| 		UserID:      1, | 		UserID:      1, | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ func logPollFunc( | |||||||
| 				Bool("readOnly", mapRequest.ReadOnly). | 				Bool("readOnly", mapRequest.ReadOnly). | ||||||
| 				Bool("omitPeers", mapRequest.OmitPeers). | 				Bool("omitPeers", mapRequest.OmitPeers). | ||||||
| 				Bool("stream", mapRequest.Stream). | 				Bool("stream", mapRequest.Stream). | ||||||
| 				Str("node_key", node.NodeKey). | 				Str("node_key", node.NodeKey.ShortString()). | ||||||
| 				Str("node", node.Hostname). | 				Str("node", node.Hostname). | ||||||
| 				Msg(msg) | 				Msg(msg) | ||||||
| 		}, | 		}, | ||||||
| @@ -45,7 +45,7 @@ func logPollFunc( | |||||||
| 				Bool("readOnly", mapRequest.ReadOnly). | 				Bool("readOnly", mapRequest.ReadOnly). | ||||||
| 				Bool("omitPeers", mapRequest.OmitPeers). | 				Bool("omitPeers", mapRequest.OmitPeers). | ||||||
| 				Bool("stream", mapRequest.Stream). | 				Bool("stream", mapRequest.Stream). | ||||||
| 				Str("node_key", node.NodeKey). | 				Str("node_key", node.NodeKey.ShortString()). | ||||||
| 				Str("node", node.Hostname). | 				Str("node", node.Hostname). | ||||||
| 				Err(err). | 				Err(err). | ||||||
| 				Msg(msg) | 				Msg(msg) | ||||||
| @@ -81,7 +81,7 @@ func (h *Headscale) handlePoll( | |||||||
| 			Bool("readOnly", mapRequest.ReadOnly). | 			Bool("readOnly", mapRequest.ReadOnly). | ||||||
| 			Bool("omitPeers", mapRequest.OmitPeers). | 			Bool("omitPeers", mapRequest.OmitPeers). | ||||||
| 			Bool("stream", mapRequest.Stream). | 			Bool("stream", mapRequest.Stream). | ||||||
| 			Str("node_key", node.NodeKey). | 			Str("node_key", node.NodeKey.ShortString()). | ||||||
| 			Str("node", node.Hostname). | 			Str("node", node.Hostname). | ||||||
| 			Strs("endpoints", node.Endpoints). | 			Strs("endpoints", node.Endpoints). | ||||||
| 			Msg("Received endpoint update") | 			Msg("Received endpoint update") | ||||||
| @@ -90,8 +90,8 @@ func (h *Headscale) handlePoll( | |||||||
| 		node.LastSeen = &now | 		node.LastSeen = &now | ||||||
| 		node.Hostname = mapRequest.Hostinfo.Hostname | 		node.Hostname = mapRequest.Hostinfo.Hostname | ||||||
| 		node.HostInfo = types.HostInfo(*mapRequest.Hostinfo) | 		node.HostInfo = types.HostInfo(*mapRequest.Hostinfo) | ||||||
| 		node.DiscoKey = mapRequest.DiscoKey.String() | 		node.DiscoKey = mapRequest.DiscoKey | ||||||
| 		node.Endpoints = mapRequest.Endpoints | 		node.SetEndpointsFromAddrPorts(mapRequest.Endpoints) | ||||||
|  |  | ||||||
| 		if err := h.db.NodeSave(node); err != nil { | 		if err := h.db.NodeSave(node); err != nil { | ||||||
| 			logErr(err, "Failed to persist/update node in the database") | 			logErr(err, "Failed to persist/update node in the database") | ||||||
| @@ -113,7 +113,7 @@ func (h *Headscale) handlePoll( | |||||||
| 				Type:    types.StatePeerChanged, | 				Type:    types.StatePeerChanged, | ||||||
| 				Changed: types.Nodes{node}, | 				Changed: types.Nodes{node}, | ||||||
| 			}, | 			}, | ||||||
| 			node.MachineKey) | 			node.MachineKey.String()) | ||||||
|  |  | ||||||
| 		writer.WriteHeader(http.StatusOK) | 		writer.WriteHeader(http.StatusOK) | ||||||
| 		if f, ok := writer.(http.Flusher); ok { | 		if f, ok := writer.(http.Flusher); ok { | ||||||
| @@ -143,8 +143,8 @@ func (h *Headscale) handlePoll( | |||||||
| 	node.LastSeen = &now | 	node.LastSeen = &now | ||||||
| 	node.Hostname = mapRequest.Hostinfo.Hostname | 	node.Hostname = mapRequest.Hostinfo.Hostname | ||||||
| 	node.HostInfo = types.HostInfo(*mapRequest.Hostinfo) | 	node.HostInfo = types.HostInfo(*mapRequest.Hostinfo) | ||||||
| 	node.DiscoKey = mapRequest.DiscoKey.String() | 	node.DiscoKey = mapRequest.DiscoKey | ||||||
| 	node.Endpoints = mapRequest.Endpoints | 	node.SetEndpointsFromAddrPorts(mapRequest.Endpoints) | ||||||
|  |  | ||||||
| 	// When a node connects to control, list the peers it has at | 	// When a node connects to control, list the peers it has at | ||||||
| 	// that given point, further updates are kept in memory in | 	// that given point, further updates are kept in memory in | ||||||
| @@ -222,7 +222,7 @@ func (h *Headscale) handlePoll( | |||||||
| 			Type:    types.StatePeerChanged, | 			Type:    types.StatePeerChanged, | ||||||
| 			Changed: types.Nodes{node}, | 			Changed: types.Nodes{node}, | ||||||
| 		}, | 		}, | ||||||
| 		node.MachineKey) | 		node.MachineKey.String()) | ||||||
|  |  | ||||||
| 	// Set up the client stream | 	// Set up the client stream | ||||||
| 	h.pollNetMapStreamWG.Add(1) | 	h.pollNetMapStreamWG.Add(1) | ||||||
| @@ -342,7 +342,7 @@ func (h *Headscale) handlePoll( | |||||||
| 				Bool("readOnly", mapRequest.ReadOnly). | 				Bool("readOnly", mapRequest.ReadOnly). | ||||||
| 				Bool("omitPeers", mapRequest.OmitPeers). | 				Bool("omitPeers", mapRequest.OmitPeers). | ||||||
| 				Bool("stream", mapRequest.Stream). | 				Bool("stream", mapRequest.Stream). | ||||||
| 				Str("node_key", node.NodeKey). | 				Str("node_key", node.NodeKey.ShortString()). | ||||||
| 				Str("node", node.Hostname). | 				Str("node", node.Hostname). | ||||||
| 				TimeDiff("timeSpent", time.Now(), now). | 				TimeDiff("timeSpent", time.Now(), now). | ||||||
| 				Msg("update sent") | 				Msg("update sent") | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ import ( | |||||||
| 	"github.com/juanfont/headscale/hscontrol/policy/matcher" | 	"github.com/juanfont/headscale/hscontrol/policy/matcher" | ||||||
| 	"go4.org/netipx" | 	"go4.org/netipx" | ||||||
| 	"google.golang.org/protobuf/types/known/timestamppb" | 	"google.golang.org/protobuf/types/known/timestamppb" | ||||||
|  | 	"gorm.io/gorm" | ||||||
| 	"tailscale.com/tailcfg" | 	"tailscale.com/tailcfg" | ||||||
| 	"tailscale.com/types/key" | 	"tailscale.com/types/key" | ||||||
| ) | ) | ||||||
| @@ -25,9 +26,29 @@ var ( | |||||||
| // Node is a Headscale client. | // Node is a Headscale client. | ||||||
| type Node struct { | type Node struct { | ||||||
| 	ID uint64 `gorm:"primary_key"` | 	ID uint64 `gorm:"primary_key"` | ||||||
| 	MachineKey  string `gorm:"type:varchar(64);unique_index"` |  | ||||||
| 	NodeKey     string | 	// MachineKeyValue is the string representation of MachineKey | ||||||
| 	DiscoKey    string | 	// it is _only_ used for reading and writing the key to the | ||||||
|  | 	// database and should not be used. | ||||||
|  | 	// Use MachineKey instead. | ||||||
|  | 	MachineKeyValue string `gorm:"column:machine_key;unique_index"` | ||||||
|  |  | ||||||
|  | 	// NodeKeyValue is the string representation of NodeKey | ||||||
|  | 	// it is _only_ used for reading and writing the key to the | ||||||
|  | 	// database and should not be used. | ||||||
|  | 	// Use NodeKey instead. | ||||||
|  | 	NodeKeyValue string `gorm:"column:node_key"` | ||||||
|  |  | ||||||
|  | 	// DiscoKeyValue is the string representation of DiscoKey | ||||||
|  | 	// it is _only_ used for reading and writing the key to the | ||||||
|  | 	// database and should not be used. | ||||||
|  | 	// Use DiscoKey instead. | ||||||
|  | 	DiscoKeyValue string `gorm:"column:disco_key"` | ||||||
|  |  | ||||||
|  | 	MachineKey key.MachinePublic `gorm:"-"` | ||||||
|  | 	NodeKey    key.NodePublic    `gorm:"-"` | ||||||
|  | 	DiscoKey   key.DiscoPublic   `gorm:"-"` | ||||||
|  |  | ||||||
| 	IPAddresses NodeAddresses | 	IPAddresses NodeAddresses | ||||||
|  |  | ||||||
| 	// Hostname represents the name given by the Tailscale | 	// Hostname represents the name given by the Tailscale | ||||||
| @@ -174,6 +195,31 @@ func (node Node) IsExpired() bool { | |||||||
| 	return time.Now().UTC().After(*node.Expiry) | 	return time.Now().UTC().After(*node.Expiry) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // TODO(kradalby): Try to replace the types in the DB to be correct. | ||||||
|  | func (node *Node) EndpointsToAddrPort() ([]netip.AddrPort, error) { | ||||||
|  | 	var ret []netip.AddrPort | ||||||
|  | 	for _, ep := range node.Endpoints { | ||||||
|  | 		addrPort, err := netip.ParseAddrPort(ep) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		ret = append(ret, addrPort) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ret, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // TODO(kradalby): Try to replace the types in the DB to be correct. | ||||||
|  | func (node *Node) SetEndpointsFromAddrPorts(in []netip.AddrPort) { | ||||||
|  | 	var strs StringList | ||||||
|  | 	for _, addrPort := range in { | ||||||
|  | 		strs = append(strs, addrPort.String()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	node.Endpoints = strs | ||||||
|  | } | ||||||
|  |  | ||||||
| // IsOnline returns if the node is connected to Headscale. | // IsOnline returns if the node is connected to Headscale. | ||||||
| // This is really a naive implementation, as we don't really see | // This is really a naive implementation, as we don't really see | ||||||
| // if there is a working connection between the client and the server. | // if there is a working connection between the client and the server. | ||||||
| @@ -226,13 +272,52 @@ func (nodes Nodes) FilterByIP(ip netip.Addr) Nodes { | |||||||
| 	return found | 	return found | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // BeforeSave is a hook that ensures that some values that | ||||||
|  | // cannot be directly marshalled into database values are stored | ||||||
|  | // correctly in the database. | ||||||
|  | // This currently means storing the keys as strings. | ||||||
|  | func (n *Node) BeforeSave(tx *gorm.DB) (err error) { | ||||||
|  | 	n.MachineKeyValue = n.MachineKey.String() | ||||||
|  | 	n.NodeKeyValue = n.NodeKey.String() | ||||||
|  | 	n.DiscoKeyValue = n.DiscoKey.String() | ||||||
|  |  | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // AfterFind is a hook that ensures that Node objects fields that | ||||||
|  | // has a different type in the database is unwrapped and populated | ||||||
|  | // correctly. | ||||||
|  | // This currently unmarshals all the keys, stored as strings, into | ||||||
|  | // the proper types. | ||||||
|  | func (n *Node) AfterFind(tx *gorm.DB) (err error) { | ||||||
|  | 	var machineKey key.MachinePublic | ||||||
|  | 	if err := machineKey.UnmarshalText([]byte(n.MachineKeyValue)); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	n.MachineKey = machineKey | ||||||
|  |  | ||||||
|  | 	var nodeKey key.NodePublic | ||||||
|  | 	if err := nodeKey.UnmarshalText([]byte(n.NodeKeyValue)); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	n.NodeKey = nodeKey | ||||||
|  |  | ||||||
|  | 	var discoKey key.DiscoPublic | ||||||
|  | 	if err := discoKey.UnmarshalText([]byte(n.DiscoKeyValue)); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	n.DiscoKey = discoKey | ||||||
|  |  | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
| func (node *Node) Proto() *v1.Node { | func (node *Node) Proto() *v1.Node { | ||||||
| 	nodeProto := &v1.Node{ | 	nodeProto := &v1.Node{ | ||||||
| 		Id:         node.ID, | 		Id:         node.ID, | ||||||
| 		MachineKey: node.MachineKey, | 		MachineKey: node.MachineKey.String(), | ||||||
|  |  | ||||||
| 		NodeKey:     node.NodeKey, | 		NodeKey:     node.NodeKey.String(), | ||||||
| 		DiscoKey:    node.DiscoKey, | 		DiscoKey:    node.DiscoKey.String(), | ||||||
| 		IpAddresses: node.IPAddresses.StringSlice(), | 		IpAddresses: node.IPAddresses.StringSlice(), | ||||||
| 		Name:        node.Hostname, | 		Name:        node.Hostname, | ||||||
| 		GivenName:   node.GivenName, | 		GivenName:   node.GivenName, | ||||||
| @@ -289,47 +374,6 @@ func (node *Node) GetFQDN(dnsConfig *tailcfg.DNSConfig, baseDomain string) (stri | |||||||
| 	return hostname, nil | 	return hostname, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (node *Node) MachinePublicKey() (key.MachinePublic, error) { |  | ||||||
| 	var machineKey key.MachinePublic |  | ||||||
|  |  | ||||||
| 	if node.MachineKey != "" { |  | ||||||
| 		err := machineKey.UnmarshalText( |  | ||||||
| 			[]byte(node.MachineKey), |  | ||||||
| 		) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return key.MachinePublic{}, fmt.Errorf("failed to parse machine public key: %w", err) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return machineKey, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (node *Node) DiscoPublicKey() (key.DiscoPublic, error) { |  | ||||||
| 	var discoKey key.DiscoPublic |  | ||||||
| 	if node.DiscoKey != "" { |  | ||||||
| 		err := discoKey.UnmarshalText( |  | ||||||
| 			[]byte(node.DiscoKey), |  | ||||||
| 		) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return key.DiscoPublic{}, fmt.Errorf("failed to parse disco public key: %w", err) |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		discoKey = key.DiscoPublic{} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return discoKey, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (node *Node) NodePublicKey() (key.NodePublic, error) { |  | ||||||
| 	var nodeKey key.NodePublic |  | ||||||
| 	err := nodeKey.UnmarshalText([]byte(node.NodeKey)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return key.NodePublic{}, fmt.Errorf("failed to parse node public key: %w", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nodeKey, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (node Node) String() string { | func (node Node) String() string { | ||||||
| 	return node.Hostname | 	return node.Hostname | ||||||
| } | } | ||||||
|   | |||||||
| @@ -683,8 +683,8 @@ func TestNodeTagCommand(t *testing.T) { | |||||||
| 	assertNoErr(t, err) | 	assertNoErr(t, err) | ||||||
|  |  | ||||||
| 	machineKeys := []string{ | 	machineKeys := []string{ | ||||||
| 		"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | 		"mkey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||||
| 		"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | 		"mkey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||||
| 	} | 	} | ||||||
| 	nodes := make([]*v1.Node, len(machineKeys)) | 	nodes := make([]*v1.Node, len(machineKeys)) | ||||||
| 	assert.Nil(t, err) | 	assert.Nil(t, err) | ||||||
| @@ -816,13 +816,13 @@ func TestNodeCommand(t *testing.T) { | |||||||
| 	headscale, err := scenario.Headscale() | 	headscale, err := scenario.Headscale() | ||||||
| 	assertNoErr(t, err) | 	assertNoErr(t, err) | ||||||
|  |  | ||||||
| 	// Randomly generated node keys | 	// Pregenerated machine keys | ||||||
| 	machineKeys := []string{ | 	machineKeys := []string{ | ||||||
| 		"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | 		"mkey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||||
| 		"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | 		"mkey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||||
| 		"nodekey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | 		"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||||
| 		"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1", | 		"mkey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1", | ||||||
| 		"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | 		"mkey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||||
| 	} | 	} | ||||||
| 	nodes := make([]*v1.Node, len(machineKeys)) | 	nodes := make([]*v1.Node, len(machineKeys)) | ||||||
| 	assert.Nil(t, err) | 	assert.Nil(t, err) | ||||||
| @@ -898,8 +898,8 @@ func TestNodeCommand(t *testing.T) { | |||||||
| 	assert.Equal(t, "node-5", listAll[4].Name) | 	assert.Equal(t, "node-5", listAll[4].Name) | ||||||
|  |  | ||||||
| 	otherUserMachineKeys := []string{ | 	otherUserMachineKeys := []string{ | ||||||
| 		"nodekey:b5b444774186d4217adcec407563a1223929465ee2c68a4da13af0d0185b4f8e", | 		"mkey:b5b444774186d4217adcec407563a1223929465ee2c68a4da13af0d0185b4f8e", | ||||||
| 		"nodekey:dc721977ac7415aafa87f7d4574cbe07c6b171834a6d37375782bdc1fb6b3584", | 		"mkey:dc721977ac7415aafa87f7d4574cbe07c6b171834a6d37375782bdc1fb6b3584", | ||||||
| 	} | 	} | ||||||
| 	otherUserMachines := make([]*v1.Node, len(otherUserMachineKeys)) | 	otherUserMachines := make([]*v1.Node, len(otherUserMachineKeys)) | ||||||
| 	assert.Nil(t, err) | 	assert.Nil(t, err) | ||||||
| @@ -1056,13 +1056,13 @@ func TestNodeExpireCommand(t *testing.T) { | |||||||
| 	headscale, err := scenario.Headscale() | 	headscale, err := scenario.Headscale() | ||||||
| 	assertNoErr(t, err) | 	assertNoErr(t, err) | ||||||
|  |  | ||||||
| 	// Randomly generated node keys | 	// Pregenerated machine keys | ||||||
| 	machineKeys := []string{ | 	machineKeys := []string{ | ||||||
| 		"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | 		"mkey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||||
| 		"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | 		"mkey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||||
| 		"nodekey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | 		"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||||
| 		"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1", | 		"mkey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1", | ||||||
| 		"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | 		"mkey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||||
| 	} | 	} | ||||||
| 	nodes := make([]*v1.Node, len(machineKeys)) | 	nodes := make([]*v1.Node, len(machineKeys)) | ||||||
|  |  | ||||||
| @@ -1183,13 +1183,13 @@ func TestNodeRenameCommand(t *testing.T) { | |||||||
| 	headscale, err := scenario.Headscale() | 	headscale, err := scenario.Headscale() | ||||||
| 	assertNoErr(t, err) | 	assertNoErr(t, err) | ||||||
|  |  | ||||||
| 	// Randomly generated node keys | 	// Pregenerated machine keys | ||||||
| 	machineKeys := []string{ | 	machineKeys := []string{ | ||||||
| 		"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | 		"mkey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||||
| 		"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1", | 		"mkey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1", | ||||||
| 		"nodekey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | 		"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||||
| 		"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | 		"mkey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||||
| 		"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | 		"mkey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||||
| 	} | 	} | ||||||
| 	nodes := make([]*v1.Node, len(machineKeys)) | 	nodes := make([]*v1.Node, len(machineKeys)) | ||||||
| 	assert.Nil(t, err) | 	assert.Nil(t, err) | ||||||
| @@ -1210,7 +1210,7 @@ func TestNodeRenameCommand(t *testing.T) { | |||||||
| 				"json", | 				"json", | ||||||
| 			}, | 			}, | ||||||
| 		) | 		) | ||||||
| 		assert.Nil(t, err) | 		assertNoErr(t, err) | ||||||
|  |  | ||||||
| 		var node v1.Node | 		var node v1.Node | ||||||
| 		err = executeAndUnmarshal( | 		err = executeAndUnmarshal( | ||||||
| @@ -1228,7 +1228,7 @@ func TestNodeRenameCommand(t *testing.T) { | |||||||
| 			}, | 			}, | ||||||
| 			&node, | 			&node, | ||||||
| 		) | 		) | ||||||
| 		assert.Nil(t, err) | 		assertNoErr(t, err) | ||||||
|  |  | ||||||
| 		nodes[index] = &node | 		nodes[index] = &node | ||||||
| 	} | 	} | ||||||
| @@ -1350,7 +1350,7 @@ func TestNodeMoveCommand(t *testing.T) { | |||||||
| 	assertNoErr(t, err) | 	assertNoErr(t, err) | ||||||
|  |  | ||||||
| 	// Randomly generated node key | 	// Randomly generated node key | ||||||
| 	machineKey := "nodekey:688411b767663479632d44140f08a9fde87383adc7cdeb518f62ce28a17ef0aa" | 	machineKey := "mkey:688411b767663479632d44140f08a9fde87383adc7cdeb518f62ce28a17ef0aa" | ||||||
|  |  | ||||||
| 	_, err = headscale.Execute( | 	_, err = headscale.Execute( | ||||||
| 		[]string{ | 		[]string{ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user