mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-31 16:11:03 +01: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:
		
							parent
							
								
									c0fd06e3f5
								
							
						
					
					
						commit
						ed4e19996b
					
				| @ -4,10 +4,10 @@ import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	v1 "github.com/juanfont/headscale/gen/go/headscale/v1" | ||||
| 	"github.com/juanfont/headscale/hscontrol/util" | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"google.golang.org/grpc/status" | ||||
| 	"tailscale.com/types/key" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| @ -93,11 +93,13 @@ var createNodeCmd = &cobra.Command{ | ||||
| 
 | ||||
| 			return | ||||
| 		} | ||||
| 		if !util.NodePublicKeyRegex.Match([]byte(machineKey)) { | ||||
| 			err = errPreAuthKeyMalformed | ||||
| 
 | ||||
| 		var mkey key.MachinePublic | ||||
| 		err = mkey.UnmarshalText([]byte(machineKey)) | ||||
| 		if err != nil { | ||||
| 			ErrorOutput( | ||||
| 				err, | ||||
| 				fmt.Sprintf("Error: %s", err), | ||||
| 				fmt.Sprintf("Failed to parse machine key from flag: %s", err), | ||||
| 				output, | ||||
| 			) | ||||
| 
 | ||||
|  | ||||
| @ -33,7 +33,7 @@ | ||||
| 
 | ||||
|           # 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. | ||||
|           vendorSha256 = "sha256-Q6eySc8lXYhkWka7Y+qOM6viv7QhdjFZDX8PttaLfr4="; | ||||
|           vendorSha256 = "sha256-SYb2LCCZT/p1UHwB1b0IHPfk6Sxh3UYkR4r+KjkL4F8="; | ||||
| 
 | ||||
|           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/grpc-ecosystem/go-grpc-middleware v1.4.0 | ||||
| 	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/ory/dockertest/v3 v3.9.1 | ||||
| 	github.com/patrickmn/go-cache v2.1.0+incompatible | ||||
| 	github.com/philip-bui/grpc-zerolog v1.0.1 | ||||
| 	github.com/pkg/profile v1.7.0 | ||||
| 	github.com/prometheus/client_golang v1.15.1 | ||||
| 	github.com/prometheus/common v0.42.0 | ||||
| 	github.com/prometheus/client_golang v1.17.0 | ||||
| 	github.com/prometheus/common v0.44.0 | ||||
| 	github.com/pterm/pterm v0.12.58 | ||||
| 	github.com/puzpuzpuz/xsync/v2 v2.4.0 | ||||
| 	github.com/rs/zerolog v1.29.0 | ||||
| @ -33,19 +33,19 @@ require ( | ||||
| 	github.com/stretchr/testify v1.8.4 | ||||
| 	github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a | ||||
| 	github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e | ||||
| 	go4.org/netipx v0.0.0-20230728180743-ad4cb58a6516 | ||||
| 	golang.org/x/crypto v0.12.0 | ||||
| 	golang.org/x/net v0.14.0 | ||||
| 	golang.org/x/oauth2 v0.7.0 | ||||
| 	golang.org/x/sync v0.2.0 | ||||
| 	go4.org/netipx v0.0.0-20230824141953-6213f710f925 | ||||
| 	golang.org/x/crypto v0.14.0 | ||||
| 	golang.org/x/net v0.17.0 | ||||
| 	golang.org/x/oauth2 v0.12.0 | ||||
| 	golang.org/x/sync v0.3.0 | ||||
| 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 | ||||
| 	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/yaml.v3 v3.0.1 | ||||
| 	gorm.io/driver/postgres v1.4.8 | ||||
| 	gorm.io/gorm v1.24.6 | ||||
| 	tailscale.com v1.50.0 | ||||
| 	tailscale.com v1.54.0 | ||||
| ) | ||||
| 
 | ||||
| require ( | ||||
| @ -56,22 +56,22 @@ require ( | ||||
| 	github.com/Microsoft/go-winio v0.6.1 // indirect | ||||
| 	github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // 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/cenkalti/backoff/v4 v4.2.0 // indirect | ||||
| 	github.com/cespare/xxhash/v2 v2.2.0 // indirect | ||||
| 	github.com/containerd/console v1.0.3 // indirect | ||||
| 	github.com/containerd/continuity v0.3.0 // indirect | ||||
| 	github.com/coreos/go-iptables v0.6.0 // indirect | ||||
| 	github.com/dblohm7/wingoes v0.0.0-20230821191801-fc76608aecf0 // indirect | ||||
| 	github.com/docker/cli v23.0.5+incompatible // indirect | ||||
| 	github.com/docker/docker v24.0.4+incompatible // indirect | ||||
| 	github.com/coreos/go-iptables v0.7.0 // indirect | ||||
| 	github.com/dblohm7/wingoes v0.0.0-20230929194252-e994401fc077 // indirect | ||||
| 	github.com/docker/cli v24.0.6+incompatible // indirect | ||||
| 	github.com/docker/docker v24.0.7+incompatible // indirect | ||||
| 	github.com/docker/go-connections v0.4.0 // indirect | ||||
| 	github.com/docker/go-units v0.5.0 // indirect | ||||
| 	github.com/dustin/go-humanize v1.0.1 // indirect | ||||
| 	github.com/felixge/fgprof v0.9.3 // 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/go-jose/go-jose/v3 v3.0.0 // 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/pprof v0.0.0-20221118152302-e6195bd50e26 // 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/hashicorp/go-version v1.6.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/now v1.1.5 // 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/kr/pretty v0.3.1 // indirect | ||||
| 	github.com/kr/text v0.2.0 // indirect | ||||
| @ -104,33 +104,34 @@ require ( | ||||
| 	github.com/lithammer/fuzzysearch v1.1.5 // indirect | ||||
| 	github.com/magiconair/properties v1.8.7 // 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/matttproud/golang_protobuf_extensions v1.0.4 // 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/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/mapstructure v1.5.0 // indirect | ||||
| 	github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // 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/pelletier/go-toml/v2 v2.0.8 // indirect | ||||
| 	github.com/pkg/errors v0.9.1 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	github.com/prometheus/client_model v0.4.0 // indirect | ||||
| 	github.com/prometheus/procfs v0.9.0 // indirect | ||||
| 	github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect | ||||
| 	github.com/prometheus/procfs v0.12.0 // indirect | ||||
| 	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect | ||||
| 	github.com/rivo/uniseg v0.4.4 // indirect | ||||
| 	github.com/rogpeppe/go-internal v1.10.0 // indirect | ||||
| 	github.com/sirupsen/logrus v1.9.0 // indirect | ||||
| 	github.com/rogpeppe/go-internal v1.11.0 // indirect | ||||
| 	github.com/sirupsen/logrus v1.9.3 // indirect | ||||
| 	github.com/spf13/afero v1.9.5 // indirect | ||||
| 	github.com/spf13/cast v1.5.1 // indirect | ||||
| 	github.com/spf13/jwalterweatherman v1.1.0 // indirect | ||||
| 	github.com/spf13/pflag v1.0.5 // 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/vishvananda/netlink v1.2.1-beta.2 // indirect | ||||
| 	github.com/vishvananda/netns v0.0.4 // indirect | ||||
| @ -140,15 +141,15 @@ require ( | ||||
| 	github.com/xeipuuv/gojsonschema v1.2.0 // indirect | ||||
| 	github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect | ||||
| 	go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect | ||||
| 	golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect | ||||
| 	golang.org/x/mod v0.11.0 // indirect | ||||
| 	golang.org/x/sys v0.11.0 // indirect | ||||
| 	golang.org/x/term v0.11.0 // indirect | ||||
| 	golang.org/x/text v0.12.0 // indirect | ||||
| 	golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect | ||||
| 	golang.org/x/mod v0.12.0 // indirect | ||||
| 	golang.org/x/sys v0.13.0 // indirect | ||||
| 	golang.org/x/term v0.13.0 // indirect | ||||
| 	golang.org/x/text v0.13.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 | ||||
| 	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/square/go-jose.v2 v2.6.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/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A= | ||||
| 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-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= | ||||
| github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= | ||||
| 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/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= | ||||
| 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/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.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ= | ||||
| github.com/cilium/ebpf v0.10.0/go.mod h1:DPiVdY/kT534dgc9ERmvP8mWA+9gvwgKfRvk4nNWnoE= | ||||
| github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= | ||||
| github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= | ||||
| 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-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/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= | ||||
| 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.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= | ||||
| github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= | ||||
| 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/go.mod h1:ecXRtV4romGPeO6ieExAsUK9cb/3fp9hXNz1tlv8PIM= | ||||
| 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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||
| 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-20230821191801-fc76608aecf0/go.mod h1:6NCrWM5jRefaG7iN0iMShPalLsljHWBh9v1zxM2f8Xs= | ||||
| github.com/dblohm7/wingoes v0.0.0-20230929194252-e994401fc077 h1:WphxHslVftszsr0oZOHPaOjpmN/BsgNYF+gW/hxZXXc= | ||||
| 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/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= | ||||
| github.com/docker/cli v23.0.5+incompatible h1:ufWmAOuD3Vmr7JP2G5K3cyuNC4YZWiAsuDEvFVVDafE= | ||||
| github.com/docker/cli v23.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= | ||||
| github.com/docker/docker v24.0.4+incompatible h1:s/LVDftw9hjblvqIeTiGYXBCD95nOEEl7qRsRrIOuQI= | ||||
| github.com/docker/docker v24.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= | ||||
| github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= | ||||
| github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= | ||||
| github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= | ||||
| 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/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= | ||||
| 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/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= | ||||
| 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.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= | ||||
| github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= | ||||
| 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/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= | ||||
| 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/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= | ||||
| 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.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||
| github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= | ||||
| 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.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= | ||||
| 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/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/jsimonetti/rtnetlink v1.3.2 h1:dcn0uWkfxycEEyNy0IGfx3GrhQ38LH7odjxAghimsVI= | ||||
| github.com/jsimonetti/rtnetlink v1.3.2/go.mod h1:BBu4jZCpTjP6Gk0/wfrO8qcqymnN3g0hoFqObRmUo6U= | ||||
| github.com/jsimonetti/rtnetlink v1.3.5 h1:hVlNQNRlLDGZz31gBPicsG7Q53rnlsz1l1Ix/9XlpVA= | ||||
| 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.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= | ||||
| 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/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.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= | ||||
| github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= | ||||
| github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= | ||||
| 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.10/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.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.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= | ||||
| github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | ||||
| github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= | ||||
| 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.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= | ||||
| 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/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= | ||||
| 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.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= | ||||
| github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI= | ||||
| 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-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= | ||||
| 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.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= | ||||
| github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= | ||||
| 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/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= | ||||
| 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/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/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8= | ||||
| github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= | ||||
| github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= | ||||
| 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/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= | ||||
| 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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| 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.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= | ||||
| github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= | ||||
| 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.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= | ||||
| github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= | ||||
| github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= | ||||
| github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= | ||||
| github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= | ||||
| github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= | ||||
| github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= | ||||
| github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= | ||||
| github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= | ||||
| github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= | ||||
| github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= | ||||
| 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.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= | ||||
| 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.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.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= | ||||
| github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= | ||||
| github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= | ||||
| 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/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= | ||||
| 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/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.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= | ||||
| github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= | ||||
| github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= | ||||
| 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/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= | ||||
| 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/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= | ||||
| 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/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8= | ||||
| 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= | ||||
| 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/netipx v0.0.0-20230728180743-ad4cb58a6516 h1:X66ZEoMN2SuaoI/dfZVYobB6E5zjZyyHUMWlCA7MgGE= | ||||
| go4.org/netipx v0.0.0-20230728180743-ad4cb58a6516/go.mod h1:TQvodOM+hJTioNQJilmLXu08JNb8i+ccq418+KWu1/Y= | ||||
| go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ= | ||||
| 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-20190510104115-cbcb75029529/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-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | ||||
| 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.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= | ||||
| golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= | ||||
| 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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | ||||
| 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-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-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= | ||||
| golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= | ||||
| golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= | ||||
| 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-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= | ||||
| 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.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.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= | ||||
| golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | ||||
| golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= | ||||
| 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-20180826012351-8a410e7b638d/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.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.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= | ||||
| golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= | ||||
| golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= | ||||
| 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-20190226205417-e64efc72b421/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-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.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= | ||||
| golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= | ||||
| golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= | ||||
| 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-20181108010431-42b317875d0f/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-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.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= | ||||
| golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= | ||||
| 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-20190215142949-d0b11bdaac8a/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.5.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.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= | ||||
| golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/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-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.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.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= | ||||
| golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= | ||||
| golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= | ||||
| 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.3.0/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.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.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= | ||||
| 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.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= | ||||
| golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= | ||||
| golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= | ||||
| 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-20190308202827-9d24e82272b4/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.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.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= | ||||
| golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= | ||||
| golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= | ||||
| 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-20191011141410-1b5146add898/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.5/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.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-20190307195333-5fe7a883aa19/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.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.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= | ||||
| google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= | ||||
| google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= | ||||
| google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= | ||||
| 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-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/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= | ||||
| 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.0/go.mod h1:23rNcYsMabIc1otwLpTkCCPwUq6kQsTyowttG/as0kQ= | ||||
| tailscale.com v1.50.0 h1:98infw8rznkdntRgcnlrAC5JuZfDH0bqKLyg8ZKfwMk= | ||||
| tailscale.com v1.50.0/go.mod h1:lBw7+Mw2d7rea3kefGjYWN8IJkB5dyaakMNMOinNGDo= | ||||
| software.sslmate.com/src/go-pkcs12 v0.2.1 h1:tbT1jjaeFOF230tzOIRJ6U5S1jNqpsSyNjzDd58H3J8= | ||||
| software.sslmate.com/src/go-pkcs12 v0.2.1/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= | ||||
| tailscale.com v1.54.0 h1:Dri5BTKkHYpl+/t8ofY+tyvoTDbH/FpP7iB4B0cAQOY= | ||||
| 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("/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) | ||||
| 
 | ||||
| 	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("/apple", h.AppleConfigMessage).Methods(http.MethodGet) | ||||
| 	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 | ||||
| 		// successful RegisterResponse. | ||||
| 		if registerRequest.Followup != "" { | ||||
| 			if _, ok := h.registrationCache.Get(registerRequest.NodeKey.String()); ok { | ||||
| 			if _, ok := h.registrationCache.Get(machineKey.String()); ok { | ||||
| 				log.Debug(). | ||||
| 					Caller(). | ||||
| 					Str("node", registerRequest.Hostinfo.Hostname). | ||||
| @ -78,7 +78,7 @@ func (h *Headscale) handleRegister( | ||||
| 			Msg("New node not yet in the database") | ||||
| 
 | ||||
| 		givenName, err := h.db.GenerateGivenName( | ||||
| 			machineKey.String(), | ||||
| 			machineKey, | ||||
| 			registerRequest.Hostinfo.Hostname, | ||||
| 		) | ||||
| 		if err != nil { | ||||
| @ -97,10 +97,10 @@ func (h *Headscale) handleRegister( | ||||
| 		// We create the node and then keep it around until a callback | ||||
| 		// happens | ||||
| 		newNode := types.Node{ | ||||
| 			MachineKey: machineKey.String(), | ||||
| 			MachineKey: machineKey, | ||||
| 			Hostname:   registerRequest.Hostinfo.Hostname, | ||||
| 			GivenName:  givenName, | ||||
| 			NodeKey:    registerRequest.NodeKey.String(), | ||||
| 			NodeKey:    registerRequest.NodeKey, | ||||
| 			LastSeen:   &now, | ||||
| 			Expiry:     &time.Time{}, | ||||
| 		} | ||||
| @ -116,7 +116,7 @@ func (h *Headscale) handleRegister( | ||||
| 		} | ||||
| 
 | ||||
| 		h.registrationCache.Set( | ||||
| 			newNode.NodeKey, | ||||
| 			machineKey.String(), | ||||
| 			newNode, | ||||
| 			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, | ||||
| 		// 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. | ||||
| 		var storedMachineKey key.MachinePublic | ||||
| 		err = storedMachineKey.UnmarshalText( | ||||
| 			[]byte(node.MachineKey), | ||||
| 		) | ||||
| 		if err != nil || storedMachineKey.IsZero() { | ||||
| 		if err != nil || node.MachineKey.IsZero() { | ||||
| 			if err := h.db.NodeSetMachineKey(node, machineKey); err != nil { | ||||
| 				log.Error(). | ||||
| 					Caller(). | ||||
| @ -156,7 +152,7 @@ func (h *Headscale) handleRegister( | ||||
| 		// - Trying to log out (sending a expiry in the past) | ||||
| 		// - A valid, registered node, looking for /map | ||||
| 		// - 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) | ||||
| 			//   https://github.com/tailscale/tailscale/blob/main/tailcfg/tailcfg.go#L648 | ||||
| 			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 | ||||
| 		if node.NodeKey == registerRequest.OldNodeKey.String() && | ||||
| 		if node.NodeKey.String() == registerRequest.OldNodeKey.String() && | ||||
| 			!node.IsExpired() { | ||||
| 			h.handleNodeKeyRefresh( | ||||
| 				writer, | ||||
| @ -207,9 +203,9 @@ func (h *Headscale) handleRegister( | ||||
| 		// we need to make sure the NodeKey matches the one in the request | ||||
| 		// TODO(juan): What happens when using fast user switching between two | ||||
| 		// headscale-managed tailnets? | ||||
| 		node.NodeKey = registerRequest.NodeKey.String() | ||||
| 		node.NodeKey = registerRequest.NodeKey | ||||
| 		h.registrationCache.Set( | ||||
| 			registerRequest.NodeKey.String(), | ||||
| 			machineKey.String(), | ||||
| 			*node, | ||||
| 			registerCacheExpiration, | ||||
| 		) | ||||
| @ -294,7 +290,7 @@ func (h *Headscale) handleAuthKey( | ||||
| 		Str("node", registerRequest.Hostinfo.Hostname). | ||||
| 		Msg("Authentication key was valid, proceeding to acquire IP addresses") | ||||
| 
 | ||||
| 	nodeKey := registerRequest.NodeKey.String() | ||||
| 	nodeKey := registerRequest.NodeKey | ||||
| 
 | ||||
| 	// retrieve node information if it exist | ||||
| 	// The error is not important, because if it does not | ||||
| @ -342,7 +338,7 @@ func (h *Headscale) handleAuthKey( | ||||
| 	} else { | ||||
| 		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 { | ||||
| 			log.Error(). | ||||
| 				Caller(). | ||||
| @ -359,7 +355,7 @@ func (h *Headscale) handleAuthKey( | ||||
| 			Hostname:       registerRequest.Hostinfo.Hostname, | ||||
| 			GivenName:      givenName, | ||||
| 			UserID:         pak.User.ID, | ||||
| 			MachineKey:     machineKey.String(), | ||||
| 			MachineKey:     machineKey, | ||||
| 			RegisterMethod: util.RegisterMethodAuthKey, | ||||
| 			Expiry:         ®isterRequest.Expiry, | ||||
| 			NodeKey:        nodeKey, | ||||
| @ -460,12 +456,12 @@ func (h *Headscale) handleNewNode( | ||||
| 		resp.AuthURL = fmt.Sprintf( | ||||
| 			"%s/oidc/register/%s", | ||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | ||||
| 			registerRequest.NodeKey, | ||||
| 			machineKey.String(), | ||||
| 		) | ||||
| 	} else { | ||||
| 		resp.AuthURL = fmt.Sprintf("%s/register/%s", | ||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | ||||
| 			registerRequest.NodeKey) | ||||
| 			machineKey.String()) | ||||
| 	} | ||||
| 
 | ||||
| 	respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey) | ||||
| @ -715,11 +711,11 @@ func (h *Headscale) handleNodeExpiredOrLoggedOut( | ||||
| 	if h.oauth2Config != nil { | ||||
| 		resp.AuthURL = fmt.Sprintf("%s/oidc/register/%s", | ||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | ||||
| 			registerRequest.NodeKey) | ||||
| 			machineKey.String()) | ||||
| 	} else { | ||||
| 		resp.AuthURL = fmt.Sprintf("%s/register/%s", | ||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | ||||
| 			registerRequest.NodeKey) | ||||
| 			machineKey.String()) | ||||
| 	} | ||||
| 
 | ||||
| 	respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey) | ||||
|  | ||||
| @ -2,6 +2,7 @@ package db | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"database/sql" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net/netip" | ||||
| @ -99,7 +100,7 @@ func NewHeadscaleDatabase( | ||||
| 	// node was registered. | ||||
| 	_ = 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 | ||||
| 	// remove the column. | ||||
| 	if dbConn.Migrator().HasColumn(&types.Node{}, "registered") { | ||||
| @ -114,13 +115,13 @@ func NewHeadscaleDatabase( | ||||
| 		for _, node := range nodes { | ||||
| 			log.Info(). | ||||
| 				Str("node", node.Hostname). | ||||
| 				Str("machine_key", node.MachineKey). | ||||
| 				Str("machine_key", node.MachineKey.ShortString()). | ||||
| 				Msg("Deleting unregistered node") | ||||
| 			if err := dbConn.Delete(&types.Node{}, node.ID).Error; err != nil { | ||||
| 				log.Error(). | ||||
| 					Err(err). | ||||
| 					Str("node", node.Hostname). | ||||
| 					Str("machine_key", node.MachineKey). | ||||
| 					Str("machine_key", node.MachineKey.ShortString()). | ||||
| 					Msg("Error deleting unregistered node") | ||||
| 			} | ||||
| 		} | ||||
| @ -136,6 +137,50 @@ func NewHeadscaleDatabase( | ||||
| 		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") { | ||||
| 		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") { | ||||
| 		nodes := types.Nodes{} | ||||
| 		if err := dbConn.Find(&nodes).Error; err != nil { | ||||
| @ -253,27 +293,6 @@ func NewHeadscaleDatabase( | ||||
| 		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? | ||||
| 	err = db.setValue("db_version", dbVersion) | ||||
| 
 | ||||
|  | ||||
| @ -55,7 +55,7 @@ func (hsdb *HSDatabase) listPeers(node *types.Node) (types.Nodes, error) { | ||||
| 		Preload("User"). | ||||
| 		Preload("Routes"). | ||||
| 		Where("node_key <> ?", | ||||
| 			node.NodeKey).Find(&nodes).Error; err != nil { | ||||
| 			node.NodeKey.String()).Find(&nodes).Error; err != nil { | ||||
| 		return types.Nodes{}, err | ||||
| 	} | ||||
| 
 | ||||
| @ -268,7 +268,7 @@ func (hsdb *HSDatabase) SetTags( | ||||
| 	hsdb.notifier.NotifyWithIgnore(types.StateUpdate{ | ||||
| 		Type:    types.StatePeerChanged, | ||||
| 		Changed: types.Nodes{node}, | ||||
| 	}, node.MachineKey) | ||||
| 	}, node.MachineKey.String()) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| @ -304,7 +304,7 @@ func (hsdb *HSDatabase) RenameNode(node *types.Node, newName string) error { | ||||
| 	hsdb.notifier.NotifyWithIgnore(types.StateUpdate{ | ||||
| 		Type:    types.StatePeerChanged, | ||||
| 		Changed: types.Nodes{node}, | ||||
| 	}, node.MachineKey) | ||||
| 	}, node.MachineKey.String()) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| @ -330,7 +330,7 @@ func (hsdb *HSDatabase) nodeSetExpiry(node *types.Node, expiry time.Time) error | ||||
| 	hsdb.notifier.NotifyWithIgnore(types.StateUpdate{ | ||||
| 		Type:    types.StatePeerChanged, | ||||
| 		Changed: types.Nodes{node}, | ||||
| 	}, node.MachineKey) | ||||
| 	}, node.MachineKey.String()) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| @ -376,7 +376,7 @@ func (hsdb *HSDatabase) UpdateLastSeen(node *types.Node) error { | ||||
| 
 | ||||
| func (hsdb *HSDatabase) RegisterNodeFromAuthCallback( | ||||
| 	cache *cache.Cache, | ||||
| 	nodeKeyStr string, | ||||
| 	mkey key.MachinePublic, | ||||
| 	userName string, | ||||
| 	nodeExpiry *time.Time, | ||||
| 	registrationMethod string, | ||||
| @ -384,20 +384,14 @@ func (hsdb *HSDatabase) RegisterNodeFromAuthCallback( | ||||
| 	hsdb.mu.Lock() | ||||
| 	defer hsdb.mu.Unlock() | ||||
| 
 | ||||
| 	nodeKey := key.NodePublic{} | ||||
| 	err := nodeKey.UnmarshalText([]byte(nodeKeyStr)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	log.Debug(). | ||||
| 		Str("nodeKey", nodeKey.ShortString()). | ||||
| 		Str("machine_key", mkey.ShortString()). | ||||
| 		Str("userName", userName). | ||||
| 		Str("registrationMethod", registrationMethod). | ||||
| 		Str("expiresAt", fmt.Sprintf("%v", nodeExpiry)). | ||||
| 		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 { | ||||
| 			user, err := hsdb.getUser(userName) | ||||
| 			if err != nil { | ||||
| @ -425,7 +419,7 @@ func (hsdb *HSDatabase) RegisterNodeFromAuthCallback( | ||||
| 			) | ||||
| 
 | ||||
| 			if err == nil { | ||||
| 				cache.Delete(nodeKeyStr) | ||||
| 				cache.Delete(mkey.String()) | ||||
| 			} | ||||
| 
 | ||||
| 			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) { | ||||
| 	log.Debug(). | ||||
| 		Str("node", node.Hostname). | ||||
| 		Str("machine_key", node.MachineKey). | ||||
| 		Str("node_key", node.NodeKey). | ||||
| 		Str("machine_key", node.MachineKey.ShortString()). | ||||
| 		Str("node_key", node.NodeKey.ShortString()). | ||||
| 		Str("user", node.User.Name). | ||||
| 		Msg("Registering node") | ||||
| 
 | ||||
| @ -464,8 +458,8 @@ func (hsdb *HSDatabase) registerNode(node types.Node) (*types.Node, error) { | ||||
| 		log.Trace(). | ||||
| 			Caller(). | ||||
| 			Str("node", node.Hostname). | ||||
| 			Str("machine_key", node.MachineKey). | ||||
| 			Str("node_key", node.NodeKey). | ||||
| 			Str("machine_key", node.MachineKey.ShortString()). | ||||
| 			Str("node_key", node.NodeKey.ShortString()). | ||||
| 			Str("user", node.User.Name). | ||||
| 			Msg("Node authorized again") | ||||
| 
 | ||||
| @ -507,7 +501,7 @@ func (hsdb *HSDatabase) NodeSetNodeKey(node *types.Node, nodeKey key.NodePublic) | ||||
| 	defer hsdb.mu.Unlock() | ||||
| 
 | ||||
| 	if err := hsdb.db.Model(node).Updates(types.Node{ | ||||
| 		NodeKey: nodeKey.String(), | ||||
| 		NodeKey: nodeKey, | ||||
| 	}).Error; err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @ -524,7 +518,7 @@ func (hsdb *HSDatabase) NodeSetMachineKey( | ||||
| 	defer hsdb.mu.Unlock() | ||||
| 
 | ||||
| 	if err := hsdb.db.Model(node).Updates(types.Node{ | ||||
| 		MachineKey: machineKey.String(), | ||||
| 		MachineKey: machineKey, | ||||
| 	}).Error; err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @ -703,7 +697,7 @@ func (hsdb *HSDatabase) enableRoutes(node *types.Node, routeStrs ...string) erro | ||||
| 	hsdb.notifier.NotifyWithIgnore(types.StateUpdate{ | ||||
| 		Type:    types.StatePeerChanged, | ||||
| 		Changed: types.Nodes{node}, | ||||
| 	}, node.MachineKey) | ||||
| 	}, node.MachineKey.String()) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| @ -734,7 +728,7 @@ func generateGivenName(suppliedName string, randomSuffix bool) (string, error) { | ||||
| 	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() | ||||
| 	defer hsdb.mu.RUnlock() | ||||
| 
 | ||||
| @ -749,8 +743,14 @@ func (hsdb *HSDatabase) GenerateGivenName(machineKey string, suppliedName string | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, node := range nodes { | ||||
| 		if node.MachineKey != machineKey && node.GivenName == givenName { | ||||
| 	var nodeFound *types.Node | ||||
| 	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) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| @ -758,7 +758,6 @@ func (hsdb *HSDatabase) GenerateGivenName(machineKey string, suppliedName string | ||||
| 
 | ||||
| 		givenName = postfixedName | ||||
| 	} | ||||
| 	} | ||||
| 
 | ||||
| 	return givenName, nil | ||||
| } | ||||
|  | ||||
| @ -25,11 +25,13 @@ func (s *Suite) TestGetNode(c *check.C) { | ||||
| 	_, err = db.GetNode("test", "testnode") | ||||
| 	c.Assert(err, check.NotNil) | ||||
| 
 | ||||
| 	nodeKey := key.NewNode() | ||||
| 	machineKey := key.NewMachine() | ||||
| 
 | ||||
| 	node := &types.Node{ | ||||
| 		ID:             0, | ||||
| 		MachineKey:     "foo", | ||||
| 		NodeKey:        "bar", | ||||
| 		DiscoKey:       "faa", | ||||
| 		MachineKey:     machineKey.Public(), | ||||
| 		NodeKey:        nodeKey.Public(), | ||||
| 		Hostname:       "testnode", | ||||
| 		UserID:         user.ID, | ||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | ||||
| @ -51,11 +53,13 @@ func (s *Suite) TestGetNodeByID(c *check.C) { | ||||
| 	_, err = db.GetNodeByID(0) | ||||
| 	c.Assert(err, check.NotNil) | ||||
| 
 | ||||
| 	nodeKey := key.NewNode() | ||||
| 	machineKey := key.NewMachine() | ||||
| 
 | ||||
| 	node := types.Node{ | ||||
| 		ID:             0, | ||||
| 		MachineKey:     "foo", | ||||
| 		NodeKey:        "bar", | ||||
| 		DiscoKey:       "faa", | ||||
| 		MachineKey:     machineKey.Public(), | ||||
| 		NodeKey:        nodeKey.Public(), | ||||
| 		Hostname:       "testnode", | ||||
| 		UserID:         user.ID, | ||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | ||||
| @ -82,9 +86,8 @@ func (s *Suite) TestGetNodeByNodeKey(c *check.C) { | ||||
| 
 | ||||
| 	node := types.Node{ | ||||
| 		ID:             0, | ||||
| 		MachineKey:     machineKey.Public().String(), | ||||
| 		NodeKey:        nodeKey.Public().String(), | ||||
| 		DiscoKey:       "faa", | ||||
| 		MachineKey:     machineKey.Public(), | ||||
| 		NodeKey:        nodeKey.Public(), | ||||
| 		Hostname:       "testnode", | ||||
| 		UserID:         user.ID, | ||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | ||||
| @ -113,9 +116,8 @@ func (s *Suite) TestGetNodeByAnyNodeKey(c *check.C) { | ||||
| 
 | ||||
| 	node := types.Node{ | ||||
| 		ID:             0, | ||||
| 		MachineKey:     machineKey.Public().String(), | ||||
| 		NodeKey:        nodeKey.Public().String(), | ||||
| 		DiscoKey:       "faa", | ||||
| 		MachineKey:     machineKey.Public(), | ||||
| 		NodeKey:        nodeKey.Public(), | ||||
| 		Hostname:       "testnode", | ||||
| 		UserID:         user.ID, | ||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | ||||
| @ -130,11 +132,14 @@ func (s *Suite) TestGetNodeByAnyNodeKey(c *check.C) { | ||||
| func (s *Suite) TestHardDeleteNode(c *check.C) { | ||||
| 	user, err := db.CreateUser("test") | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 
 | ||||
| 	nodeKey := key.NewNode() | ||||
| 	machineKey := key.NewMachine() | ||||
| 
 | ||||
| 	node := types.Node{ | ||||
| 		ID:             0, | ||||
| 		MachineKey:     "foo", | ||||
| 		NodeKey:        "bar", | ||||
| 		DiscoKey:       "faa", | ||||
| 		MachineKey:     machineKey.Public(), | ||||
| 		NodeKey:        nodeKey.Public(), | ||||
| 		Hostname:       "testnode3", | ||||
| 		UserID:         user.ID, | ||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | ||||
| @ -160,11 +165,13 @@ func (s *Suite) TestListPeers(c *check.C) { | ||||
| 	c.Assert(err, check.NotNil) | ||||
| 
 | ||||
| 	for index := 0; index <= 10; index++ { | ||||
| 		nodeKey := key.NewNode() | ||||
| 		machineKey := key.NewMachine() | ||||
| 
 | ||||
| 		node := types.Node{ | ||||
| 			ID:             uint64(index), | ||||
| 			MachineKey:     "foo" + strconv.Itoa(index), | ||||
| 			NodeKey:        "bar" + strconv.Itoa(index), | ||||
| 			DiscoKey:       "faa" + strconv.Itoa(index), | ||||
| 			MachineKey:     machineKey.Public(), | ||||
| 			NodeKey:        nodeKey.Public(), | ||||
| 			Hostname:       "testnode" + strconv.Itoa(index), | ||||
| 			UserID:         user.ID, | ||||
| 			RegisterMethod: util.RegisterMethodAuthKey, | ||||
| @ -205,11 +212,13 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) { | ||||
| 	c.Assert(err, check.NotNil) | ||||
| 
 | ||||
| 	for index := 0; index <= 10; index++ { | ||||
| 		nodeKey := key.NewNode() | ||||
| 		machineKey := key.NewMachine() | ||||
| 
 | ||||
| 		node := types.Node{ | ||||
| 			ID:         uint64(index), | ||||
| 			MachineKey: "foo" + strconv.Itoa(index), | ||||
| 			NodeKey:    "bar" + strconv.Itoa(index), | ||||
| 			DiscoKey:   "faa" + strconv.Itoa(index), | ||||
| 			MachineKey: machineKey.Public(), | ||||
| 			NodeKey:    nodeKey.Public(), | ||||
| 			IPAddresses: types.NodeAddresses{ | ||||
| 				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") | ||||
| 	c.Assert(err, check.NotNil) | ||||
| 
 | ||||
| 	nodeKey := key.NewNode() | ||||
| 	machineKey := key.NewMachine() | ||||
| 
 | ||||
| 	node := &types.Node{ | ||||
| 		ID:             0, | ||||
| 		MachineKey:     "foo", | ||||
| 		NodeKey:        "bar", | ||||
| 		DiscoKey:       "faa", | ||||
| 		MachineKey:     machineKey.Public(), | ||||
| 		NodeKey:        nodeKey.Public(), | ||||
| 		Hostname:       "testnode", | ||||
| 		UserID:         user.ID, | ||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | ||||
| @ -345,11 +356,15 @@ func (s *Suite) TestGenerateGivenName(c *check.C) { | ||||
| 	_, err = db.GetNode("user-1", "testnode") | ||||
| 	c.Assert(err, check.NotNil) | ||||
| 
 | ||||
| 	nodeKey := key.NewNode() | ||||
| 	machineKey := key.NewMachine() | ||||
| 
 | ||||
| 	machineKey2 := key.NewMachine() | ||||
| 
 | ||||
| 	node := &types.Node{ | ||||
| 		ID:             0, | ||||
| 		MachineKey:     "node-key-1", | ||||
| 		NodeKey:        "node-key-1", | ||||
| 		DiscoKey:       "disco-key-1", | ||||
| 		MachineKey:     machineKey.Public(), | ||||
| 		NodeKey:        nodeKey.Public(), | ||||
| 		Hostname:       "hostname-1", | ||||
| 		GivenName:      "hostname-1", | ||||
| 		UserID:         user1.ID, | ||||
| @ -358,25 +373,20 @@ func (s *Suite) TestGenerateGivenName(c *check.C) { | ||||
| 	} | ||||
| 	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") | ||||
| 	c.Assert(err, check.IsNil, 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") | ||||
| 	c.Assert(err, check.IsNil, 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") | ||||
| 	c.Assert(err, check.IsNil, 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) { | ||||
| @ -389,11 +399,13 @@ func (s *Suite) TestSetTags(c *check.C) { | ||||
| 	_, err = db.GetNode("test", "testnode") | ||||
| 	c.Assert(err, check.NotNil) | ||||
| 
 | ||||
| 	nodeKey := key.NewNode() | ||||
| 	machineKey := key.NewMachine() | ||||
| 
 | ||||
| 	node := &types.Node{ | ||||
| 		ID:             0, | ||||
| 		MachineKey:     "foo", | ||||
| 		NodeKey:        "bar", | ||||
| 		DiscoKey:       "faa", | ||||
| 		MachineKey:     machineKey.Public(), | ||||
| 		NodeKey:        nodeKey.Public(), | ||||
| 		Hostname:       "testnode", | ||||
| 		UserID:         user.ID, | ||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | ||||
| @ -565,6 +577,7 @@ func (s *Suite) TestAutoApproveRoutes(c *check.C) { | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 
 | ||||
| 	nodeKey := key.NewNode() | ||||
| 	machineKey := key.NewMachine() | ||||
| 
 | ||||
| 	defaultRouteV4 := netip.MustParsePrefix("0.0.0.0/0") | ||||
| 	defaultRouteV6 := netip.MustParsePrefix("::/0") | ||||
| @ -574,9 +587,8 @@ func (s *Suite) TestAutoApproveRoutes(c *check.C) { | ||||
| 
 | ||||
| 	node := types.Node{ | ||||
| 		ID:             0, | ||||
| 		MachineKey:     "foo", | ||||
| 		NodeKey:        nodeKey.Public().String(), | ||||
| 		DiscoKey:       "faa", | ||||
| 		MachineKey:     machineKey.Public(), | ||||
| 		NodeKey:        nodeKey.Public(), | ||||
| 		Hostname:       "test", | ||||
| 		UserID:         user.ID, | ||||
| 		RegisterMethod: util.RegisterMethodAuthKey, | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| package db | ||||
| 
 | ||||
| import ( | ||||
| 	"log" | ||||
| 	"net/netip" | ||||
| 	"os" | ||||
| 	"testing" | ||||
| @ -27,19 +28,22 @@ func (s *Suite) SetUpTest(c *check.C) { | ||||
| } | ||||
| 
 | ||||
| func (s *Suite) TearDownTest(c *check.C) { | ||||
| 	os.RemoveAll(tmpDir) | ||||
| 	// os.RemoveAll(tmpDir) | ||||
| } | ||||
| 
 | ||||
| func (s *Suite) ResetDB(c *check.C) { | ||||
| 	if len(tmpDir) != 0 { | ||||
| 		os.RemoveAll(tmpDir) | ||||
| 	} | ||||
| 	// if len(tmpDir) != 0 { | ||||
| 	// 	os.RemoveAll(tmpDir) | ||||
| 	// } | ||||
| 
 | ||||
| 	var err error | ||||
| 	tmpDir, err = os.MkdirTemp("", "autoygg-client-test") | ||||
| 	tmpDir, err = os.MkdirTemp("", "headscale-db-test-*") | ||||
| 	if err != nil { | ||||
| 		c.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	log.Printf("database path: %s", tmpDir+"/headscale_test.db") | ||||
| 
 | ||||
| 	db, err = NewHeadscaleDatabase( | ||||
| 		"sqlite3", | ||||
| 		tmpDir+"/headscale_test.db", | ||||
|  | ||||
| @ -172,12 +172,18 @@ func (api headscaleV1APIServer) RegisterNode( | ||||
| ) (*v1.RegisterNodeResponse, error) { | ||||
| 	log.Trace(). | ||||
| 		Str("user", request.GetUser()). | ||||
| 		Str("node_key", request.GetKey()). | ||||
| 		Str("machine_key", request.GetKey()). | ||||
| 		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( | ||||
| 		api.h.registrationCache, | ||||
| 		request.GetKey(), | ||||
| 		mkey, | ||||
| 		request.GetUser(), | ||||
| 		nil, | ||||
| 		util.RegisterMethodCLI, | ||||
| @ -521,13 +527,22 @@ func (api headscaleV1APIServer) DebugCreateNode( | ||||
| 		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 { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	givenName, err := api.h.db.GenerateGivenName(mkey, request.GetName()) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	nodeKey := key.NewNode() | ||||
| 
 | ||||
| 	newNode := types.Node{ | ||||
| 		MachineKey: request.GetKey(), | ||||
| 		MachineKey: mkey, | ||||
| 		NodeKey:    nodeKey.Public(), | ||||
| 		Hostname:   request.GetName(), | ||||
| 		GivenName:  givenName, | ||||
| 		User:       *user, | ||||
| @ -538,14 +553,12 @@ func (api headscaleV1APIServer) DebugCreateNode( | ||||
| 		HostInfo: types.HostInfo(hostinfo), | ||||
| 	} | ||||
| 
 | ||||
| 	nodeKey := key.NodePublic{} | ||||
| 	err = nodeKey.UnmarshalText([]byte(request.GetKey())) | ||||
| 	if err != nil { | ||||
| 		log.Panic().Msg("can not add node for debug. invalid node key") | ||||
| 	} | ||||
| 	log.Debug(). | ||||
| 		Str("machine_key", mkey.ShortString()). | ||||
| 		Msg("adding debug machine via CLI, appending to registration cache") | ||||
| 
 | ||||
| 	api.h.registrationCache.Set( | ||||
| 		nodeKey.String(), | ||||
| 		mkey.String(), | ||||
| 		newNode, | ||||
| 		registerCacheExpiration, | ||||
| 	) | ||||
|  | ||||
| @ -12,7 +12,6 @@ import ( | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/gorilla/mux" | ||||
| 	"github.com/juanfont/headscale/hscontrol/util" | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"tailscale.com/tailcfg" | ||||
| 	"tailscale.com/types/key" | ||||
| @ -207,33 +206,16 @@ func (h *Headscale) RegisterWebAPI( | ||||
| 	req *http.Request, | ||||
| ) { | ||||
| 	vars := mux.Vars(req) | ||||
| 	nodeKeyStr, ok := vars["nkey"] | ||||
| 
 | ||||
| 	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 | ||||
| 	} | ||||
| 	machineKeyStr := vars["mkey"] | ||||
| 
 | ||||
| 	// 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 | ||||
| 	// the template and log an error. | ||||
| 	var nodeKey key.NodePublic | ||||
| 	err := nodeKey.UnmarshalText( | ||||
| 		[]byte(nodeKeyStr), | ||||
| 	var machineKey key.MachinePublic | ||||
| 	err := machineKey.UnmarshalText( | ||||
| 		[]byte(machineKeyStr), | ||||
| 	) | ||||
| 
 | ||||
| 	if !ok || nodeKeyStr == "" || err != nil { | ||||
| 	if err != nil { | ||||
| 		log.Warn().Err(err).Msg("Failed to parse incoming nodekey") | ||||
| 
 | ||||
| 		writer.Header().Set("Content-Type", "text/plain; charset=utf-8") | ||||
| @ -251,7 +233,7 @@ func (h *Headscale) RegisterWebAPI( | ||||
| 
 | ||||
| 	var content bytes.Buffer | ||||
| 	if err := registerWebAPITemplate.Execute(&content, registerWebAPITemplateConfig{ | ||||
| 		Key: nodeKeyStr, | ||||
| 		Key: machineKey.String(), | ||||
| 	}); err != nil { | ||||
| 		log.Error(). | ||||
| 			Str("func", "RegisterWebAPI"). | ||||
|  | ||||
| @ -368,17 +368,6 @@ func (m *Mapper) marshalMapResponse( | ||||
| ) ([]byte, error) { | ||||
| 	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) | ||||
| 	if err != nil { | ||||
| 		log.Error(). | ||||
| @ -426,11 +415,11 @@ func (m *Mapper) marshalMapResponse( | ||||
| 	if compression == util.ZstdCompression { | ||||
| 		respBody = zstdEncode(jsonBody) | ||||
| 		if !m.isNoise { // if legacy protocol | ||||
| 			respBody = m.privateKey2019.SealTo(machineKey, respBody) | ||||
| 			respBody = m.privateKey2019.SealTo(node.MachineKey, respBody) | ||||
| 		} | ||||
| 	} else { | ||||
| 		if !m.isNoise { // if legacy protocol | ||||
| 			respBody = m.privateKey2019.SealTo(machineKey, jsonBody) | ||||
| 			respBody = m.privateKey2019.SealTo(node.MachineKey, jsonBody) | ||||
| 		} else { | ||||
| 			respBody = jsonBody | ||||
| 		} | ||||
|  | ||||
| @ -167,9 +167,15 @@ func Test_fullMapResponse(t *testing.T) { | ||||
| 
 | ||||
| 	mini := &types.Node{ | ||||
| 		ID: 0, | ||||
| 		MachineKey:  "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 		NodeKey:     "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		DiscoKey:    "discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 		MachineKey: mustMK( | ||||
| 			"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 		), | ||||
| 		NodeKey: mustNK( | ||||
| 			"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		), | ||||
| 		DiscoKey: mustDK( | ||||
| 			"discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 		), | ||||
| 		IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")}, | ||||
| 		Hostname:    "mini", | ||||
| 		GivenName:   "mini", | ||||
| @ -226,7 +232,6 @@ func Test_fullMapResponse(t *testing.T) { | ||||
| 			netip.MustParsePrefix("0.0.0.0/0"), | ||||
| 			netip.MustParsePrefix("192.168.0.0/24"), | ||||
| 		}, | ||||
| 		Endpoints:         []string{}, | ||||
| 		DERP:              "127.3.3.40:0", | ||||
| 		Hostinfo:          hiview(tailcfg.Hostinfo{}), | ||||
| 		Created:           created, | ||||
| @ -245,9 +250,15 @@ func Test_fullMapResponse(t *testing.T) { | ||||
| 
 | ||||
| 	peer1 := &types.Node{ | ||||
| 		ID: 1, | ||||
| 		MachineKey:  "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 		NodeKey:     "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		DiscoKey:    "discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 		MachineKey: mustMK( | ||||
| 			"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 		), | ||||
| 		NodeKey: mustNK( | ||||
| 			"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		), | ||||
| 		DiscoKey: mustDK( | ||||
| 			"discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 		), | ||||
| 		IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")}, | ||||
| 		Hostname:    "peer1", | ||||
| 		GivenName:   "peer1", | ||||
| @ -278,7 +289,6 @@ func Test_fullMapResponse(t *testing.T) { | ||||
| 		), | ||||
| 		Addresses:         []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", | ||||
| 		Hostinfo:          hiview(tailcfg.Hostinfo{}), | ||||
| 		Created:           created, | ||||
| @ -297,9 +307,15 @@ func Test_fullMapResponse(t *testing.T) { | ||||
| 
 | ||||
| 	peer2 := &types.Node{ | ||||
| 		ID: 2, | ||||
| 		MachineKey:  "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 		NodeKey:     "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		DiscoKey:    "discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 		MachineKey: mustMK( | ||||
| 			"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 		), | ||||
| 		NodeKey: mustNK( | ||||
| 			"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		), | ||||
| 		DiscoKey: mustDK( | ||||
| 			"discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 		), | ||||
| 		IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")}, | ||||
| 		Hostname:    "peer2", | ||||
| 		GivenName:   "peer2", | ||||
|  | ||||
| @ -52,21 +52,6 @@ func tailNode( | ||||
| 	baseDomain string, | ||||
| 	randomClientPort bool, | ||||
| ) (*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() | ||||
| 
 | ||||
| 	allowedIPs := append( | ||||
| @ -112,6 +97,11 @@ func tailNode( | ||||
| 	tags, _ := pol.TagsOfNode(node) | ||||
| 	tags = lo.Uniq(append(tags, node.ForcedTags...)) | ||||
| 
 | ||||
| 	endpoints, err := node.EndpointsToAddrPort() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	tNode := tailcfg.Node{ | ||||
| 		ID: tailcfg.NodeID(node.ID), // this is the actual ID | ||||
| 		StableID: tailcfg.StableNodeID( | ||||
| @ -121,14 +111,14 @@ func tailNode( | ||||
| 
 | ||||
| 		User: tailcfg.UserID(node.UserID), | ||||
| 
 | ||||
| 		Key:       nodeKey, | ||||
| 		Key:       node.NodeKey, | ||||
| 		KeyExpiry: keyExpiry, | ||||
| 
 | ||||
| 		Machine:    machineKey, | ||||
| 		DiscoKey:   discoKey, | ||||
| 		Machine:    node.MachineKey, | ||||
| 		DiscoKey:   node.DiscoKey, | ||||
| 		Addresses:  addrs, | ||||
| 		AllowedIPs: allowedIPs, | ||||
| 		Endpoints:  node.Endpoints, | ||||
| 		Endpoints:  endpoints, | ||||
| 		DERP:       derp, | ||||
| 		Hostinfo:   hostInfo.View(), | ||||
| 		Created:    node.CreatedAt, | ||||
|  | ||||
| @ -58,16 +58,36 @@ func TestTailNode(t *testing.T) { | ||||
| 			pol:        &policy.ACLPolicy{}, | ||||
| 			dnsConfig:  &tailcfg.DNSConfig{}, | ||||
| 			baseDomain: "", | ||||
| 			want:       nil, | ||||
| 			wantErr:    true, | ||||
| 			want: &tailcfg.Node{ | ||||
| 				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", | ||||
| 			node: &types.Node{ | ||||
| 				ID: 0, | ||||
| 				MachineKey: "mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 				NodeKey:    "nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 				DiscoKey:   "discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 				MachineKey: mustMK( | ||||
| 					"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 				), | ||||
| 				NodeKey: mustNK( | ||||
| 					"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 				), | ||||
| 				DiscoKey: mustDK( | ||||
| 					"discokey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 				), | ||||
| 				IPAddresses: []netip.Addr{ | ||||
| 					netip.MustParseAddr("100.64.0.1"), | ||||
| 				}, | ||||
| @ -133,7 +153,6 @@ func TestTailNode(t *testing.T) { | ||||
| 					netip.MustParsePrefix("0.0.0.0/0"), | ||||
| 					netip.MustParsePrefix("192.168.0.0/24"), | ||||
| 				}, | ||||
| 				Endpoints: []string{}, | ||||
| 				DERP:     "127.3.3.40:0", | ||||
| 				Hostinfo: hiview(tailcfg.Hostinfo{}), | ||||
| 				Created:  created, | ||||
|  | ||||
| @ -6,6 +6,7 @@ import ( | ||||
| 	"github.com/juanfont/headscale/hscontrol/types" | ||||
| 	"github.com/juanfont/headscale/hscontrol/util" | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"tailscale.com/types/key" | ||||
| ) | ||||
| 
 | ||||
| type Notifier struct { | ||||
| @ -17,9 +18,9 @@ func NewNotifier() *Notifier { | ||||
| 	return &Notifier{} | ||||
| } | ||||
| 
 | ||||
| func (n *Notifier) AddNode(machineKey string, c chan<- types.StateUpdate) { | ||||
| 	log.Trace().Caller().Str("key", machineKey).Msg("acquiring lock to add node") | ||||
| 	defer log.Trace().Caller().Str("key", machineKey).Msg("releasing lock to add node") | ||||
| func (n *Notifier) AddNode(machineKey key.MachinePublic, c chan<- types.StateUpdate) { | ||||
| 	log.Trace().Caller().Str("key", machineKey.ShortString()).Msg("acquiring lock to add node") | ||||
| 	defer log.Trace().Caller().Str("key", machineKey.ShortString()).Msg("releasing lock to add node") | ||||
| 
 | ||||
| 	n.l.Lock() | ||||
| 	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[machineKey] = c | ||||
| 	n.nodes[machineKey.String()] = c | ||||
| 
 | ||||
| 	log.Trace(). | ||||
| 		Str("machine_key", machineKey). | ||||
| 		Str("machine_key", machineKey.ShortString()). | ||||
| 		Int("open_chans", len(n.nodes)). | ||||
| 		Msg("Added new channel") | ||||
| } | ||||
| 
 | ||||
| func (n *Notifier) RemoveNode(machineKey string) { | ||||
| 	log.Trace().Caller().Str("key", machineKey).Msg("acquiring lock to remove node") | ||||
| 	defer log.Trace().Caller().Str("key", machineKey).Msg("releasing lock to remove node") | ||||
| func (n *Notifier) RemoveNode(machineKey key.MachinePublic) { | ||||
| 	log.Trace().Caller().Str("key", machineKey.ShortString()).Msg("acquiring lock to remove node") | ||||
| 	defer log.Trace().Caller().Str("key", machineKey.ShortString()).Msg("releasing lock to remove node") | ||||
| 
 | ||||
| 	n.l.Lock() | ||||
| 	defer n.l.Unlock() | ||||
| @ -47,10 +48,10 @@ func (n *Notifier) RemoveNode(machineKey string) { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	delete(n.nodes, machineKey) | ||||
| 	delete(n.nodes, machineKey.String()) | ||||
| 
 | ||||
| 	log.Trace(). | ||||
| 		Str("machine_key", machineKey). | ||||
| 		Str("machine_key", machineKey.ShortString()). | ||||
| 		Int("open_chans", len(n.nodes)). | ||||
| 		Msg("Removed channel") | ||||
| } | ||||
|  | ||||
| @ -90,42 +90,28 @@ func (h *Headscale) determineTokenExpiration(idTokenExpiration time.Time) time.T | ||||
| 
 | ||||
| // RegisterOIDC redirects to the OIDC provider for authentication | ||||
| // 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( | ||||
| 	writer http.ResponseWriter, | ||||
| 	req *http.Request, | ||||
| ) { | ||||
| 	vars := mux.Vars(req) | ||||
| 	nodeKeyStr, ok := vars["nkey"] | ||||
| 	machineKeyStr, ok := vars["mkey"] | ||||
| 
 | ||||
| 	log.Debug(). | ||||
| 		Caller(). | ||||
| 		Str("node_key", nodeKeyStr). | ||||
| 		Str("machine_key", machineKeyStr). | ||||
| 		Bool("ok", ok). | ||||
| 		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 | ||||
| 	// is passed as a key is not parsable/validated as a NodePublic key, then fail to render | ||||
| 	// the template and log an error. | ||||
| 	var nodeKey key.NodePublic | ||||
| 	err := nodeKey.UnmarshalText( | ||||
| 		[]byte(nodeKeyStr), | ||||
| 	var machineKey key.MachinePublic | ||||
| 	err := machineKey.UnmarshalText( | ||||
| 		[]byte(machineKeyStr), | ||||
| 	) | ||||
| 
 | ||||
| 	if !ok || nodeKeyStr == "" || err != nil { | ||||
| 	if err != nil { | ||||
| 		log.Warn(). | ||||
| 			Err(err). | ||||
| 			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 | ||||
| 	h.registrationCache.Set( | ||||
| 		stateStr, | ||||
| 		nodeKey, | ||||
| 		machineKey, | ||||
| 		registerCacheExpiration, | ||||
| 	) | ||||
| 
 | ||||
| @ -232,7 +218,7 @@ func (h *Headscale) OIDCCallback( | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	nodeKey, nodeExists, err := h.validateNodeForOIDCCallback( | ||||
| 	machineKey, nodeExists, err := h.validateNodeForOIDCCallback( | ||||
| 		writer, | ||||
| 		state, | ||||
| 		claims, | ||||
| @ -255,7 +241,7 @@ func (h *Headscale) OIDCCallback( | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if err := h.registerNodeForOIDCCallback(writer, user, nodeKey, idTokenExpiry); err != nil { | ||||
| 	if err := h.registerNodeForOIDCCallback(writer, user, machineKey, idTokenExpiry); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| @ -462,10 +448,10 @@ func (h *Headscale) validateNodeForOIDCCallback( | ||||
| 	state string, | ||||
| 	claims *IDTokenClaims, | ||||
| 	expiry time.Time, | ||||
| ) (*key.NodePublic, bool, error) { | ||||
| ) (*key.MachinePublic, bool, error) { | ||||
| 	// retrieve nodekey from state cache | ||||
| 	nodeKeyIf, nodeKeyFound := h.registrationCache.Get(state) | ||||
| 	if !nodeKeyFound { | ||||
| 	machineKeyIf, machineKeyFound := h.registrationCache.Get(state) | ||||
| 	if !machineKeyFound { | ||||
| 		log.Trace(). | ||||
| 			Msg("requested node state key expired before authorisation completed") | ||||
| 		writer.Header().Set("Content-Type", "text/plain; charset=utf-8") | ||||
| @ -478,11 +464,11 @@ func (h *Headscale) validateNodeForOIDCCallback( | ||||
| 		return nil, false, errOIDCNodeKeyMissing | ||||
| 	} | ||||
| 
 | ||||
| 	var nodeKey key.NodePublic | ||||
| 	nodeKey, nodeKeyOK := nodeKeyIf.(key.NodePublic) | ||||
| 	if !nodeKeyOK { | ||||
| 	var machineKey key.MachinePublic | ||||
| 	machineKey, machineKeyOK := machineKeyIf.(key.MachinePublic) | ||||
| 	if !machineKeyOK { | ||||
| 		log.Trace(). | ||||
| 			Interface("got", nodeKeyIf). | ||||
| 			Interface("got", machineKeyIf). | ||||
| 			Msg("requested node state key is not a nodekey") | ||||
| 		writer.Header().Set("Content-Type", "text/plain; charset=utf-8") | ||||
| 		writer.WriteHeader(http.StatusBadRequest) | ||||
| @ -498,7 +484,7 @@ func (h *Headscale) validateNodeForOIDCCallback( | ||||
| 	// The error is not important, because if it does not | ||||
| 	// exist, then this is a new node and we will move | ||||
| 	// on to registration. | ||||
| 	node, _ := h.db.GetNodeByNodeKey(nodeKey) | ||||
| 	node, _ := h.db.GetNodeByMachineKey(machineKey) | ||||
| 
 | ||||
| 	if node != nil { | ||||
| 		log.Trace(). | ||||
| @ -553,7 +539,7 @@ func (h *Headscale) validateNodeForOIDCCallback( | ||||
| 		return nil, true, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return &nodeKey, false, nil | ||||
| 	return &machineKey, false, nil | ||||
| } | ||||
| 
 | ||||
| func getUserName( | ||||
| @ -624,13 +610,13 @@ func (h *Headscale) findOrCreateNewUserForOIDCCallback( | ||||
| func (h *Headscale) registerNodeForOIDCCallback( | ||||
| 	writer http.ResponseWriter, | ||||
| 	user *types.User, | ||||
| 	nodeKey *key.NodePublic, | ||||
| 	machineKey *key.MachinePublic, | ||||
| 	expiry time.Time, | ||||
| ) error { | ||||
| 	if _, err := h.db.RegisterNodeFromAuthCallback( | ||||
| 		// TODO(kradalby): find a better way to use the cache across modules | ||||
| 		h.registrationCache, | ||||
| 		nodeKey.String(), | ||||
| 		*machineKey, | ||||
| 		user.Name, | ||||
| 		&expiry, | ||||
| 		util.RegisterMethodOIDC, | ||||
|  | ||||
| @ -14,12 +14,29 @@ import ( | ||||
| 	"go4.org/netipx" | ||||
| 	"gopkg.in/check.v1" | ||||
| 	"tailscale.com/tailcfg" | ||||
| 	"tailscale.com/types/key" | ||||
| ) | ||||
| 
 | ||||
| var ipComparer = cmp.Comparer(func(x, y netip.Addr) bool { | ||||
| 	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) { | ||||
| 	check.TestingT(t) | ||||
| } | ||||
| @ -951,7 +968,7 @@ func Test_listNodesInUser(t *testing.T) { | ||||
| 		t.Run(test.name, func(t *testing.T) { | ||||
| 			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) | ||||
| 			} | ||||
| 		}) | ||||
| @ -1704,7 +1721,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) { | ||||
| 				test.args.nodes, | ||||
| 				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) | ||||
| 			} | ||||
| 		}) | ||||
| @ -2723,7 +2740,7 @@ func Test_getFilteredByACLPeers(t *testing.T) { | ||||
| 				tt.args.nodes, | ||||
| 				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) | ||||
| 			} | ||||
| 		}) | ||||
| @ -2986,9 +3003,6 @@ func TestValidExpandTagOwnersInSources(t *testing.T) { | ||||
| 
 | ||||
| 	node := &types.Node{ | ||||
| 		ID:          0, | ||||
| 		MachineKey:  "foo", | ||||
| 		NodeKey:     "bar", | ||||
| 		DiscoKey:    "faa", | ||||
| 		Hostname:    "testnodes", | ||||
| 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.1")}, | ||||
| 		UserID:      0, | ||||
| @ -3041,9 +3055,6 @@ func TestInvalidTagValidUser(t *testing.T) { | ||||
| 
 | ||||
| 	node := &types.Node{ | ||||
| 		ID:          1, | ||||
| 		MachineKey:  "12345", | ||||
| 		NodeKey:     "bar", | ||||
| 		DiscoKey:    "faa", | ||||
| 		Hostname:    "testnodes", | ||||
| 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.1")}, | ||||
| 		UserID:      1, | ||||
| @ -3095,9 +3106,6 @@ func TestValidExpandTagOwnersInDestinations(t *testing.T) { | ||||
| 
 | ||||
| 	node := &types.Node{ | ||||
| 		ID:          1, | ||||
| 		MachineKey:  "12345", | ||||
| 		NodeKey:     "bar", | ||||
| 		DiscoKey:    "faa", | ||||
| 		Hostname:    "testnodes", | ||||
| 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.1")}, | ||||
| 		UserID:      1, | ||||
| @ -3159,9 +3167,6 @@ func TestValidTagInvalidUser(t *testing.T) { | ||||
| 
 | ||||
| 	node := &types.Node{ | ||||
| 		ID:          1, | ||||
| 		MachineKey:  "12345", | ||||
| 		NodeKey:     "bar", | ||||
| 		DiscoKey:    "faa", | ||||
| 		Hostname:    "webserver", | ||||
| 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.1")}, | ||||
| 		UserID:      1, | ||||
| @ -3179,9 +3184,6 @@ func TestValidTagInvalidUser(t *testing.T) { | ||||
| 
 | ||||
| 	nodes2 := &types.Node{ | ||||
| 		ID:          2, | ||||
| 		MachineKey:  "56789", | ||||
| 		NodeKey:     "bar2", | ||||
| 		DiscoKey:    "faab", | ||||
| 		Hostname:    "user", | ||||
| 		IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.2")}, | ||||
| 		UserID:      1, | ||||
|  | ||||
| @ -34,7 +34,7 @@ func logPollFunc( | ||||
| 				Bool("readOnly", mapRequest.ReadOnly). | ||||
| 				Bool("omitPeers", mapRequest.OmitPeers). | ||||
| 				Bool("stream", mapRequest.Stream). | ||||
| 				Str("node_key", node.NodeKey). | ||||
| 				Str("node_key", node.NodeKey.ShortString()). | ||||
| 				Str("node", node.Hostname). | ||||
| 				Msg(msg) | ||||
| 		}, | ||||
| @ -45,7 +45,7 @@ func logPollFunc( | ||||
| 				Bool("readOnly", mapRequest.ReadOnly). | ||||
| 				Bool("omitPeers", mapRequest.OmitPeers). | ||||
| 				Bool("stream", mapRequest.Stream). | ||||
| 				Str("node_key", node.NodeKey). | ||||
| 				Str("node_key", node.NodeKey.ShortString()). | ||||
| 				Str("node", node.Hostname). | ||||
| 				Err(err). | ||||
| 				Msg(msg) | ||||
| @ -81,7 +81,7 @@ func (h *Headscale) handlePoll( | ||||
| 			Bool("readOnly", mapRequest.ReadOnly). | ||||
| 			Bool("omitPeers", mapRequest.OmitPeers). | ||||
| 			Bool("stream", mapRequest.Stream). | ||||
| 			Str("node_key", node.NodeKey). | ||||
| 			Str("node_key", node.NodeKey.ShortString()). | ||||
| 			Str("node", node.Hostname). | ||||
| 			Strs("endpoints", node.Endpoints). | ||||
| 			Msg("Received endpoint update") | ||||
| @ -90,8 +90,8 @@ func (h *Headscale) handlePoll( | ||||
| 		node.LastSeen = &now | ||||
| 		node.Hostname = mapRequest.Hostinfo.Hostname | ||||
| 		node.HostInfo = types.HostInfo(*mapRequest.Hostinfo) | ||||
| 		node.DiscoKey = mapRequest.DiscoKey.String() | ||||
| 		node.Endpoints = mapRequest.Endpoints | ||||
| 		node.DiscoKey = mapRequest.DiscoKey | ||||
| 		node.SetEndpointsFromAddrPorts(mapRequest.Endpoints) | ||||
| 
 | ||||
| 		if err := h.db.NodeSave(node); err != nil { | ||||
| 			logErr(err, "Failed to persist/update node in the database") | ||||
| @ -113,7 +113,7 @@ func (h *Headscale) handlePoll( | ||||
| 				Type:    types.StatePeerChanged, | ||||
| 				Changed: types.Nodes{node}, | ||||
| 			}, | ||||
| 			node.MachineKey) | ||||
| 			node.MachineKey.String()) | ||||
| 
 | ||||
| 		writer.WriteHeader(http.StatusOK) | ||||
| 		if f, ok := writer.(http.Flusher); ok { | ||||
| @ -143,8 +143,8 @@ func (h *Headscale) handlePoll( | ||||
| 	node.LastSeen = &now | ||||
| 	node.Hostname = mapRequest.Hostinfo.Hostname | ||||
| 	node.HostInfo = types.HostInfo(*mapRequest.Hostinfo) | ||||
| 	node.DiscoKey = mapRequest.DiscoKey.String() | ||||
| 	node.Endpoints = mapRequest.Endpoints | ||||
| 	node.DiscoKey = mapRequest.DiscoKey | ||||
| 	node.SetEndpointsFromAddrPorts(mapRequest.Endpoints) | ||||
| 
 | ||||
| 	// When a node connects to control, list the peers it has at | ||||
| 	// that given point, further updates are kept in memory in | ||||
| @ -222,7 +222,7 @@ func (h *Headscale) handlePoll( | ||||
| 			Type:    types.StatePeerChanged, | ||||
| 			Changed: types.Nodes{node}, | ||||
| 		}, | ||||
| 		node.MachineKey) | ||||
| 		node.MachineKey.String()) | ||||
| 
 | ||||
| 	// Set up the client stream | ||||
| 	h.pollNetMapStreamWG.Add(1) | ||||
| @ -342,7 +342,7 @@ func (h *Headscale) handlePoll( | ||||
| 				Bool("readOnly", mapRequest.ReadOnly). | ||||
| 				Bool("omitPeers", mapRequest.OmitPeers). | ||||
| 				Bool("stream", mapRequest.Stream). | ||||
| 				Str("node_key", node.NodeKey). | ||||
| 				Str("node_key", node.NodeKey.ShortString()). | ||||
| 				Str("node", node.Hostname). | ||||
| 				TimeDiff("timeSpent", time.Now(), now). | ||||
| 				Msg("update sent") | ||||
|  | ||||
| @ -13,6 +13,7 @@ import ( | ||||
| 	"github.com/juanfont/headscale/hscontrol/policy/matcher" | ||||
| 	"go4.org/netipx" | ||||
| 	"google.golang.org/protobuf/types/known/timestamppb" | ||||
| 	"gorm.io/gorm" | ||||
| 	"tailscale.com/tailcfg" | ||||
| 	"tailscale.com/types/key" | ||||
| ) | ||||
| @ -25,9 +26,29 @@ var ( | ||||
| // Node is a Headscale client. | ||||
| type Node struct { | ||||
| 	ID uint64 `gorm:"primary_key"` | ||||
| 	MachineKey  string `gorm:"type:varchar(64);unique_index"` | ||||
| 	NodeKey     string | ||||
| 	DiscoKey    string | ||||
| 
 | ||||
| 	// MachineKeyValue is the string representation of MachineKey | ||||
| 	// 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 | ||||
| 
 | ||||
| 	// Hostname represents the name given by the Tailscale | ||||
| @ -174,6 +195,31 @@ func (node Node) IsExpired() bool { | ||||
| 	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. | ||||
| // This is really a naive implementation, as we don't really see | ||||
| // 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 | ||||
| } | ||||
| 
 | ||||
| // 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 { | ||||
| 	nodeProto := &v1.Node{ | ||||
| 		Id:         node.ID, | ||||
| 		MachineKey: node.MachineKey, | ||||
| 		MachineKey: node.MachineKey.String(), | ||||
| 
 | ||||
| 		NodeKey:     node.NodeKey, | ||||
| 		DiscoKey:    node.DiscoKey, | ||||
| 		NodeKey:     node.NodeKey.String(), | ||||
| 		DiscoKey:    node.DiscoKey.String(), | ||||
| 		IpAddresses: node.IPAddresses.StringSlice(), | ||||
| 		Name:        node.Hostname, | ||||
| 		GivenName:   node.GivenName, | ||||
| @ -289,47 +374,6 @@ func (node *Node) GetFQDN(dnsConfig *tailcfg.DNSConfig, baseDomain string) (stri | ||||
| 	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 { | ||||
| 	return node.Hostname | ||||
| } | ||||
|  | ||||
| @ -683,8 +683,8 @@ func TestNodeTagCommand(t *testing.T) { | ||||
| 	assertNoErr(t, err) | ||||
| 
 | ||||
| 	machineKeys := []string{ | ||||
| 		"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||
| 		"mkey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		"mkey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||
| 	} | ||||
| 	nodes := make([]*v1.Node, len(machineKeys)) | ||||
| 	assert.Nil(t, err) | ||||
| @ -816,13 +816,13 @@ func TestNodeCommand(t *testing.T) { | ||||
| 	headscale, err := scenario.Headscale() | ||||
| 	assertNoErr(t, err) | ||||
| 
 | ||||
| 	// Randomly generated node keys | ||||
| 	// Pregenerated machine keys | ||||
| 	machineKeys := []string{ | ||||
| 		"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||
| 		"nodekey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 		"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1", | ||||
| 		"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 		"mkey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		"mkey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||
| 		"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 		"mkey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1", | ||||
| 		"mkey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 	} | ||||
| 	nodes := make([]*v1.Node, len(machineKeys)) | ||||
| 	assert.Nil(t, err) | ||||
| @ -898,8 +898,8 @@ func TestNodeCommand(t *testing.T) { | ||||
| 	assert.Equal(t, "node-5", listAll[4].Name) | ||||
| 
 | ||||
| 	otherUserMachineKeys := []string{ | ||||
| 		"nodekey:b5b444774186d4217adcec407563a1223929465ee2c68a4da13af0d0185b4f8e", | ||||
| 		"nodekey:dc721977ac7415aafa87f7d4574cbe07c6b171834a6d37375782bdc1fb6b3584", | ||||
| 		"mkey:b5b444774186d4217adcec407563a1223929465ee2c68a4da13af0d0185b4f8e", | ||||
| 		"mkey:dc721977ac7415aafa87f7d4574cbe07c6b171834a6d37375782bdc1fb6b3584", | ||||
| 	} | ||||
| 	otherUserMachines := make([]*v1.Node, len(otherUserMachineKeys)) | ||||
| 	assert.Nil(t, err) | ||||
| @ -1056,13 +1056,13 @@ func TestNodeExpireCommand(t *testing.T) { | ||||
| 	headscale, err := scenario.Headscale() | ||||
| 	assertNoErr(t, err) | ||||
| 
 | ||||
| 	// Randomly generated node keys | ||||
| 	// Pregenerated machine keys | ||||
| 	machineKeys := []string{ | ||||
| 		"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||
| 		"nodekey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 		"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1", | ||||
| 		"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 		"mkey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		"mkey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||
| 		"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 		"mkey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1", | ||||
| 		"mkey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 	} | ||||
| 	nodes := make([]*v1.Node, len(machineKeys)) | ||||
| 
 | ||||
| @ -1183,13 +1183,13 @@ func TestNodeRenameCommand(t *testing.T) { | ||||
| 	headscale, err := scenario.Headscale() | ||||
| 	assertNoErr(t, err) | ||||
| 
 | ||||
| 	// Randomly generated node keys | ||||
| 	// Pregenerated machine keys | ||||
| 	machineKeys := []string{ | ||||
| 		"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 		"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1", | ||||
| 		"nodekey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 		"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||
| 		"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		"mkey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 		"mkey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1", | ||||
| 		"mkey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 		"mkey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||
| 		"mkey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 	} | ||||
| 	nodes := make([]*v1.Node, len(machineKeys)) | ||||
| 	assert.Nil(t, err) | ||||
| @ -1210,7 +1210,7 @@ func TestNodeRenameCommand(t *testing.T) { | ||||
| 				"json", | ||||
| 			}, | ||||
| 		) | ||||
| 		assert.Nil(t, err) | ||||
| 		assertNoErr(t, err) | ||||
| 
 | ||||
| 		var node v1.Node | ||||
| 		err = executeAndUnmarshal( | ||||
| @ -1228,7 +1228,7 @@ func TestNodeRenameCommand(t *testing.T) { | ||||
| 			}, | ||||
| 			&node, | ||||
| 		) | ||||
| 		assert.Nil(t, err) | ||||
| 		assertNoErr(t, err) | ||||
| 
 | ||||
| 		nodes[index] = &node | ||||
| 	} | ||||
| @ -1350,7 +1350,7 @@ func TestNodeMoveCommand(t *testing.T) { | ||||
| 	assertNoErr(t, err) | ||||
| 
 | ||||
| 	// Randomly generated node key | ||||
| 	machineKey := "nodekey:688411b767663479632d44140f08a9fde87383adc7cdeb518f62ce28a17ef0aa" | ||||
| 	machineKey := "mkey:688411b767663479632d44140f08a9fde87383adc7cdeb518f62ce28a17ef0aa" | ||||
| 
 | ||||
| 	_, err = headscale.Execute( | ||||
| 		[]string{ | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user