mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	Merge branch 'main' into fix-derp-example-config
This commit is contained in:
		
						commit
						45bc3f7a09
					
				| @ -25,9 +25,6 @@ linters: | ||||
|     - godox | ||||
|     - ireturn | ||||
| 
 | ||||
|     # In progress | ||||
|     - gocritic | ||||
| 
 | ||||
|     # We should strive to enable these: | ||||
|     - wrapcheck | ||||
|     - dupl | ||||
| @ -51,3 +48,9 @@ linters-settings: | ||||
|       - ip | ||||
|       - ok | ||||
|       - c | ||||
| 
 | ||||
|   gocritic: | ||||
|     disabled-checks: | ||||
|       - appendAssign | ||||
|       # TODO(kradalby): Remove this | ||||
|       - ifElseChain | ||||
|  | ||||
| @ -100,7 +100,7 @@ func (s *Suite) TestPortNamespace(c *check.C) { | ||||
| 		Name:           "testmachine", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      ip.String(), | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 	} | ||||
| @ -142,7 +142,7 @@ func (s *Suite) TestPortGroup(c *check.C) { | ||||
| 		Name:           "testmachine", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      ip.String(), | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										466
									
								
								api.go
									
									
									
									
									
								
							
							
						
						
									
										466
									
								
								api.go
									
									
									
									
									
								
							| @ -18,7 +18,15 @@ import ( | ||||
| 	"tailscale.com/types/wgkey" | ||||
| ) | ||||
| 
 | ||||
| const reservedResponseHeaderSize = 4 | ||||
| const ( | ||||
| 	reservedResponseHeaderSize               = 4 | ||||
| 	RegisterMethodAuthKey                    = "authKey" | ||||
| 	RegisterMethodOIDC                       = "oidc" | ||||
| 	RegisterMethodCLI                        = "cli" | ||||
| 	ErrRegisterMethodCLIDoesNotSupportExpire = Error( | ||||
| 		"machines registered with CLI does not support expire", | ||||
| 	) | ||||
| ) | ||||
| 
 | ||||
| // KeyHandler provides the Headscale pub key
 | ||||
| // Listens in /key.
 | ||||
| @ -111,178 +119,52 @@ func (h *Headscale) RegistrationHandler(ctx *gin.Context) { | ||||
| 		machine = &newMachine | ||||
| 	} | ||||
| 
 | ||||
| 	if !machine.Registered && req.Auth.AuthKey != "" { | ||||
| 		h.handleAuthKey(ctx, h.db, machineKey, req, *machine) | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	resp := tailcfg.RegisterResponse{} | ||||
| 
 | ||||
| 	// We have the updated key!
 | ||||
| 	if machine.NodeKey == wgkey.Key(req.NodeKey).HexString() { | ||||
| 		// 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 !req.Expiry.IsZero() && req.Expiry.UTC().Before(now) { | ||||
| 			log.Info(). | ||||
| 				Str("handler", "Registration"). | ||||
| 				Str("machine", machine.Name). | ||||
| 				Msg("Client requested logout") | ||||
| 
 | ||||
| 			machine.Expiry = &req.Expiry // save the expiry so that the machine is marked as expired
 | ||||
| 			h.db.Save(&machine) | ||||
| 
 | ||||
| 			resp.AuthURL = "" | ||||
| 			resp.MachineAuthorized = false | ||||
| 			resp.User = *machine.Namespace.toUser() | ||||
| 			respBody, err := encode(resp, &machineKey, h.privateKey) | ||||
| 			if err != nil { | ||||
| 				log.Error(). | ||||
| 					Str("handler", "Registration"). | ||||
| 					Err(err). | ||||
| 					Msg("Cannot encode message") | ||||
| 				ctx.String(http.StatusInternalServerError, "") | ||||
| 	if machine.Registered { | ||||
| 		// If the NodeKey stored in headscale is the same as the key presented in a registration
 | ||||
| 		// request, then we have a node that is either:
 | ||||
| 		// - Trying to log out (sending a expiry in the past)
 | ||||
| 		// - A valid, registered machine, looking for the node map
 | ||||
| 		// - Expired machine wanting to reauthenticate
 | ||||
| 		if machine.NodeKey == wgkey.Key(req.NodeKey).HexString() { | ||||
| 			// 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 !req.Expiry.IsZero() && req.Expiry.UTC().Before(now) { | ||||
| 				h.handleMachineLogOut(ctx, machineKey, *machine) | ||||
| 
 | ||||
| 				return | ||||
| 			} | ||||
| 			ctx.Data(http.StatusOK, "application/json; charset=utf-8", respBody) | ||||
| 
 | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		if machine.Registered && machine.Expiry.UTC().After(now) { | ||||
| 			// The machine registration is valid, respond with redirect to /map
 | ||||
| 			log.Debug(). | ||||
| 				Str("handler", "Registration"). | ||||
| 				Str("machine", machine.Name). | ||||
| 				Msg("Client is registered and we have the current NodeKey. All clear to /map") | ||||
| 
 | ||||
| 			resp.AuthURL = "" | ||||
| 			resp.MachineAuthorized = true | ||||
| 			resp.User = *machine.Namespace.toUser() | ||||
| 			resp.Login = *machine.Namespace.toLogin() | ||||
| 
 | ||||
| 			respBody, err := encode(resp, &machineKey, h.privateKey) | ||||
| 			if err != nil { | ||||
| 				log.Error(). | ||||
| 					Str("handler", "Registration"). | ||||
| 					Err(err). | ||||
| 					Msg("Cannot encode message") | ||||
| 				machineRegistrations.WithLabelValues("update", "web", "error", machine.Namespace.Name). | ||||
| 					Inc() | ||||
| 				ctx.String(http.StatusInternalServerError, "") | ||||
| 			// If machine is not expired, and is register, we have a already accepted this machine,
 | ||||
| 			// let it proceed with a valid registration
 | ||||
| 			if !machine.isExpired() { | ||||
| 				h.handleMachineValidRegistration(ctx, machineKey, *machine) | ||||
| 
 | ||||
| 				return | ||||
| 			} | ||||
| 			machineRegistrations.WithLabelValues("update", "web", "success", machine.Namespace.Name). | ||||
| 				Inc() | ||||
| 			ctx.Data(http.StatusOK, "application/json; charset=utf-8", respBody) | ||||
| 		} | ||||
| 
 | ||||
| 		// The NodeKey we have matches OldNodeKey, which means this is a refresh after a key expiration
 | ||||
| 		if machine.NodeKey == wgkey.Key(req.OldNodeKey).HexString() && | ||||
| 			!machine.isExpired() { | ||||
| 			h.handleMachineRefreshKey(ctx, machineKey, req, *machine) | ||||
| 
 | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		// The client has registered before, but has expired
 | ||||
| 		log.Debug(). | ||||
| 			Str("handler", "Registration"). | ||||
| 			Str("machine", machine.Name). | ||||
| 			Msg("Machine registration has expired. Sending a authurl to register") | ||||
| 
 | ||||
| 		if h.cfg.OIDC.Issuer != "" { | ||||
| 			resp.AuthURL = fmt.Sprintf("%s/oidc/register/%s", | ||||
| 				strings.TrimSuffix(h.cfg.ServerURL, "/"), machineKey.HexString()) | ||||
| 		} else { | ||||
| 			resp.AuthURL = fmt.Sprintf("%s/register?key=%s", | ||||
| 				strings.TrimSuffix(h.cfg.ServerURL, "/"), machineKey.HexString()) | ||||
| 		} | ||||
| 
 | ||||
| 		// When a client connects, it may request a specific expiry time in its
 | ||||
| 		// RegisterRequest (https://github.com/tailscale/tailscale/blob/main/tailcfg/tailcfg.go#L634)
 | ||||
| 		// RequestedExpiry is used to store the clients requested expiry time since the authentication flow is broken
 | ||||
| 		// into two steps (which cant pass arbitrary data between them easily) and needs to be
 | ||||
| 		// retrieved again after the user has authenticated. After the authentication flow
 | ||||
| 		// completes, RequestedExpiry is copied into Expiry.
 | ||||
| 		machine.RequestedExpiry = &req.Expiry | ||||
| 
 | ||||
| 		h.db.Save(&machine) | ||||
| 
 | ||||
| 		respBody, err := encode(resp, &machineKey, h.privateKey) | ||||
| 		if err != nil { | ||||
| 			log.Error(). | ||||
| 				Str("handler", "Registration"). | ||||
| 				Err(err). | ||||
| 				Msg("Cannot encode message") | ||||
| 			machineRegistrations.WithLabelValues("new", "web", "error", machine.Namespace.Name). | ||||
| 				Inc() | ||||
| 			ctx.String(http.StatusInternalServerError, "") | ||||
| 
 | ||||
| 			return | ||||
| 		} | ||||
| 		machineRegistrations.WithLabelValues("new", "web", "success", machine.Namespace.Name). | ||||
| 			Inc() | ||||
| 		ctx.Data(http.StatusOK, "application/json; charset=utf-8", respBody) | ||||
| 		// The machine has expired
 | ||||
| 		h.handleMachineExpired(ctx, machineKey, req, *machine) | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// The NodeKey we have matches OldNodeKey, which means this is a refresh after a key expiration
 | ||||
| 	if machine.NodeKey == wgkey.Key(req.OldNodeKey).HexString() && | ||||
| 		machine.Expiry.UTC().After(now) { | ||||
| 		log.Debug(). | ||||
| 			Str("handler", "Registration"). | ||||
| 			Str("machine", machine.Name). | ||||
| 			Msg("We have the OldNodeKey in the database. This is a key refresh") | ||||
| 		machine.NodeKey = wgkey.Key(req.NodeKey).HexString() | ||||
| 		h.db.Save(&machine) | ||||
| 
 | ||||
| 		resp.AuthURL = "" | ||||
| 		resp.User = *machine.Namespace.toUser() | ||||
| 		respBody, err := encode(resp, &machineKey, h.privateKey) | ||||
| 		if err != nil { | ||||
| 			log.Error(). | ||||
| 				Str("handler", "Registration"). | ||||
| 				Err(err). | ||||
| 				Msg("Cannot encode message") | ||||
| 			ctx.String(http.StatusInternalServerError, "Extremely sad!") | ||||
| 
 | ||||
| 			return | ||||
| 		} | ||||
| 		ctx.Data(http.StatusOK, "application/json; charset=utf-8", respBody) | ||||
| 	// If the machine has AuthKey set, handle registration via PreAuthKeys
 | ||||
| 	if req.Auth.AuthKey != "" { | ||||
| 		h.handleAuthKey(ctx, machineKey, req, *machine) | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// The machine registration is new, redirect the client to the registration URL
 | ||||
| 	log.Debug(). | ||||
| 		Str("handler", "Registration"). | ||||
| 		Str("machine", machine.Name). | ||||
| 		Msg("The node is sending us a new NodeKey, sending auth url") | ||||
| 	if h.cfg.OIDC.Issuer != "" { | ||||
| 		resp.AuthURL = fmt.Sprintf( | ||||
| 			"%s/oidc/register/%s", | ||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | ||||
| 			machineKey.HexString(), | ||||
| 		) | ||||
| 	} else { | ||||
| 		resp.AuthURL = fmt.Sprintf("%s/register?key=%s", | ||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), machineKey.HexString()) | ||||
| 	} | ||||
| 
 | ||||
| 	// save the requested expiry time for retrieval later in the authentication flow
 | ||||
| 	machine.RequestedExpiry = &req.Expiry | ||||
| 	machine.NodeKey = wgkey.Key(req.NodeKey).HexString() // save the NodeKey
 | ||||
| 	h.db.Save(&machine) | ||||
| 
 | ||||
| 	respBody, err := encode(resp, &machineKey, h.privateKey) | ||||
| 	if err != nil { | ||||
| 		log.Error(). | ||||
| 			Str("handler", "Registration"). | ||||
| 			Err(err). | ||||
| 			Msg("Cannot encode message") | ||||
| 		ctx.String(http.StatusInternalServerError, "") | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 	ctx.Data(http.StatusOK, "application/json; charset=utf-8", respBody) | ||||
| 	h.handleMachineRegistrationNew(ctx, machineKey, req, *machine) | ||||
| } | ||||
| 
 | ||||
| func (h *Headscale) getMapResponse( | ||||
| @ -304,7 +186,7 @@ func (h *Headscale) getMapResponse( | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	peers, err := h.getPeers(machine) | ||||
| 	peers, err := h.getValidPeers(machine) | ||||
| 	if err != nil { | ||||
| 		log.Error(). | ||||
| 			Str("func", "getMapResponse"). | ||||
| @ -404,19 +286,211 @@ func (h *Headscale) getMapKeepAliveResponse( | ||||
| 	return data, nil | ||||
| } | ||||
| 
 | ||||
| func (h *Headscale) handleMachineLogOut( | ||||
| 	ctx *gin.Context, | ||||
| 	machineKey wgkey.Key, | ||||
| 	machine Machine, | ||||
| ) { | ||||
| 	resp := tailcfg.RegisterResponse{} | ||||
| 
 | ||||
| 	log.Info(). | ||||
| 		Str("handler", "Registration"). | ||||
| 		Str("machine", machine.Name). | ||||
| 		Msg("Client requested logout") | ||||
| 
 | ||||
| 	h.ExpireMachine(&machine) | ||||
| 
 | ||||
| 	resp.AuthURL = "" | ||||
| 	resp.MachineAuthorized = false | ||||
| 	resp.User = *machine.Namespace.toUser() | ||||
| 	respBody, err := encode(resp, &machineKey, h.privateKey) | ||||
| 	if err != nil { | ||||
| 		log.Error(). | ||||
| 			Str("handler", "Registration"). | ||||
| 			Err(err). | ||||
| 			Msg("Cannot encode message") | ||||
| 		ctx.String(http.StatusInternalServerError, "") | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 	ctx.Data(http.StatusOK, "application/json; charset=utf-8", respBody) | ||||
| } | ||||
| 
 | ||||
| func (h *Headscale) handleMachineValidRegistration( | ||||
| 	ctx *gin.Context, | ||||
| 	machineKey wgkey.Key, | ||||
| 	machine Machine, | ||||
| ) { | ||||
| 	resp := tailcfg.RegisterResponse{} | ||||
| 
 | ||||
| 	// The machine registration is valid, respond with redirect to /map
 | ||||
| 	log.Debug(). | ||||
| 		Str("handler", "Registration"). | ||||
| 		Str("machine", machine.Name). | ||||
| 		Msg("Client is registered and we have the current NodeKey. All clear to /map") | ||||
| 
 | ||||
| 	resp.AuthURL = "" | ||||
| 	resp.MachineAuthorized = true | ||||
| 	resp.User = *machine.Namespace.toUser() | ||||
| 	resp.Login = *machine.Namespace.toLogin() | ||||
| 
 | ||||
| 	respBody, err := encode(resp, &machineKey, h.privateKey) | ||||
| 	if err != nil { | ||||
| 		log.Error(). | ||||
| 			Str("handler", "Registration"). | ||||
| 			Err(err). | ||||
| 			Msg("Cannot encode message") | ||||
| 		machineRegistrations.WithLabelValues("update", "web", "error", machine.Namespace.Name). | ||||
| 			Inc() | ||||
| 		ctx.String(http.StatusInternalServerError, "") | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 	machineRegistrations.WithLabelValues("update", "web", "success", machine.Namespace.Name). | ||||
| 		Inc() | ||||
| 	ctx.Data(http.StatusOK, "application/json; charset=utf-8", respBody) | ||||
| } | ||||
| 
 | ||||
| func (h *Headscale) handleMachineExpired( | ||||
| 	ctx *gin.Context, | ||||
| 	machineKey wgkey.Key, | ||||
| 	registerRequest tailcfg.RegisterRequest, | ||||
| 	machine Machine, | ||||
| ) { | ||||
| 	resp := tailcfg.RegisterResponse{} | ||||
| 
 | ||||
| 	// The client has registered before, but has expired
 | ||||
| 	log.Debug(). | ||||
| 		Str("handler", "Registration"). | ||||
| 		Str("machine", machine.Name). | ||||
| 		Msg("Machine registration has expired. Sending a authurl to register") | ||||
| 
 | ||||
| 	if registerRequest.Auth.AuthKey != "" { | ||||
| 		h.handleAuthKey(ctx, machineKey, registerRequest, machine) | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if h.cfg.OIDC.Issuer != "" { | ||||
| 		resp.AuthURL = fmt.Sprintf("%s/oidc/register/%s", | ||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), machineKey.HexString()) | ||||
| 	} else { | ||||
| 		resp.AuthURL = fmt.Sprintf("%s/register?key=%s", | ||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), machineKey.HexString()) | ||||
| 	} | ||||
| 
 | ||||
| 	respBody, err := encode(resp, &machineKey, h.privateKey) | ||||
| 	if err != nil { | ||||
| 		log.Error(). | ||||
| 			Str("handler", "Registration"). | ||||
| 			Err(err). | ||||
| 			Msg("Cannot encode message") | ||||
| 		machineRegistrations.WithLabelValues("reauth", "web", "error", machine.Namespace.Name). | ||||
| 			Inc() | ||||
| 		ctx.String(http.StatusInternalServerError, "") | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 	machineRegistrations.WithLabelValues("reauth", "web", "success", machine.Namespace.Name). | ||||
| 		Inc() | ||||
| 	ctx.Data(http.StatusOK, "application/json; charset=utf-8", respBody) | ||||
| } | ||||
| 
 | ||||
| func (h *Headscale) handleMachineRefreshKey( | ||||
| 	ctx *gin.Context, | ||||
| 	machineKey wgkey.Key, | ||||
| 	registerRequest tailcfg.RegisterRequest, | ||||
| 	machine Machine, | ||||
| ) { | ||||
| 	resp := tailcfg.RegisterResponse{} | ||||
| 
 | ||||
| 	log.Debug(). | ||||
| 		Str("handler", "Registration"). | ||||
| 		Str("machine", machine.Name). | ||||
| 		Msg("We have the OldNodeKey in the database. This is a key refresh") | ||||
| 	machine.NodeKey = wgkey.Key(registerRequest.NodeKey).HexString() | ||||
| 	h.db.Save(&machine) | ||||
| 
 | ||||
| 	resp.AuthURL = "" | ||||
| 	resp.User = *machine.Namespace.toUser() | ||||
| 	respBody, err := encode(resp, &machineKey, h.privateKey) | ||||
| 	if err != nil { | ||||
| 		log.Error(). | ||||
| 			Str("handler", "Registration"). | ||||
| 			Err(err). | ||||
| 			Msg("Cannot encode message") | ||||
| 		ctx.String(http.StatusInternalServerError, "Extremely sad!") | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 	ctx.Data(http.StatusOK, "application/json; charset=utf-8", respBody) | ||||
| } | ||||
| 
 | ||||
| func (h *Headscale) handleMachineRegistrationNew( | ||||
| 	ctx *gin.Context, | ||||
| 	machineKey wgkey.Key, | ||||
| 	registerRequest tailcfg.RegisterRequest, | ||||
| 	machine Machine, | ||||
| ) { | ||||
| 	resp := tailcfg.RegisterResponse{} | ||||
| 
 | ||||
| 	// The machine registration is new, redirect the client to the registration URL
 | ||||
| 	log.Debug(). | ||||
| 		Str("handler", "Registration"). | ||||
| 		Str("machine", machine.Name). | ||||
| 		Msg("The node is sending us a new NodeKey, sending auth url") | ||||
| 	if h.cfg.OIDC.Issuer != "" { | ||||
| 		resp.AuthURL = fmt.Sprintf( | ||||
| 			"%s/oidc/register/%s", | ||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), | ||||
| 			machineKey.HexString(), | ||||
| 		) | ||||
| 	} else { | ||||
| 		resp.AuthURL = fmt.Sprintf("%s/register?key=%s", | ||||
| 			strings.TrimSuffix(h.cfg.ServerURL, "/"), machineKey.HexString()) | ||||
| 	} | ||||
| 
 | ||||
| 	if !registerRequest.Expiry.IsZero() { | ||||
| 		log.Trace(). | ||||
| 			Caller(). | ||||
| 			Str("machine", machine.Name). | ||||
| 			Time("expiry", registerRequest.Expiry). | ||||
| 			Msg("Non-zero expiry time requested, adding to cache") | ||||
| 		h.requestedExpiryCache.Set( | ||||
| 			machineKey.HexString(), | ||||
| 			registerRequest.Expiry, | ||||
| 			requestedExpiryCacheExpiration, | ||||
| 		) | ||||
| 	} | ||||
| 
 | ||||
| 	machine.NodeKey = wgkey.Key(registerRequest.NodeKey).HexString() // save the NodeKey
 | ||||
| 	h.db.Save(&machine) | ||||
| 
 | ||||
| 	respBody, err := encode(resp, &machineKey, h.privateKey) | ||||
| 	if err != nil { | ||||
| 		log.Error(). | ||||
| 			Str("handler", "Registration"). | ||||
| 			Err(err). | ||||
| 			Msg("Cannot encode message") | ||||
| 		ctx.String(http.StatusInternalServerError, "") | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 	ctx.Data(http.StatusOK, "application/json; charset=utf-8", respBody) | ||||
| } | ||||
| 
 | ||||
| func (h *Headscale) handleAuthKey( | ||||
| 	ctx *gin.Context, | ||||
| 	db *gorm.DB, | ||||
| 	idKey wgkey.Key, | ||||
| 	reqisterRequest tailcfg.RegisterRequest, | ||||
| 	machineKey wgkey.Key, | ||||
| 	registerRequest tailcfg.RegisterRequest, | ||||
| 	machine Machine, | ||||
| ) { | ||||
| 	log.Debug(). | ||||
| 		Str("func", "handleAuthKey"). | ||||
| 		Str("machine", reqisterRequest.Hostinfo.Hostname). | ||||
| 		Msgf("Processing auth key for %s", reqisterRequest.Hostinfo.Hostname) | ||||
| 		Str("machine", registerRequest.Hostinfo.Hostname). | ||||
| 		Msgf("Processing auth key for %s", registerRequest.Hostinfo.Hostname) | ||||
| 	resp := tailcfg.RegisterResponse{} | ||||
| 	pak, err := h.checkKeyValidity(reqisterRequest.Auth.AuthKey) | ||||
| 	pak, err := h.checkKeyValidity(registerRequest.Auth.AuthKey) | ||||
| 	if err != nil { | ||||
| 		log.Error(). | ||||
| 			Str("func", "handleAuthKey"). | ||||
| @ -424,7 +498,7 @@ func (h *Headscale) handleAuthKey( | ||||
| 			Err(err). | ||||
| 			Msg("Failed authentication via AuthKey") | ||||
| 		resp.MachineAuthorized = false | ||||
| 		respBody, err := encode(resp, &idKey, h.privateKey) | ||||
| 		respBody, err := encode(resp, &machineKey, h.privateKey) | ||||
| 		if err != nil { | ||||
| 			log.Error(). | ||||
| 				Str("func", "handleAuthKey"). | ||||
| @ -448,43 +522,53 @@ func (h *Headscale) handleAuthKey( | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	log.Debug(). | ||||
| 		Str("func", "handleAuthKey"). | ||||
| 		Str("machine", machine.Name). | ||||
| 		Msg("Authentication key was valid, proceeding to acquire an IP address") | ||||
| 	ip, err := h.getAvailableIP() | ||||
| 	if err != nil { | ||||
| 		log.Error(). | ||||
| 	if machine.isRegistered() { | ||||
| 		log.Trace(). | ||||
| 			Caller(). | ||||
| 			Str("machine", machine.Name). | ||||
| 			Msg("machine already registered, reauthenticating") | ||||
| 
 | ||||
| 		h.RefreshMachine(&machine, registerRequest.Expiry) | ||||
| 	} else { | ||||
| 		log.Debug(). | ||||
| 			Str("func", "handleAuthKey"). | ||||
| 			Str("machine", machine.Name). | ||||
| 			Msg("Failed to find an available IP") | ||||
| 		machineRegistrations.WithLabelValues("new", "authkey", "error", machine.Namespace.Name). | ||||
| 			Inc() | ||||
| 			Msg("Authentication key was valid, proceeding to acquire an IP address") | ||||
| 		ip, err := h.getAvailableIP() | ||||
| 		if err != nil { | ||||
| 			log.Error(). | ||||
| 				Str("func", "handleAuthKey"). | ||||
| 				Str("machine", machine.Name). | ||||
| 				Msg("Failed to find an available IP") | ||||
| 			machineRegistrations.WithLabelValues("new", "authkey", "error", machine.Namespace.Name). | ||||
| 				Inc() | ||||
| 
 | ||||
| 		return | ||||
| 			return | ||||
| 		} | ||||
| 		log.Info(). | ||||
| 			Str("func", "handleAuthKey"). | ||||
| 			Str("machine", machine.Name). | ||||
| 			Str("ip", ip.String()). | ||||
| 			Msgf("Assigning %s to %s", ip, machine.Name) | ||||
| 
 | ||||
| 		machine.Expiry = ®isterRequest.Expiry | ||||
| 		machine.AuthKeyID = uint(pak.ID) | ||||
| 		machine.IPAddress = ip.String() | ||||
| 		machine.NamespaceID = pak.NamespaceID | ||||
| 		machine.NodeKey = wgkey.Key(registerRequest.NodeKey). | ||||
| 			HexString() | ||||
| 			// we update it just in case
 | ||||
| 		machine.Registered = true | ||||
| 		machine.RegisterMethod = RegisterMethodAuthKey | ||||
| 		h.db.Save(&machine) | ||||
| 	} | ||||
| 	log.Info(). | ||||
| 		Str("func", "handleAuthKey"). | ||||
| 		Str("machine", machine.Name). | ||||
| 		Str("ip", ip.String()). | ||||
| 		Msgf("Assigning %s to %s", ip, machine.Name) | ||||
| 
 | ||||
| 	machine.AuthKeyID = uint(pak.ID) | ||||
| 	machine.IPAddress = ip.String() | ||||
| 	machine.NamespaceID = pak.NamespaceID | ||||
| 	machine.NodeKey = wgkey.Key(reqisterRequest.NodeKey). | ||||
| 		HexString() | ||||
| 		// we update it just in case
 | ||||
| 	machine.Registered = true | ||||
| 	machine.RegisterMethod = "authKey" | ||||
| 	db.Save(&machine) | ||||
| 
 | ||||
| 	pak.Used = true | ||||
| 	db.Save(&pak) | ||||
| 	h.db.Save(&pak) | ||||
| 
 | ||||
| 	resp.MachineAuthorized = true | ||||
| 	resp.User = *pak.Namespace.toUser() | ||||
| 	respBody, err := encode(resp, &idKey, h.privateKey) | ||||
| 	respBody, err := encode(resp, &machineKey, h.privateKey) | ||||
| 	if err != nil { | ||||
| 		log.Error(). | ||||
| 			Str("func", "handleAuthKey"). | ||||
| @ -503,6 +587,6 @@ func (h *Headscale) handleAuthKey( | ||||
| 	log.Info(). | ||||
| 		Str("func", "handleAuthKey"). | ||||
| 		Str("machine", machine.Name). | ||||
| 		Str("ip", ip.String()). | ||||
| 		Str("ip", machine.IPAddress). | ||||
| 		Msg("Successfully authenticated via AuthKey") | ||||
| } | ||||
|  | ||||
							
								
								
									
										26
									
								
								app.go
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								app.go
									
									
									
									
									
								
							| @ -53,6 +53,9 @@ const ( | ||||
| 	updateInterval  = 5000 | ||||
| 	HTTPReadTimeout = 30 * time.Second | ||||
| 
 | ||||
| 	requestedExpiryCacheExpiration      = time.Minute * 5 | ||||
| 	requestedExpiryCacheCleanupInterval = time.Minute * 10 | ||||
| 
 | ||||
| 	errUnsupportedDatabase                 = Error("unsupported DB") | ||||
| 	errUnsupportedLetsEncryptChallengeType = Error( | ||||
| 		"unknown value for Lets Encrypt challenge type", | ||||
| @ -96,9 +99,6 @@ type Config struct { | ||||
| 	OIDC OIDCConfig | ||||
| 
 | ||||
| 	CLI CLIConfig | ||||
| 
 | ||||
| 	MaxMachineRegistrationDuration     time.Duration | ||||
| 	DefaultMachineRegistrationDuration time.Duration | ||||
| } | ||||
| 
 | ||||
| type OIDCConfig struct { | ||||
| @ -142,6 +142,8 @@ type Headscale struct { | ||||
| 	oidcProvider   *oidc.Provider | ||||
| 	oauth2Config   *oauth2.Config | ||||
| 	oidcStateCache *cache.Cache | ||||
| 
 | ||||
| 	requestedExpiryCache *cache.Cache | ||||
| } | ||||
| 
 | ||||
| // NewHeadscale returns the Headscale app.
 | ||||
| @ -174,13 +176,19 @@ func NewHeadscale(cfg Config) (*Headscale, error) { | ||||
| 		return nil, errUnsupportedDatabase | ||||
| 	} | ||||
| 
 | ||||
| 	requestedExpiryCache := cache.New( | ||||
| 		requestedExpiryCacheExpiration, | ||||
| 		requestedExpiryCacheCleanupInterval, | ||||
| 	) | ||||
| 
 | ||||
| 	app := Headscale{ | ||||
| 		cfg:        cfg, | ||||
| 		dbType:     cfg.DBtype, | ||||
| 		dbString:   dbString, | ||||
| 		privateKey: privKey, | ||||
| 		publicKey:  &pubKey, | ||||
| 		aclRules:   tailcfg.FilterAllowAll, // default allowall
 | ||||
| 		cfg:                  cfg, | ||||
| 		dbType:               cfg.DBtype, | ||||
| 		dbString:             dbString, | ||||
| 		privateKey:           privKey, | ||||
| 		publicKey:            &pubKey, | ||||
| 		aclRules:             tailcfg.FilterAllowAll, // default allowall
 | ||||
| 		requestedExpiryCache: requestedExpiryCache, | ||||
| 	} | ||||
| 
 | ||||
| 	err = app.initDB() | ||||
|  | ||||
| @ -5,6 +5,7 @@ import ( | ||||
| 	"os" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/patrickmn/go-cache" | ||||
| 	"gopkg.in/check.v1" | ||||
| 	"inet.af/netaddr" | ||||
| ) | ||||
| @ -47,6 +48,10 @@ func (s *Suite) ResetDB(c *check.C) { | ||||
| 		cfg:      cfg, | ||||
| 		dbType:   "sqlite3", | ||||
| 		dbString: tmpDir + "/headscale_test.db", | ||||
| 		requestedExpiryCache: cache.New( | ||||
| 			requestedExpiryCacheExpiration, | ||||
| 			requestedExpiryCacheCleanupInterval, | ||||
| 		), | ||||
| 	} | ||||
| 	err = app.initDB() | ||||
| 	if err != nil { | ||||
|  | ||||
							
								
								
									
										17
									
								
								cli_test.go
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								cli_test.go
									
									
									
									
									
								
							| @ -13,15 +13,14 @@ func (s *Suite) TestRegisterMachine(c *check.C) { | ||||
| 	now := time.Now().UTC() | ||||
| 
 | ||||
| 	machine := Machine{ | ||||
| 		ID:              0, | ||||
| 		MachineKey:      "8ce002a935f8c394e55e78fbbb410576575ff8ec5cfa2e627e4b807f1be15b0e", | ||||
| 		NodeKey:         "bar", | ||||
| 		DiscoKey:        "faa", | ||||
| 		Name:            "testmachine", | ||||
| 		NamespaceID:     namespace.ID, | ||||
| 		IPAddress:       "10.0.0.1", | ||||
| 		Expiry:          &now, | ||||
| 		RequestedExpiry: &now, | ||||
| 		ID:          0, | ||||
| 		MachineKey:  "8ce002a935f8c394e55e78fbbb410576575ff8ec5cfa2e627e4b807f1be15b0e", | ||||
| 		NodeKey:     "bar", | ||||
| 		DiscoKey:    "faa", | ||||
| 		Name:        "testmachine", | ||||
| 		NamespaceID: namespace.ID, | ||||
| 		IPAddress:   "10.0.0.1", | ||||
| 		Expiry:      &now, | ||||
| 	} | ||||
| 	app.db.Save(&machine) | ||||
| 
 | ||||
|  | ||||
| @ -33,7 +33,14 @@ func init() { | ||||
| 	} | ||||
| 	nodeCmd.AddCommand(registerNodeCmd) | ||||
| 
 | ||||
| 	deleteNodeCmd.Flags().IntP("identifier", "i", 0, "Node identifier (ID)") | ||||
| 	expireNodeCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") | ||||
| 	err = expireNodeCmd.MarkFlagRequired("identifier") | ||||
| 	if err != nil { | ||||
| 		log.Fatalf(err.Error()) | ||||
| 	} | ||||
| 	nodeCmd.AddCommand(expireNodeCmd) | ||||
| 
 | ||||
| 	deleteNodeCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") | ||||
| 	err = deleteNodeCmd.MarkFlagRequired("identifier") | ||||
| 	if err != nil { | ||||
| 		log.Fatalf(err.Error()) | ||||
| @ -45,7 +52,7 @@ func init() { | ||||
| 	if err != nil { | ||||
| 		log.Fatalf(err.Error()) | ||||
| 	} | ||||
| 	shareMachineCmd.Flags().IntP("identifier", "i", 0, "Node identifier (ID)") | ||||
| 	shareMachineCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") | ||||
| 	err = shareMachineCmd.MarkFlagRequired("identifier") | ||||
| 	if err != nil { | ||||
| 		log.Fatalf(err.Error()) | ||||
| @ -57,7 +64,7 @@ func init() { | ||||
| 	if err != nil { | ||||
| 		log.Fatalf(err.Error()) | ||||
| 	} | ||||
| 	unshareMachineCmd.Flags().IntP("identifier", "i", 0, "Node identifier (ID)") | ||||
| 	unshareMachineCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)") | ||||
| 	err = unshareMachineCmd.MarkFlagRequired("identifier") | ||||
| 	if err != nil { | ||||
| 		log.Fatalf(err.Error()) | ||||
| @ -177,13 +184,58 @@ var listNodesCmd = &cobra.Command{ | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| var expireNodeCmd = &cobra.Command{ | ||||
| 	Use:     "expire", | ||||
| 	Short:   "Expire (log out) a machine in your network", | ||||
| 	Long:    "Expiring a node will keep the node in the database and force it to reauthenticate.", | ||||
| 	Aliases: []string{"logout"}, | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		output, _ := cmd.Flags().GetString("output") | ||||
| 
 | ||||
| 		identifier, err := cmd.Flags().GetUint64("identifier") | ||||
| 		if err != nil { | ||||
| 			ErrorOutput( | ||||
| 				err, | ||||
| 				fmt.Sprintf("Error converting ID to integer: %s", err), | ||||
| 				output, | ||||
| 			) | ||||
| 
 | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		ctx, client, conn, cancel := getHeadscaleCLIClient() | ||||
| 		defer cancel() | ||||
| 		defer conn.Close() | ||||
| 
 | ||||
| 		request := &v1.ExpireMachineRequest{ | ||||
| 			MachineId: identifier, | ||||
| 		} | ||||
| 
 | ||||
| 		response, err := client.ExpireMachine(ctx, request) | ||||
| 		if err != nil { | ||||
| 			ErrorOutput( | ||||
| 				err, | ||||
| 				fmt.Sprintf( | ||||
| 					"Cannot expire machine: %s\n", | ||||
| 					status.Convert(err).Message(), | ||||
| 				), | ||||
| 				output, | ||||
| 			) | ||||
| 
 | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		SuccessOutput(response.Machine, "Machine expired", output) | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| var deleteNodeCmd = &cobra.Command{ | ||||
| 	Use:   "delete", | ||||
| 	Short: "Delete a node", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		output, _ := cmd.Flags().GetString("output") | ||||
| 
 | ||||
| 		identifier, err := cmd.Flags().GetInt("identifier") | ||||
| 		identifier, err := cmd.Flags().GetUint64("identifier") | ||||
| 		if err != nil { | ||||
| 			ErrorOutput( | ||||
| 				err, | ||||
| @ -199,7 +251,7 @@ var deleteNodeCmd = &cobra.Command{ | ||||
| 		defer conn.Close() | ||||
| 
 | ||||
| 		getRequest := &v1.GetMachineRequest{ | ||||
| 			MachineId: uint64(identifier), | ||||
| 			MachineId: identifier, | ||||
| 		} | ||||
| 
 | ||||
| 		getResponse, err := client.GetMachine(ctx, getRequest) | ||||
| @ -217,7 +269,7 @@ var deleteNodeCmd = &cobra.Command{ | ||||
| 		} | ||||
| 
 | ||||
| 		deleteRequest := &v1.DeleteMachineRequest{ | ||||
| 			MachineId: uint64(identifier), | ||||
| 			MachineId: identifier, | ||||
| 		} | ||||
| 
 | ||||
| 		confirm := false | ||||
| @ -280,7 +332,7 @@ func sharingWorker( | ||||
| 	defer cancel() | ||||
| 	defer conn.Close() | ||||
| 
 | ||||
| 	identifier, err := cmd.Flags().GetInt("identifier") | ||||
| 	identifier, err := cmd.Flags().GetUint64("identifier") | ||||
| 	if err != nil { | ||||
| 		ErrorOutput(err, fmt.Sprintf("Error converting ID to integer: %s", err), output) | ||||
| 
 | ||||
| @ -288,7 +340,7 @@ func sharingWorker( | ||||
| 	} | ||||
| 
 | ||||
| 	machineRequest := &v1.GetMachineRequest{ | ||||
| 		MachineId: uint64(identifier), | ||||
| 		MachineId: identifier, | ||||
| 	} | ||||
| 
 | ||||
| 	machineResponse, err := client.GetMachine(ctx, machineRequest) | ||||
| @ -412,6 +464,7 @@ func nodesToPtables( | ||||
| 			"Ephemeral", | ||||
| 			"Last seen", | ||||
| 			"Online", | ||||
| 			"Expired", | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| @ -420,12 +473,19 @@ func nodesToPtables( | ||||
| 		if machine.PreAuthKey != nil && machine.PreAuthKey.Ephemeral { | ||||
| 			ephemeral = true | ||||
| 		} | ||||
| 
 | ||||
| 		var lastSeen time.Time | ||||
| 		var lastSeenTime string | ||||
| 		if machine.LastSeen != nil { | ||||
| 			lastSeen = machine.LastSeen.AsTime() | ||||
| 			lastSeenTime = lastSeen.Format("2006-01-02 15:04:05") | ||||
| 		} | ||||
| 
 | ||||
| 		var expiry time.Time | ||||
| 		if machine.Expiry != nil { | ||||
| 			expiry = machine.Expiry.AsTime() | ||||
| 		} | ||||
| 
 | ||||
| 		nKey, err := wgkey.ParseHex(machine.NodeKey) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| @ -436,9 +496,16 @@ func nodesToPtables( | ||||
| 		if lastSeen.After( | ||||
| 			time.Now().Add(-5 * time.Minute), | ||||
| 		) { // TODO: Find a better way to reliably show if online
 | ||||
| 			online = pterm.LightGreen("true") | ||||
| 			online = pterm.LightGreen("online") | ||||
| 		} else { | ||||
| 			online = pterm.LightRed("false") | ||||
| 			online = pterm.LightRed("offline") | ||||
| 		} | ||||
| 
 | ||||
| 		var expired string | ||||
| 		if expiry.IsZero() || expiry.After(time.Now()) { | ||||
| 			expired = pterm.LightGreen("no") | ||||
| 		} else { | ||||
| 			expired = pterm.LightRed("yes") | ||||
| 		} | ||||
| 
 | ||||
| 		var namespace string | ||||
| @ -459,6 +526,7 @@ func nodesToPtables( | ||||
| 				strconv.FormatBool(ephemeral), | ||||
| 				lastSeenTime, | ||||
| 				online, | ||||
| 				expired, | ||||
| 			}, | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| @ -218,30 +218,6 @@ func absPath(path string) string { | ||||
| } | ||||
| 
 | ||||
| func getHeadscaleConfig() headscale.Config { | ||||
| 	// maxMachineRegistrationDuration is the maximum time headscale will allow a client to (optionally) request for
 | ||||
| 	// the machine key expiry time. RegisterRequests with Expiry times that are more than
 | ||||
| 	// maxMachineRegistrationDuration in the future will be clamped to (now + maxMachineRegistrationDuration)
 | ||||
| 	maxMachineRegistrationDuration, _ := time.ParseDuration( | ||||
| 		"10h", | ||||
| 	) // use 10h here because it is the length of a standard business day plus a small amount of leeway
 | ||||
| 	if viper.GetDuration("max_machine_registration_duration") >= time.Second { | ||||
| 		maxMachineRegistrationDuration = viper.GetDuration( | ||||
| 			"max_machine_registration_duration", | ||||
| 		) | ||||
| 	} | ||||
| 
 | ||||
| 	// defaultMachineRegistrationDuration is the default time assigned to a machine registration if one is not
 | ||||
| 	// specified by the tailscale client. It is the default amount of time a machine registration is valid for
 | ||||
| 	// (ie the amount of time before the user has to re-authenticate when requesting a connection)
 | ||||
| 	defaultMachineRegistrationDuration, _ := time.ParseDuration( | ||||
| 		"8h", | ||||
| 	) // use 8h here because it's the length of a standard business day
 | ||||
| 	if viper.GetDuration("default_machine_registration_duration") >= time.Second { | ||||
| 		defaultMachineRegistrationDuration = viper.GetDuration( | ||||
| 			"default_machine_registration_duration", | ||||
| 		) | ||||
| 	} | ||||
| 
 | ||||
| 	dnsConfig, baseDomain := GetDNSConfig() | ||||
| 	derpConfig := GetDERPConfig() | ||||
| 
 | ||||
| @ -295,9 +271,6 @@ func getHeadscaleConfig() headscale.Config { | ||||
| 			Insecure: viper.GetBool("cli.insecure"), | ||||
| 			Timeout:  viper.GetDuration("cli.timeout"), | ||||
| 		}, | ||||
| 
 | ||||
| 		MaxMachineRegistrationDuration:     maxMachineRegistrationDuration, | ||||
| 		DefaultMachineRegistrationDuration: defaultMachineRegistrationDuration, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										16
									
								
								dns_test.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								dns_test.go
									
									
									
									
									
								
							| @ -123,7 +123,7 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) { | ||||
| 		NamespaceID:    namespaceShared1.ID, | ||||
| 		Namespace:      *namespaceShared1, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.1", | ||||
| 		AuthKeyID:      uint(preAuthKeyInShared1.ID), | ||||
| 	} | ||||
| @ -141,7 +141,7 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) { | ||||
| 		NamespaceID:    namespaceShared2.ID, | ||||
| 		Namespace:      *namespaceShared2, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.2", | ||||
| 		AuthKeyID:      uint(preAuthKeyInShared2.ID), | ||||
| 	} | ||||
| @ -159,7 +159,7 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) { | ||||
| 		NamespaceID:    namespaceShared3.ID, | ||||
| 		Namespace:      *namespaceShared3, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.3", | ||||
| 		AuthKeyID:      uint(preAuthKeyInShared3.ID), | ||||
| 	} | ||||
| @ -177,7 +177,7 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) { | ||||
| 		NamespaceID:    namespaceShared1.ID, | ||||
| 		Namespace:      *namespaceShared1, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.4", | ||||
| 		AuthKeyID:      uint(PreAuthKey2InShared1.ID), | ||||
| 	} | ||||
| @ -272,7 +272,7 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) { | ||||
| 		NamespaceID:    namespaceShared1.ID, | ||||
| 		Namespace:      *namespaceShared1, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.1", | ||||
| 		AuthKeyID:      uint(preAuthKeyInShared1.ID), | ||||
| 	} | ||||
| @ -290,7 +290,7 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) { | ||||
| 		NamespaceID:    namespaceShared2.ID, | ||||
| 		Namespace:      *namespaceShared2, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.2", | ||||
| 		AuthKeyID:      uint(preAuthKeyInShared2.ID), | ||||
| 	} | ||||
| @ -308,7 +308,7 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) { | ||||
| 		NamespaceID:    namespaceShared3.ID, | ||||
| 		Namespace:      *namespaceShared3, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.3", | ||||
| 		AuthKeyID:      uint(preAuthKeyInShared3.ID), | ||||
| 	} | ||||
| @ -326,7 +326,7 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) { | ||||
| 		NamespaceID:    namespaceShared1.ID, | ||||
| 		Namespace:      *namespaceShared1, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.4", | ||||
| 		AuthKeyID:      uint(preAuthKey2InShared1.ID), | ||||
| 	} | ||||
|  | ||||
| @ -34,8 +34,8 @@ var file_headscale_v1_headscale_proto_rawDesc = []byte{ | ||||
| 	0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, | ||||
| 	0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2e, 0x70, 0x72, | ||||
| 	0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, | ||||
| 	0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xec, | ||||
| 	0x11, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, | ||||
| 	0x31, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xf4, | ||||
| 	0x12, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, | ||||
| 	0x69, 0x63, 0x65, 0x12, 0x77, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, | ||||
| 	0x61, 0x63, 0x65, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, | ||||
| 	0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, | ||||
| @ -133,54 +133,63 @@ var file_headscale_v1_headscale_proto_rawDesc = []byte{ | ||||
| 	0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, | ||||
| 	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x2a, | ||||
| 	0x1c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | ||||
| 	0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x6e, 0x0a, | ||||
| 	0x0c, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x21, 0x2e, | ||||
| 	0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, | ||||
| 	0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, | ||||
| 	0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, | ||||
| 	0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, | ||||
| 	0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x61, | ||||
| 	0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x8d, 0x01, | ||||
| 	0x0a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x21, | ||||
| 	0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x68, | ||||
| 	0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, | ||||
| 	0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, | ||||
| 	0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, | ||||
| 	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x36, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x30, 0x22, 0x2e, 0x2f, | ||||
| 	0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, | ||||
| 	0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x73, 0x68, 0x61, 0x72, | ||||
| 	0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x12, 0x95, 0x01, | ||||
| 	0x0a, 0x0e, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | ||||
| 	0x12, 0x23, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, | ||||
| 	0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, | ||||
| 	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, | ||||
| 	0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, | ||||
| 	0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x38, 0x82, 0xd3, 0xe4, | ||||
| 	0x93, 0x02, 0x32, 0x22, 0x30, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, | ||||
| 	0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, | ||||
| 	0x7d, 0x2f, 0x75, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, | ||||
| 	0x70, 0x61, 0x63, 0x65, 0x7d, 0x12, 0x8b, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, | ||||
| 	0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x24, 0x2e, 0x68, 0x65, 0x61, 0x64, | ||||
| 	0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, | ||||
| 	0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, | ||||
| 	0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, | ||||
| 	0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, | ||||
| 	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, | ||||
| 	0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, | ||||
| 	0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x6f, 0x75, | ||||
| 	0x74, 0x65, 0x73, 0x12, 0x97, 0x01, 0x0a, 0x13, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, | ||||
| 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x28, 0x2e, 0x68, 0x65, | ||||
| 	0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, | ||||
| 	0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, | ||||
| 	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, | ||||
| 	0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, | ||||
| 	0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, | ||||
| 	0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, | ||||
| 	0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, | ||||
| 	0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x42, 0x29, 0x5a, | ||||
| 	0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x75, 0x61, 0x6e, | ||||
| 	0x66, 0x6f, 0x6e, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x67, | ||||
| 	0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, | ||||
| 	0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x85, 0x01, | ||||
| 	0x0a, 0x0d, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, | ||||
| 	0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, | ||||
| 	0x78, 0x70, 0x69, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, | ||||
| 	0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, | ||||
| 	0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | ||||
| 	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, | ||||
| 	0x22, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, | ||||
| 	0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x65, | ||||
| 	0x78, 0x70, 0x69, 0x72, 0x65, 0x12, 0x6e, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, | ||||
| 	0x68, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, | ||||
| 	0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | ||||
| 	0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, | ||||
| 	0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, | ||||
| 	0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, | ||||
| 	0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, | ||||
| 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x8d, 0x01, 0x0a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x4d, | ||||
| 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x21, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, | ||||
| 	0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, | ||||
| 	0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x65, 0x61, 0x64, | ||||
| 	0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, | ||||
| 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x36, 0x82, | ||||
| 	0xd3, 0xe4, 0x93, 0x02, 0x30, 0x22, 0x2e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, | ||||
| 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, | ||||
| 	0x69, 0x64, 0x7d, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, | ||||
| 	0x70, 0x61, 0x63, 0x65, 0x7d, 0x12, 0x95, 0x01, 0x0a, 0x0e, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, | ||||
| 	0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x23, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, | ||||
| 	0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, | ||||
| 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, | ||||
| 	0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x73, | ||||
| 	0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, | ||||
| 	0x6e, 0x73, 0x65, 0x22, 0x38, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x22, 0x30, 0x2f, 0x61, 0x70, | ||||
| 	0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, | ||||
| 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x75, 0x6e, 0x73, 0x68, 0x61, 0x72, | ||||
| 	0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x12, 0x8b, 0x01, | ||||
| 	0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, | ||||
| 	0x65, 0x12, 0x24, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, | ||||
| 	0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, | ||||
| 	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, | ||||
| 	0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, | ||||
| 	0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, | ||||
| 	0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, | ||||
| 	0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | ||||
| 	0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x97, 0x01, 0x0a, 0x13, | ||||
| 	0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, | ||||
| 	0x74, 0x65, 0x73, 0x12, 0x28, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, | ||||
| 	0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | ||||
| 	0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, | ||||
| 	0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, | ||||
| 	0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, | ||||
| 	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, | ||||
| 	0x22, 0x23, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, | ||||
| 	0x65, 0x2f, 0x7b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, | ||||
| 	0x6f, 0x75, 0x74, 0x65, 0x73, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, | ||||
| 	0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x75, 0x61, 0x6e, 0x66, 0x6f, 0x6e, 0x74, 0x2f, 0x68, 0x65, 0x61, | ||||
| 	0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, | ||||
| 	0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, | ||||
| } | ||||
| 
 | ||||
| var file_headscale_v1_headscale_proto_goTypes = []interface{}{ | ||||
| @ -196,28 +205,30 @@ var file_headscale_v1_headscale_proto_goTypes = []interface{}{ | ||||
| 	(*GetMachineRequest)(nil),           // 9: headscale.v1.GetMachineRequest
 | ||||
| 	(*RegisterMachineRequest)(nil),      // 10: headscale.v1.RegisterMachineRequest
 | ||||
| 	(*DeleteMachineRequest)(nil),        // 11: headscale.v1.DeleteMachineRequest
 | ||||
| 	(*ListMachinesRequest)(nil),         // 12: headscale.v1.ListMachinesRequest
 | ||||
| 	(*ShareMachineRequest)(nil),         // 13: headscale.v1.ShareMachineRequest
 | ||||
| 	(*UnshareMachineRequest)(nil),       // 14: headscale.v1.UnshareMachineRequest
 | ||||
| 	(*GetMachineRouteRequest)(nil),      // 15: headscale.v1.GetMachineRouteRequest
 | ||||
| 	(*EnableMachineRoutesRequest)(nil),  // 16: headscale.v1.EnableMachineRoutesRequest
 | ||||
| 	(*GetNamespaceResponse)(nil),        // 17: headscale.v1.GetNamespaceResponse
 | ||||
| 	(*CreateNamespaceResponse)(nil),     // 18: headscale.v1.CreateNamespaceResponse
 | ||||
| 	(*RenameNamespaceResponse)(nil),     // 19: headscale.v1.RenameNamespaceResponse
 | ||||
| 	(*DeleteNamespaceResponse)(nil),     // 20: headscale.v1.DeleteNamespaceResponse
 | ||||
| 	(*ListNamespacesResponse)(nil),      // 21: headscale.v1.ListNamespacesResponse
 | ||||
| 	(*CreatePreAuthKeyResponse)(nil),    // 22: headscale.v1.CreatePreAuthKeyResponse
 | ||||
| 	(*ExpirePreAuthKeyResponse)(nil),    // 23: headscale.v1.ExpirePreAuthKeyResponse
 | ||||
| 	(*ListPreAuthKeysResponse)(nil),     // 24: headscale.v1.ListPreAuthKeysResponse
 | ||||
| 	(*DebugCreateMachineResponse)(nil),  // 25: headscale.v1.DebugCreateMachineResponse
 | ||||
| 	(*GetMachineResponse)(nil),          // 26: headscale.v1.GetMachineResponse
 | ||||
| 	(*RegisterMachineResponse)(nil),     // 27: headscale.v1.RegisterMachineResponse
 | ||||
| 	(*DeleteMachineResponse)(nil),       // 28: headscale.v1.DeleteMachineResponse
 | ||||
| 	(*ListMachinesResponse)(nil),        // 29: headscale.v1.ListMachinesResponse
 | ||||
| 	(*ShareMachineResponse)(nil),        // 30: headscale.v1.ShareMachineResponse
 | ||||
| 	(*UnshareMachineResponse)(nil),      // 31: headscale.v1.UnshareMachineResponse
 | ||||
| 	(*GetMachineRouteResponse)(nil),     // 32: headscale.v1.GetMachineRouteResponse
 | ||||
| 	(*EnableMachineRoutesResponse)(nil), // 33: headscale.v1.EnableMachineRoutesResponse
 | ||||
| 	(*ExpireMachineRequest)(nil),        // 12: headscale.v1.ExpireMachineRequest
 | ||||
| 	(*ListMachinesRequest)(nil),         // 13: headscale.v1.ListMachinesRequest
 | ||||
| 	(*ShareMachineRequest)(nil),         // 14: headscale.v1.ShareMachineRequest
 | ||||
| 	(*UnshareMachineRequest)(nil),       // 15: headscale.v1.UnshareMachineRequest
 | ||||
| 	(*GetMachineRouteRequest)(nil),      // 16: headscale.v1.GetMachineRouteRequest
 | ||||
| 	(*EnableMachineRoutesRequest)(nil),  // 17: headscale.v1.EnableMachineRoutesRequest
 | ||||
| 	(*GetNamespaceResponse)(nil),        // 18: headscale.v1.GetNamespaceResponse
 | ||||
| 	(*CreateNamespaceResponse)(nil),     // 19: headscale.v1.CreateNamespaceResponse
 | ||||
| 	(*RenameNamespaceResponse)(nil),     // 20: headscale.v1.RenameNamespaceResponse
 | ||||
| 	(*DeleteNamespaceResponse)(nil),     // 21: headscale.v1.DeleteNamespaceResponse
 | ||||
| 	(*ListNamespacesResponse)(nil),      // 22: headscale.v1.ListNamespacesResponse
 | ||||
| 	(*CreatePreAuthKeyResponse)(nil),    // 23: headscale.v1.CreatePreAuthKeyResponse
 | ||||
| 	(*ExpirePreAuthKeyResponse)(nil),    // 24: headscale.v1.ExpirePreAuthKeyResponse
 | ||||
| 	(*ListPreAuthKeysResponse)(nil),     // 25: headscale.v1.ListPreAuthKeysResponse
 | ||||
| 	(*DebugCreateMachineResponse)(nil),  // 26: headscale.v1.DebugCreateMachineResponse
 | ||||
| 	(*GetMachineResponse)(nil),          // 27: headscale.v1.GetMachineResponse
 | ||||
| 	(*RegisterMachineResponse)(nil),     // 28: headscale.v1.RegisterMachineResponse
 | ||||
| 	(*DeleteMachineResponse)(nil),       // 29: headscale.v1.DeleteMachineResponse
 | ||||
| 	(*ExpireMachineResponse)(nil),       // 30: headscale.v1.ExpireMachineResponse
 | ||||
| 	(*ListMachinesResponse)(nil),        // 31: headscale.v1.ListMachinesResponse
 | ||||
| 	(*ShareMachineResponse)(nil),        // 32: headscale.v1.ShareMachineResponse
 | ||||
| 	(*UnshareMachineResponse)(nil),      // 33: headscale.v1.UnshareMachineResponse
 | ||||
| 	(*GetMachineRouteResponse)(nil),     // 34: headscale.v1.GetMachineRouteResponse
 | ||||
| 	(*EnableMachineRoutesResponse)(nil), // 35: headscale.v1.EnableMachineRoutesResponse
 | ||||
| } | ||||
| var file_headscale_v1_headscale_proto_depIdxs = []int32{ | ||||
| 	0,  // 0: headscale.v1.HeadscaleService.GetNamespace:input_type -> headscale.v1.GetNamespaceRequest
 | ||||
| @ -232,30 +243,32 @@ var file_headscale_v1_headscale_proto_depIdxs = []int32{ | ||||
| 	9,  // 9: headscale.v1.HeadscaleService.GetMachine:input_type -> headscale.v1.GetMachineRequest
 | ||||
| 	10, // 10: headscale.v1.HeadscaleService.RegisterMachine:input_type -> headscale.v1.RegisterMachineRequest
 | ||||
| 	11, // 11: headscale.v1.HeadscaleService.DeleteMachine:input_type -> headscale.v1.DeleteMachineRequest
 | ||||
| 	12, // 12: headscale.v1.HeadscaleService.ListMachines:input_type -> headscale.v1.ListMachinesRequest
 | ||||
| 	13, // 13: headscale.v1.HeadscaleService.ShareMachine:input_type -> headscale.v1.ShareMachineRequest
 | ||||
| 	14, // 14: headscale.v1.HeadscaleService.UnshareMachine:input_type -> headscale.v1.UnshareMachineRequest
 | ||||
| 	15, // 15: headscale.v1.HeadscaleService.GetMachineRoute:input_type -> headscale.v1.GetMachineRouteRequest
 | ||||
| 	16, // 16: headscale.v1.HeadscaleService.EnableMachineRoutes:input_type -> headscale.v1.EnableMachineRoutesRequest
 | ||||
| 	17, // 17: headscale.v1.HeadscaleService.GetNamespace:output_type -> headscale.v1.GetNamespaceResponse
 | ||||
| 	18, // 18: headscale.v1.HeadscaleService.CreateNamespace:output_type -> headscale.v1.CreateNamespaceResponse
 | ||||
| 	19, // 19: headscale.v1.HeadscaleService.RenameNamespace:output_type -> headscale.v1.RenameNamespaceResponse
 | ||||
| 	20, // 20: headscale.v1.HeadscaleService.DeleteNamespace:output_type -> headscale.v1.DeleteNamespaceResponse
 | ||||
| 	21, // 21: headscale.v1.HeadscaleService.ListNamespaces:output_type -> headscale.v1.ListNamespacesResponse
 | ||||
| 	22, // 22: headscale.v1.HeadscaleService.CreatePreAuthKey:output_type -> headscale.v1.CreatePreAuthKeyResponse
 | ||||
| 	23, // 23: headscale.v1.HeadscaleService.ExpirePreAuthKey:output_type -> headscale.v1.ExpirePreAuthKeyResponse
 | ||||
| 	24, // 24: headscale.v1.HeadscaleService.ListPreAuthKeys:output_type -> headscale.v1.ListPreAuthKeysResponse
 | ||||
| 	25, // 25: headscale.v1.HeadscaleService.DebugCreateMachine:output_type -> headscale.v1.DebugCreateMachineResponse
 | ||||
| 	26, // 26: headscale.v1.HeadscaleService.GetMachine:output_type -> headscale.v1.GetMachineResponse
 | ||||
| 	27, // 27: headscale.v1.HeadscaleService.RegisterMachine:output_type -> headscale.v1.RegisterMachineResponse
 | ||||
| 	28, // 28: headscale.v1.HeadscaleService.DeleteMachine:output_type -> headscale.v1.DeleteMachineResponse
 | ||||
| 	29, // 29: headscale.v1.HeadscaleService.ListMachines:output_type -> headscale.v1.ListMachinesResponse
 | ||||
| 	30, // 30: headscale.v1.HeadscaleService.ShareMachine:output_type -> headscale.v1.ShareMachineResponse
 | ||||
| 	31, // 31: headscale.v1.HeadscaleService.UnshareMachine:output_type -> headscale.v1.UnshareMachineResponse
 | ||||
| 	32, // 32: headscale.v1.HeadscaleService.GetMachineRoute:output_type -> headscale.v1.GetMachineRouteResponse
 | ||||
| 	33, // 33: headscale.v1.HeadscaleService.EnableMachineRoutes:output_type -> headscale.v1.EnableMachineRoutesResponse
 | ||||
| 	17, // [17:34] is the sub-list for method output_type
 | ||||
| 	0,  // [0:17] is the sub-list for method input_type
 | ||||
| 	12, // 12: headscale.v1.HeadscaleService.ExpireMachine:input_type -> headscale.v1.ExpireMachineRequest
 | ||||
| 	13, // 13: headscale.v1.HeadscaleService.ListMachines:input_type -> headscale.v1.ListMachinesRequest
 | ||||
| 	14, // 14: headscale.v1.HeadscaleService.ShareMachine:input_type -> headscale.v1.ShareMachineRequest
 | ||||
| 	15, // 15: headscale.v1.HeadscaleService.UnshareMachine:input_type -> headscale.v1.UnshareMachineRequest
 | ||||
| 	16, // 16: headscale.v1.HeadscaleService.GetMachineRoute:input_type -> headscale.v1.GetMachineRouteRequest
 | ||||
| 	17, // 17: headscale.v1.HeadscaleService.EnableMachineRoutes:input_type -> headscale.v1.EnableMachineRoutesRequest
 | ||||
| 	18, // 18: headscale.v1.HeadscaleService.GetNamespace:output_type -> headscale.v1.GetNamespaceResponse
 | ||||
| 	19, // 19: headscale.v1.HeadscaleService.CreateNamespace:output_type -> headscale.v1.CreateNamespaceResponse
 | ||||
| 	20, // 20: headscale.v1.HeadscaleService.RenameNamespace:output_type -> headscale.v1.RenameNamespaceResponse
 | ||||
| 	21, // 21: headscale.v1.HeadscaleService.DeleteNamespace:output_type -> headscale.v1.DeleteNamespaceResponse
 | ||||
| 	22, // 22: headscale.v1.HeadscaleService.ListNamespaces:output_type -> headscale.v1.ListNamespacesResponse
 | ||||
| 	23, // 23: headscale.v1.HeadscaleService.CreatePreAuthKey:output_type -> headscale.v1.CreatePreAuthKeyResponse
 | ||||
| 	24, // 24: headscale.v1.HeadscaleService.ExpirePreAuthKey:output_type -> headscale.v1.ExpirePreAuthKeyResponse
 | ||||
| 	25, // 25: headscale.v1.HeadscaleService.ListPreAuthKeys:output_type -> headscale.v1.ListPreAuthKeysResponse
 | ||||
| 	26, // 26: headscale.v1.HeadscaleService.DebugCreateMachine:output_type -> headscale.v1.DebugCreateMachineResponse
 | ||||
| 	27, // 27: headscale.v1.HeadscaleService.GetMachine:output_type -> headscale.v1.GetMachineResponse
 | ||||
| 	28, // 28: headscale.v1.HeadscaleService.RegisterMachine:output_type -> headscale.v1.RegisterMachineResponse
 | ||||
| 	29, // 29: headscale.v1.HeadscaleService.DeleteMachine:output_type -> headscale.v1.DeleteMachineResponse
 | ||||
| 	30, // 30: headscale.v1.HeadscaleService.ExpireMachine:output_type -> headscale.v1.ExpireMachineResponse
 | ||||
| 	31, // 31: headscale.v1.HeadscaleService.ListMachines:output_type -> headscale.v1.ListMachinesResponse
 | ||||
| 	32, // 32: headscale.v1.HeadscaleService.ShareMachine:output_type -> headscale.v1.ShareMachineResponse
 | ||||
| 	33, // 33: headscale.v1.HeadscaleService.UnshareMachine:output_type -> headscale.v1.UnshareMachineResponse
 | ||||
| 	34, // 34: headscale.v1.HeadscaleService.GetMachineRoute:output_type -> headscale.v1.GetMachineRouteResponse
 | ||||
| 	35, // 35: headscale.v1.HeadscaleService.EnableMachineRoutes:output_type -> headscale.v1.EnableMachineRoutesResponse
 | ||||
| 	18, // [18:36] is the sub-list for method output_type
 | ||||
| 	0,  // [0:18] is the sub-list for method input_type
 | ||||
| 	0,  // [0:0] is the sub-list for extension type_name
 | ||||
| 	0,  // [0:0] is the sub-list for extension extendee
 | ||||
| 	0,  // [0:0] is the sub-list for field type_name
 | ||||
|  | ||||
| @ -537,6 +537,58 @@ func local_request_HeadscaleService_DeleteMachine_0(ctx context.Context, marshal | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func request_HeadscaleService_ExpireMachine_0(ctx context.Context, marshaler runtime.Marshaler, client HeadscaleServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { | ||||
| 	var protoReq ExpireMachineRequest | ||||
| 	var metadata runtime.ServerMetadata | ||||
| 
 | ||||
| 	var ( | ||||
| 		val string | ||||
| 		ok  bool | ||||
| 		err error | ||||
| 		_   = err | ||||
| 	) | ||||
| 
 | ||||
| 	val, ok = pathParams["machine_id"] | ||||
| 	if !ok { | ||||
| 		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "machine_id") | ||||
| 	} | ||||
| 
 | ||||
| 	protoReq.MachineId, err = runtime.Uint64(val) | ||||
| 	if err != nil { | ||||
| 		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "machine_id", err) | ||||
| 	} | ||||
| 
 | ||||
| 	msg, err := client.ExpireMachine(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) | ||||
| 	return msg, metadata, err | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func local_request_HeadscaleService_ExpireMachine_0(ctx context.Context, marshaler runtime.Marshaler, server HeadscaleServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { | ||||
| 	var protoReq ExpireMachineRequest | ||||
| 	var metadata runtime.ServerMetadata | ||||
| 
 | ||||
| 	var ( | ||||
| 		val string | ||||
| 		ok  bool | ||||
| 		err error | ||||
| 		_   = err | ||||
| 	) | ||||
| 
 | ||||
| 	val, ok = pathParams["machine_id"] | ||||
| 	if !ok { | ||||
| 		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "machine_id") | ||||
| 	} | ||||
| 
 | ||||
| 	protoReq.MachineId, err = runtime.Uint64(val) | ||||
| 	if err != nil { | ||||
| 		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "machine_id", err) | ||||
| 	} | ||||
| 
 | ||||
| 	msg, err := server.ExpireMachine(ctx, &protoReq) | ||||
| 	return msg, metadata, err | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	filter_HeadscaleService_ListMachines_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} | ||||
| ) | ||||
| @ -1121,6 +1173,29 @@ func RegisterHeadscaleServiceHandlerServer(ctx context.Context, mux *runtime.Ser | ||||
| 
 | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.Handle("POST", pattern_HeadscaleService_ExpireMachine_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | ||||
| 		ctx, cancel := context.WithCancel(req.Context()) | ||||
| 		defer cancel() | ||||
| 		var stream runtime.ServerTransportStream | ||||
| 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) | ||||
| 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) | ||||
| 		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/headscale.v1.HeadscaleService/ExpireMachine", runtime.WithHTTPPathPattern("/api/v1/machine/{machine_id}/expire")) | ||||
| 		if err != nil { | ||||
| 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) | ||||
| 			return | ||||
| 		} | ||||
| 		resp, md, err := local_request_HeadscaleService_ExpireMachine_0(rctx, inboundMarshaler, server, req, pathParams) | ||||
| 		md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) | ||||
| 		ctx = runtime.NewServerMetadataContext(ctx, md) | ||||
| 		if err != nil { | ||||
| 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		forward_HeadscaleService_ExpireMachine_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) | ||||
| 
 | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.Handle("GET", pattern_HeadscaleService_ListMachines_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | ||||
| 		ctx, cancel := context.WithCancel(req.Context()) | ||||
| 		defer cancel() | ||||
| @ -1517,6 +1592,26 @@ func RegisterHeadscaleServiceHandlerClient(ctx context.Context, mux *runtime.Ser | ||||
| 
 | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.Handle("POST", pattern_HeadscaleService_ExpireMachine_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | ||||
| 		ctx, cancel := context.WithCancel(req.Context()) | ||||
| 		defer cancel() | ||||
| 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) | ||||
| 		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/headscale.v1.HeadscaleService/ExpireMachine", runtime.WithHTTPPathPattern("/api/v1/machine/{machine_id}/expire")) | ||||
| 		if err != nil { | ||||
| 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) | ||||
| 			return | ||||
| 		} | ||||
| 		resp, md, err := request_HeadscaleService_ExpireMachine_0(rctx, inboundMarshaler, client, req, pathParams) | ||||
| 		ctx = runtime.NewServerMetadataContext(ctx, md) | ||||
| 		if err != nil { | ||||
| 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		forward_HeadscaleService_ExpireMachine_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) | ||||
| 
 | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.Handle("GET", pattern_HeadscaleService_ListMachines_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { | ||||
| 		ctx, cancel := context.WithCancel(req.Context()) | ||||
| 		defer cancel() | ||||
| @ -1645,6 +1740,8 @@ var ( | ||||
| 
 | ||||
| 	pattern_HeadscaleService_DeleteMachine_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "machine", "machine_id"}, "")) | ||||
| 
 | ||||
| 	pattern_HeadscaleService_ExpireMachine_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "machine", "machine_id", "expire"}, "")) | ||||
| 
 | ||||
| 	pattern_HeadscaleService_ListMachines_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "machine"}, "")) | ||||
| 
 | ||||
| 	pattern_HeadscaleService_ShareMachine_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"api", "v1", "machine", "machine_id", "share", "namespace"}, "")) | ||||
| @ -1681,6 +1778,8 @@ var ( | ||||
| 
 | ||||
| 	forward_HeadscaleService_DeleteMachine_0 = runtime.ForwardResponseMessage | ||||
| 
 | ||||
| 	forward_HeadscaleService_ExpireMachine_0 = runtime.ForwardResponseMessage | ||||
| 
 | ||||
| 	forward_HeadscaleService_ListMachines_0 = runtime.ForwardResponseMessage | ||||
| 
 | ||||
| 	forward_HeadscaleService_ShareMachine_0 = runtime.ForwardResponseMessage | ||||
|  | ||||
| @ -33,6 +33,7 @@ type HeadscaleServiceClient interface { | ||||
| 	GetMachine(ctx context.Context, in *GetMachineRequest, opts ...grpc.CallOption) (*GetMachineResponse, error) | ||||
| 	RegisterMachine(ctx context.Context, in *RegisterMachineRequest, opts ...grpc.CallOption) (*RegisterMachineResponse, error) | ||||
| 	DeleteMachine(ctx context.Context, in *DeleteMachineRequest, opts ...grpc.CallOption) (*DeleteMachineResponse, error) | ||||
| 	ExpireMachine(ctx context.Context, in *ExpireMachineRequest, opts ...grpc.CallOption) (*ExpireMachineResponse, error) | ||||
| 	ListMachines(ctx context.Context, in *ListMachinesRequest, opts ...grpc.CallOption) (*ListMachinesResponse, error) | ||||
| 	ShareMachine(ctx context.Context, in *ShareMachineRequest, opts ...grpc.CallOption) (*ShareMachineResponse, error) | ||||
| 	UnshareMachine(ctx context.Context, in *UnshareMachineRequest, opts ...grpc.CallOption) (*UnshareMachineResponse, error) | ||||
| @ -157,6 +158,15 @@ func (c *headscaleServiceClient) DeleteMachine(ctx context.Context, in *DeleteMa | ||||
| 	return out, nil | ||||
| } | ||||
| 
 | ||||
| func (c *headscaleServiceClient) ExpireMachine(ctx context.Context, in *ExpireMachineRequest, opts ...grpc.CallOption) (*ExpireMachineResponse, error) { | ||||
| 	out := new(ExpireMachineResponse) | ||||
| 	err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/ExpireMachine", in, out, opts...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return out, nil | ||||
| } | ||||
| 
 | ||||
| func (c *headscaleServiceClient) ListMachines(ctx context.Context, in *ListMachinesRequest, opts ...grpc.CallOption) (*ListMachinesResponse, error) { | ||||
| 	out := new(ListMachinesResponse) | ||||
| 	err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/ListMachines", in, out, opts...) | ||||
| @ -221,6 +231,7 @@ type HeadscaleServiceServer interface { | ||||
| 	GetMachine(context.Context, *GetMachineRequest) (*GetMachineResponse, error) | ||||
| 	RegisterMachine(context.Context, *RegisterMachineRequest) (*RegisterMachineResponse, error) | ||||
| 	DeleteMachine(context.Context, *DeleteMachineRequest) (*DeleteMachineResponse, error) | ||||
| 	ExpireMachine(context.Context, *ExpireMachineRequest) (*ExpireMachineResponse, error) | ||||
| 	ListMachines(context.Context, *ListMachinesRequest) (*ListMachinesResponse, error) | ||||
| 	ShareMachine(context.Context, *ShareMachineRequest) (*ShareMachineResponse, error) | ||||
| 	UnshareMachine(context.Context, *UnshareMachineRequest) (*UnshareMachineResponse, error) | ||||
| @ -270,6 +281,9 @@ func (UnimplementedHeadscaleServiceServer) RegisterMachine(context.Context, *Reg | ||||
| func (UnimplementedHeadscaleServiceServer) DeleteMachine(context.Context, *DeleteMachineRequest) (*DeleteMachineResponse, error) { | ||||
| 	return nil, status.Errorf(codes.Unimplemented, "method DeleteMachine not implemented") | ||||
| } | ||||
| func (UnimplementedHeadscaleServiceServer) ExpireMachine(context.Context, *ExpireMachineRequest) (*ExpireMachineResponse, error) { | ||||
| 	return nil, status.Errorf(codes.Unimplemented, "method ExpireMachine not implemented") | ||||
| } | ||||
| func (UnimplementedHeadscaleServiceServer) ListMachines(context.Context, *ListMachinesRequest) (*ListMachinesResponse, error) { | ||||
| 	return nil, status.Errorf(codes.Unimplemented, "method ListMachines not implemented") | ||||
| } | ||||
| @ -514,6 +528,24 @@ func _HeadscaleService_DeleteMachine_Handler(srv interface{}, ctx context.Contex | ||||
| 	return interceptor(ctx, in, info, handler) | ||||
| } | ||||
| 
 | ||||
| func _HeadscaleService_ExpireMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | ||||
| 	in := new(ExpireMachineRequest) | ||||
| 	if err := dec(in); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if interceptor == nil { | ||||
| 		return srv.(HeadscaleServiceServer).ExpireMachine(ctx, in) | ||||
| 	} | ||||
| 	info := &grpc.UnaryServerInfo{ | ||||
| 		Server:     srv, | ||||
| 		FullMethod: "/headscale.v1.HeadscaleService/ExpireMachine", | ||||
| 	} | ||||
| 	handler := func(ctx context.Context, req interface{}) (interface{}, error) { | ||||
| 		return srv.(HeadscaleServiceServer).ExpireMachine(ctx, req.(*ExpireMachineRequest)) | ||||
| 	} | ||||
| 	return interceptor(ctx, in, info, handler) | ||||
| } | ||||
| 
 | ||||
| func _HeadscaleService_ListMachines_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | ||||
| 	in := new(ListMachinesRequest) | ||||
| 	if err := dec(in); err != nil { | ||||
| @ -659,6 +691,10 @@ var HeadscaleService_ServiceDesc = grpc.ServiceDesc{ | ||||
| 			MethodName: "DeleteMachine", | ||||
| 			Handler:    _HeadscaleService_DeleteMachine_Handler, | ||||
| 		}, | ||||
| 		{ | ||||
| 			MethodName: "ExpireMachine", | ||||
| 			Handler:    _HeadscaleService_ExpireMachine_Handler, | ||||
| 		}, | ||||
| 		{ | ||||
| 			MethodName: "ListMachines", | ||||
| 			Handler:    _HeadscaleService_ListMachines_Handler, | ||||
|  | ||||
| @ -505,6 +505,100 @@ func (*DeleteMachineResponse) Descriptor() ([]byte, []int) { | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{6} | ||||
| } | ||||
| 
 | ||||
| type ExpireMachineRequest struct { | ||||
| 	state         protoimpl.MessageState | ||||
| 	sizeCache     protoimpl.SizeCache | ||||
| 	unknownFields protoimpl.UnknownFields | ||||
| 
 | ||||
| 	MachineId uint64 `protobuf:"varint,1,opt,name=machine_id,json=machineId,proto3" json:"machine_id,omitempty"` | ||||
| } | ||||
| 
 | ||||
| func (x *ExpireMachineRequest) Reset() { | ||||
| 	*x = ExpireMachineRequest{} | ||||
| 	if protoimpl.UnsafeEnabled { | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[7] | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		ms.StoreMessageInfo(mi) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (x *ExpireMachineRequest) String() string { | ||||
| 	return protoimpl.X.MessageStringOf(x) | ||||
| } | ||||
| 
 | ||||
| func (*ExpireMachineRequest) ProtoMessage() {} | ||||
| 
 | ||||
| func (x *ExpireMachineRequest) ProtoReflect() protoreflect.Message { | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[7] | ||||
| 	if protoimpl.UnsafeEnabled && x != nil { | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		if ms.LoadMessageInfo() == nil { | ||||
| 			ms.StoreMessageInfo(mi) | ||||
| 		} | ||||
| 		return ms | ||||
| 	} | ||||
| 	return mi.MessageOf(x) | ||||
| } | ||||
| 
 | ||||
| // Deprecated: Use ExpireMachineRequest.ProtoReflect.Descriptor instead.
 | ||||
| func (*ExpireMachineRequest) Descriptor() ([]byte, []int) { | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{7} | ||||
| } | ||||
| 
 | ||||
| func (x *ExpireMachineRequest) GetMachineId() uint64 { | ||||
| 	if x != nil { | ||||
| 		return x.MachineId | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| type ExpireMachineResponse struct { | ||||
| 	state         protoimpl.MessageState | ||||
| 	sizeCache     protoimpl.SizeCache | ||||
| 	unknownFields protoimpl.UnknownFields | ||||
| 
 | ||||
| 	Machine *Machine `protobuf:"bytes,1,opt,name=machine,proto3" json:"machine,omitempty"` | ||||
| } | ||||
| 
 | ||||
| func (x *ExpireMachineResponse) Reset() { | ||||
| 	*x = ExpireMachineResponse{} | ||||
| 	if protoimpl.UnsafeEnabled { | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[8] | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		ms.StoreMessageInfo(mi) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (x *ExpireMachineResponse) String() string { | ||||
| 	return protoimpl.X.MessageStringOf(x) | ||||
| } | ||||
| 
 | ||||
| func (*ExpireMachineResponse) ProtoMessage() {} | ||||
| 
 | ||||
| func (x *ExpireMachineResponse) ProtoReflect() protoreflect.Message { | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[8] | ||||
| 	if protoimpl.UnsafeEnabled && x != nil { | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		if ms.LoadMessageInfo() == nil { | ||||
| 			ms.StoreMessageInfo(mi) | ||||
| 		} | ||||
| 		return ms | ||||
| 	} | ||||
| 	return mi.MessageOf(x) | ||||
| } | ||||
| 
 | ||||
| // Deprecated: Use ExpireMachineResponse.ProtoReflect.Descriptor instead.
 | ||||
| func (*ExpireMachineResponse) Descriptor() ([]byte, []int) { | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{8} | ||||
| } | ||||
| 
 | ||||
| func (x *ExpireMachineResponse) GetMachine() *Machine { | ||||
| 	if x != nil { | ||||
| 		return x.Machine | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| type ListMachinesRequest struct { | ||||
| 	state         protoimpl.MessageState | ||||
| 	sizeCache     protoimpl.SizeCache | ||||
| @ -516,7 +610,7 @@ type ListMachinesRequest struct { | ||||
| func (x *ListMachinesRequest) Reset() { | ||||
| 	*x = ListMachinesRequest{} | ||||
| 	if protoimpl.UnsafeEnabled { | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[7] | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[9] | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		ms.StoreMessageInfo(mi) | ||||
| 	} | ||||
| @ -529,7 +623,7 @@ func (x *ListMachinesRequest) String() string { | ||||
| func (*ListMachinesRequest) ProtoMessage() {} | ||||
| 
 | ||||
| func (x *ListMachinesRequest) ProtoReflect() protoreflect.Message { | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[7] | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[9] | ||||
| 	if protoimpl.UnsafeEnabled && x != nil { | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		if ms.LoadMessageInfo() == nil { | ||||
| @ -542,7 +636,7 @@ func (x *ListMachinesRequest) ProtoReflect() protoreflect.Message { | ||||
| 
 | ||||
| // Deprecated: Use ListMachinesRequest.ProtoReflect.Descriptor instead.
 | ||||
| func (*ListMachinesRequest) Descriptor() ([]byte, []int) { | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{7} | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{9} | ||||
| } | ||||
| 
 | ||||
| func (x *ListMachinesRequest) GetNamespace() string { | ||||
| @ -563,7 +657,7 @@ type ListMachinesResponse struct { | ||||
| func (x *ListMachinesResponse) Reset() { | ||||
| 	*x = ListMachinesResponse{} | ||||
| 	if protoimpl.UnsafeEnabled { | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[8] | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[10] | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		ms.StoreMessageInfo(mi) | ||||
| 	} | ||||
| @ -576,7 +670,7 @@ func (x *ListMachinesResponse) String() string { | ||||
| func (*ListMachinesResponse) ProtoMessage() {} | ||||
| 
 | ||||
| func (x *ListMachinesResponse) ProtoReflect() protoreflect.Message { | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[8] | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[10] | ||||
| 	if protoimpl.UnsafeEnabled && x != nil { | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		if ms.LoadMessageInfo() == nil { | ||||
| @ -589,7 +683,7 @@ func (x *ListMachinesResponse) ProtoReflect() protoreflect.Message { | ||||
| 
 | ||||
| // Deprecated: Use ListMachinesResponse.ProtoReflect.Descriptor instead.
 | ||||
| func (*ListMachinesResponse) Descriptor() ([]byte, []int) { | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{8} | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{10} | ||||
| } | ||||
| 
 | ||||
| func (x *ListMachinesResponse) GetMachines() []*Machine { | ||||
| @ -611,7 +705,7 @@ type ShareMachineRequest struct { | ||||
| func (x *ShareMachineRequest) Reset() { | ||||
| 	*x = ShareMachineRequest{} | ||||
| 	if protoimpl.UnsafeEnabled { | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[9] | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[11] | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		ms.StoreMessageInfo(mi) | ||||
| 	} | ||||
| @ -624,7 +718,7 @@ func (x *ShareMachineRequest) String() string { | ||||
| func (*ShareMachineRequest) ProtoMessage() {} | ||||
| 
 | ||||
| func (x *ShareMachineRequest) ProtoReflect() protoreflect.Message { | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[9] | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[11] | ||||
| 	if protoimpl.UnsafeEnabled && x != nil { | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		if ms.LoadMessageInfo() == nil { | ||||
| @ -637,7 +731,7 @@ func (x *ShareMachineRequest) ProtoReflect() protoreflect.Message { | ||||
| 
 | ||||
| // Deprecated: Use ShareMachineRequest.ProtoReflect.Descriptor instead.
 | ||||
| func (*ShareMachineRequest) Descriptor() ([]byte, []int) { | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{9} | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{11} | ||||
| } | ||||
| 
 | ||||
| func (x *ShareMachineRequest) GetMachineId() uint64 { | ||||
| @ -665,7 +759,7 @@ type ShareMachineResponse struct { | ||||
| func (x *ShareMachineResponse) Reset() { | ||||
| 	*x = ShareMachineResponse{} | ||||
| 	if protoimpl.UnsafeEnabled { | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[10] | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[12] | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		ms.StoreMessageInfo(mi) | ||||
| 	} | ||||
| @ -678,7 +772,7 @@ func (x *ShareMachineResponse) String() string { | ||||
| func (*ShareMachineResponse) ProtoMessage() {} | ||||
| 
 | ||||
| func (x *ShareMachineResponse) ProtoReflect() protoreflect.Message { | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[10] | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[12] | ||||
| 	if protoimpl.UnsafeEnabled && x != nil { | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		if ms.LoadMessageInfo() == nil { | ||||
| @ -691,7 +785,7 @@ func (x *ShareMachineResponse) ProtoReflect() protoreflect.Message { | ||||
| 
 | ||||
| // Deprecated: Use ShareMachineResponse.ProtoReflect.Descriptor instead.
 | ||||
| func (*ShareMachineResponse) Descriptor() ([]byte, []int) { | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{10} | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{12} | ||||
| } | ||||
| 
 | ||||
| func (x *ShareMachineResponse) GetMachine() *Machine { | ||||
| @ -713,7 +807,7 @@ type UnshareMachineRequest struct { | ||||
| func (x *UnshareMachineRequest) Reset() { | ||||
| 	*x = UnshareMachineRequest{} | ||||
| 	if protoimpl.UnsafeEnabled { | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[11] | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[13] | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		ms.StoreMessageInfo(mi) | ||||
| 	} | ||||
| @ -726,7 +820,7 @@ func (x *UnshareMachineRequest) String() string { | ||||
| func (*UnshareMachineRequest) ProtoMessage() {} | ||||
| 
 | ||||
| func (x *UnshareMachineRequest) ProtoReflect() protoreflect.Message { | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[11] | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[13] | ||||
| 	if protoimpl.UnsafeEnabled && x != nil { | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		if ms.LoadMessageInfo() == nil { | ||||
| @ -739,7 +833,7 @@ func (x *UnshareMachineRequest) ProtoReflect() protoreflect.Message { | ||||
| 
 | ||||
| // Deprecated: Use UnshareMachineRequest.ProtoReflect.Descriptor instead.
 | ||||
| func (*UnshareMachineRequest) Descriptor() ([]byte, []int) { | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{11} | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{13} | ||||
| } | ||||
| 
 | ||||
| func (x *UnshareMachineRequest) GetMachineId() uint64 { | ||||
| @ -767,7 +861,7 @@ type UnshareMachineResponse struct { | ||||
| func (x *UnshareMachineResponse) Reset() { | ||||
| 	*x = UnshareMachineResponse{} | ||||
| 	if protoimpl.UnsafeEnabled { | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[12] | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[14] | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		ms.StoreMessageInfo(mi) | ||||
| 	} | ||||
| @ -780,7 +874,7 @@ func (x *UnshareMachineResponse) String() string { | ||||
| func (*UnshareMachineResponse) ProtoMessage() {} | ||||
| 
 | ||||
| func (x *UnshareMachineResponse) ProtoReflect() protoreflect.Message { | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[12] | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[14] | ||||
| 	if protoimpl.UnsafeEnabled && x != nil { | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		if ms.LoadMessageInfo() == nil { | ||||
| @ -793,7 +887,7 @@ func (x *UnshareMachineResponse) ProtoReflect() protoreflect.Message { | ||||
| 
 | ||||
| // Deprecated: Use UnshareMachineResponse.ProtoReflect.Descriptor instead.
 | ||||
| func (*UnshareMachineResponse) Descriptor() ([]byte, []int) { | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{12} | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{14} | ||||
| } | ||||
| 
 | ||||
| func (x *UnshareMachineResponse) GetMachine() *Machine { | ||||
| @ -817,7 +911,7 @@ type DebugCreateMachineRequest struct { | ||||
| func (x *DebugCreateMachineRequest) Reset() { | ||||
| 	*x = DebugCreateMachineRequest{} | ||||
| 	if protoimpl.UnsafeEnabled { | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[13] | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[15] | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		ms.StoreMessageInfo(mi) | ||||
| 	} | ||||
| @ -830,7 +924,7 @@ func (x *DebugCreateMachineRequest) String() string { | ||||
| func (*DebugCreateMachineRequest) ProtoMessage() {} | ||||
| 
 | ||||
| func (x *DebugCreateMachineRequest) ProtoReflect() protoreflect.Message { | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[13] | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[15] | ||||
| 	if protoimpl.UnsafeEnabled && x != nil { | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		if ms.LoadMessageInfo() == nil { | ||||
| @ -843,7 +937,7 @@ func (x *DebugCreateMachineRequest) ProtoReflect() protoreflect.Message { | ||||
| 
 | ||||
| // Deprecated: Use DebugCreateMachineRequest.ProtoReflect.Descriptor instead.
 | ||||
| func (*DebugCreateMachineRequest) Descriptor() ([]byte, []int) { | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{13} | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{15} | ||||
| } | ||||
| 
 | ||||
| func (x *DebugCreateMachineRequest) GetNamespace() string { | ||||
| @ -885,7 +979,7 @@ type DebugCreateMachineResponse struct { | ||||
| func (x *DebugCreateMachineResponse) Reset() { | ||||
| 	*x = DebugCreateMachineResponse{} | ||||
| 	if protoimpl.UnsafeEnabled { | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[14] | ||||
| 		mi := &file_headscale_v1_machine_proto_msgTypes[16] | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		ms.StoreMessageInfo(mi) | ||||
| 	} | ||||
| @ -898,7 +992,7 @@ func (x *DebugCreateMachineResponse) String() string { | ||||
| func (*DebugCreateMachineResponse) ProtoMessage() {} | ||||
| 
 | ||||
| func (x *DebugCreateMachineResponse) ProtoReflect() protoreflect.Message { | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[14] | ||||
| 	mi := &file_headscale_v1_machine_proto_msgTypes[16] | ||||
| 	if protoimpl.UnsafeEnabled && x != nil { | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		if ms.LoadMessageInfo() == nil { | ||||
| @ -911,7 +1005,7 @@ func (x *DebugCreateMachineResponse) ProtoReflect() protoreflect.Message { | ||||
| 
 | ||||
| // Deprecated: Use DebugCreateMachineResponse.ProtoReflect.Descriptor instead.
 | ||||
| func (*DebugCreateMachineResponse) Descriptor() ([]byte, []int) { | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{14} | ||||
| 	return file_headscale_v1_machine_proto_rawDescGZIP(), []int{16} | ||||
| } | ||||
| 
 | ||||
| func (x *DebugCreateMachineResponse) GetMachine() *Machine { | ||||
| @ -994,59 +1088,67 @@ var file_headscale_v1_machine_proto_rawDesc = []byte{ | ||||
| 	0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, | ||||
| 	0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x22, 0x17, 0x0a, 0x15, | ||||
| 	0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, | ||||
| 	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, | ||||
| 	0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, | ||||
| 	0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, | ||||
| 	0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x49, 0x0a, 0x14, 0x4c, 0x69, | ||||
| 	0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, | ||||
| 	0x73, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, | ||||
| 	0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, | ||||
| 	0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x08, 0x6d, 0x61, 0x63, | ||||
| 	0x68, 0x69, 0x6e, 0x65, 0x73, 0x22, 0x52, 0x0a, 0x13, 0x53, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, | ||||
| 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, | ||||
| 	0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, | ||||
| 	0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, | ||||
| 	0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, | ||||
| 	0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x47, 0x0a, 0x14, 0x53, 0x68, 0x61, | ||||
| 	0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, | ||||
| 	0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, | ||||
| 	0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, | ||||
| 	0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, | ||||
| 	0x6e, 0x65, 0x22, 0x54, 0x0a, 0x15, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, | ||||
| 	0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, | ||||
| 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, | ||||
| 	0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, | ||||
| 	0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, | ||||
| 	0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x49, 0x0a, 0x16, 0x55, 0x6e, 0x73, 0x68, | ||||
| 	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x0a, 0x14, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4d, | ||||
| 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, | ||||
| 	0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, | ||||
| 	0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x22, 0x48, 0x0a, 0x15, | ||||
| 	0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, | ||||
| 	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, | ||||
| 	0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, | ||||
| 	0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, | ||||
| 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x22, 0x33, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, | ||||
| 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, | ||||
| 	0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, | ||||
| 	0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x49, 0x0a, 0x14, 0x4c, | ||||
| 	0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, | ||||
| 	0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x18, | ||||
| 	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, | ||||
| 	0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x08, 0x6d, 0x61, | ||||
| 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x22, 0x52, 0x0a, 0x13, 0x53, 0x68, 0x61, 0x72, 0x65, 0x4d, | ||||
| 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, | ||||
| 	0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, | ||||
| 	0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, | ||||
| 	0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, | ||||
| 	0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x47, 0x0a, 0x14, 0x53, 0x68, | ||||
| 	0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, | ||||
| 	0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, | ||||
| 	0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, | ||||
| 	0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, | ||||
| 	0x69, 0x6e, 0x65, 0x22, 0x77, 0x0a, 0x19, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, | ||||
| 	0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, | ||||
| 	0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, | ||||
| 	0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x10, | ||||
| 	0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, | ||||
| 	0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, | ||||
| 	0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, | ||||
| 	0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, 0x1a, | ||||
| 	0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, | ||||
| 	0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, | ||||
| 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, | ||||
| 	0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, | ||||
| 	0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2a, 0x82, 0x01, 0x0a, 0x0e, | ||||
| 	0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1f, | ||||
| 	0x0a, 0x1b, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, | ||||
| 	0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, | ||||
| 	0x1c, 0x0a, 0x18, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, | ||||
| 	0x4f, 0x44, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x01, 0x12, 0x17, 0x0a, | ||||
| 	0x13, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, | ||||
| 	0x5f, 0x43, 0x4c, 0x49, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, | ||||
| 	0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x4f, 0x49, 0x44, 0x43, 0x10, 0x03, | ||||
| 	0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, | ||||
| 	0x75, 0x61, 0x6e, 0x66, 0x6f, 0x6e, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, | ||||
| 	0x65, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, | ||||
| 	0x74, 0x6f, 0x33, | ||||
| 	0x69, 0x6e, 0x65, 0x22, 0x54, 0x0a, 0x15, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, | ||||
| 	0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, | ||||
| 	0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, | ||||
| 	0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, | ||||
| 	0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, | ||||
| 	0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x49, 0x0a, 0x16, 0x55, 0x6e, 0x73, | ||||
| 	0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, | ||||
| 	0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, | ||||
| 	0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, | ||||
| 	0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, | ||||
| 	0x68, 0x69, 0x6e, 0x65, 0x22, 0x77, 0x0a, 0x19, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, | ||||
| 	0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, | ||||
| 	0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, | ||||
| 	0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, | ||||
| 	0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, | ||||
| 	0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, | ||||
| 	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, | ||||
| 	0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, | ||||
| 	0x1a, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x68, | ||||
| 	0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x6d, | ||||
| 	0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, | ||||
| 	0x65, 0x61, 0x64, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, | ||||
| 	0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2a, 0x82, 0x01, 0x0a, | ||||
| 	0x0e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, | ||||
| 	0x1f, 0x0a, 0x1b, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, | ||||
| 	0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, | ||||
| 	0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, | ||||
| 	0x48, 0x4f, 0x44, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x01, 0x12, 0x17, | ||||
| 	0x0a, 0x13, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, | ||||
| 	0x44, 0x5f, 0x43, 0x4c, 0x49, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x47, 0x49, 0x53, | ||||
| 	0x54, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x4f, 0x49, 0x44, 0x43, 0x10, | ||||
| 	0x03, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, | ||||
| 	0x6a, 0x75, 0x61, 0x6e, 0x66, 0x6f, 0x6e, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x73, 0x63, 0x61, | ||||
| 	0x6c, 0x65, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, | ||||
| 	0x6f, 0x74, 0x6f, 0x33, | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| @ -1062,7 +1164,7 @@ func file_headscale_v1_machine_proto_rawDescGZIP() []byte { | ||||
| } | ||||
| 
 | ||||
| var file_headscale_v1_machine_proto_enumTypes = make([]protoimpl.EnumInfo, 1) | ||||
| var file_headscale_v1_machine_proto_msgTypes = make([]protoimpl.MessageInfo, 15) | ||||
| var file_headscale_v1_machine_proto_msgTypes = make([]protoimpl.MessageInfo, 17) | ||||
| var file_headscale_v1_machine_proto_goTypes = []interface{}{ | ||||
| 	(RegisterMethod)(0),                // 0: headscale.v1.RegisterMethod
 | ||||
| 	(*Machine)(nil),                    // 1: headscale.v1.Machine
 | ||||
| @ -1072,37 +1174,40 @@ var file_headscale_v1_machine_proto_goTypes = []interface{}{ | ||||
| 	(*GetMachineResponse)(nil),         // 5: headscale.v1.GetMachineResponse
 | ||||
| 	(*DeleteMachineRequest)(nil),       // 6: headscale.v1.DeleteMachineRequest
 | ||||
| 	(*DeleteMachineResponse)(nil),      // 7: headscale.v1.DeleteMachineResponse
 | ||||
| 	(*ListMachinesRequest)(nil),        // 8: headscale.v1.ListMachinesRequest
 | ||||
| 	(*ListMachinesResponse)(nil),       // 9: headscale.v1.ListMachinesResponse
 | ||||
| 	(*ShareMachineRequest)(nil),        // 10: headscale.v1.ShareMachineRequest
 | ||||
| 	(*ShareMachineResponse)(nil),       // 11: headscale.v1.ShareMachineResponse
 | ||||
| 	(*UnshareMachineRequest)(nil),      // 12: headscale.v1.UnshareMachineRequest
 | ||||
| 	(*UnshareMachineResponse)(nil),     // 13: headscale.v1.UnshareMachineResponse
 | ||||
| 	(*DebugCreateMachineRequest)(nil),  // 14: headscale.v1.DebugCreateMachineRequest
 | ||||
| 	(*DebugCreateMachineResponse)(nil), // 15: headscale.v1.DebugCreateMachineResponse
 | ||||
| 	(*Namespace)(nil),                  // 16: headscale.v1.Namespace
 | ||||
| 	(*timestamppb.Timestamp)(nil),      // 17: google.protobuf.Timestamp
 | ||||
| 	(*PreAuthKey)(nil),                 // 18: headscale.v1.PreAuthKey
 | ||||
| 	(*ExpireMachineRequest)(nil),       // 8: headscale.v1.ExpireMachineRequest
 | ||||
| 	(*ExpireMachineResponse)(nil),      // 9: headscale.v1.ExpireMachineResponse
 | ||||
| 	(*ListMachinesRequest)(nil),        // 10: headscale.v1.ListMachinesRequest
 | ||||
| 	(*ListMachinesResponse)(nil),       // 11: headscale.v1.ListMachinesResponse
 | ||||
| 	(*ShareMachineRequest)(nil),        // 12: headscale.v1.ShareMachineRequest
 | ||||
| 	(*ShareMachineResponse)(nil),       // 13: headscale.v1.ShareMachineResponse
 | ||||
| 	(*UnshareMachineRequest)(nil),      // 14: headscale.v1.UnshareMachineRequest
 | ||||
| 	(*UnshareMachineResponse)(nil),     // 15: headscale.v1.UnshareMachineResponse
 | ||||
| 	(*DebugCreateMachineRequest)(nil),  // 16: headscale.v1.DebugCreateMachineRequest
 | ||||
| 	(*DebugCreateMachineResponse)(nil), // 17: headscale.v1.DebugCreateMachineResponse
 | ||||
| 	(*Namespace)(nil),                  // 18: headscale.v1.Namespace
 | ||||
| 	(*timestamppb.Timestamp)(nil),      // 19: google.protobuf.Timestamp
 | ||||
| 	(*PreAuthKey)(nil),                 // 20: headscale.v1.PreAuthKey
 | ||||
| } | ||||
| var file_headscale_v1_machine_proto_depIdxs = []int32{ | ||||
| 	16, // 0: headscale.v1.Machine.namespace:type_name -> headscale.v1.Namespace
 | ||||
| 	18, // 0: headscale.v1.Machine.namespace:type_name -> headscale.v1.Namespace
 | ||||
| 	0,  // 1: headscale.v1.Machine.register_method:type_name -> headscale.v1.RegisterMethod
 | ||||
| 	17, // 2: headscale.v1.Machine.last_seen:type_name -> google.protobuf.Timestamp
 | ||||
| 	17, // 3: headscale.v1.Machine.last_successful_update:type_name -> google.protobuf.Timestamp
 | ||||
| 	17, // 4: headscale.v1.Machine.expiry:type_name -> google.protobuf.Timestamp
 | ||||
| 	18, // 5: headscale.v1.Machine.pre_auth_key:type_name -> headscale.v1.PreAuthKey
 | ||||
| 	17, // 6: headscale.v1.Machine.created_at:type_name -> google.protobuf.Timestamp
 | ||||
| 	19, // 2: headscale.v1.Machine.last_seen:type_name -> google.protobuf.Timestamp
 | ||||
| 	19, // 3: headscale.v1.Machine.last_successful_update:type_name -> google.protobuf.Timestamp
 | ||||
| 	19, // 4: headscale.v1.Machine.expiry:type_name -> google.protobuf.Timestamp
 | ||||
| 	20, // 5: headscale.v1.Machine.pre_auth_key:type_name -> headscale.v1.PreAuthKey
 | ||||
| 	19, // 6: headscale.v1.Machine.created_at:type_name -> google.protobuf.Timestamp
 | ||||
| 	1,  // 7: headscale.v1.RegisterMachineResponse.machine:type_name -> headscale.v1.Machine
 | ||||
| 	1,  // 8: headscale.v1.GetMachineResponse.machine:type_name -> headscale.v1.Machine
 | ||||
| 	1,  // 9: headscale.v1.ListMachinesResponse.machines:type_name -> headscale.v1.Machine
 | ||||
| 	1,  // 10: headscale.v1.ShareMachineResponse.machine:type_name -> headscale.v1.Machine
 | ||||
| 	1,  // 11: headscale.v1.UnshareMachineResponse.machine:type_name -> headscale.v1.Machine
 | ||||
| 	1,  // 12: headscale.v1.DebugCreateMachineResponse.machine:type_name -> headscale.v1.Machine
 | ||||
| 	13, // [13:13] is the sub-list for method output_type
 | ||||
| 	13, // [13:13] is the sub-list for method input_type
 | ||||
| 	13, // [13:13] is the sub-list for extension type_name
 | ||||
| 	13, // [13:13] is the sub-list for extension extendee
 | ||||
| 	0,  // [0:13] is the sub-list for field type_name
 | ||||
| 	1,  // 9: headscale.v1.ExpireMachineResponse.machine:type_name -> headscale.v1.Machine
 | ||||
| 	1,  // 10: headscale.v1.ListMachinesResponse.machines:type_name -> headscale.v1.Machine
 | ||||
| 	1,  // 11: headscale.v1.ShareMachineResponse.machine:type_name -> headscale.v1.Machine
 | ||||
| 	1,  // 12: headscale.v1.UnshareMachineResponse.machine:type_name -> headscale.v1.Machine
 | ||||
| 	1,  // 13: headscale.v1.DebugCreateMachineResponse.machine:type_name -> headscale.v1.Machine
 | ||||
| 	14, // [14:14] is the sub-list for method output_type
 | ||||
| 	14, // [14:14] is the sub-list for method input_type
 | ||||
| 	14, // [14:14] is the sub-list for extension type_name
 | ||||
| 	14, // [14:14] is the sub-list for extension extendee
 | ||||
| 	0,  // [0:14] is the sub-list for field type_name
 | ||||
| } | ||||
| 
 | ||||
| func init() { file_headscale_v1_machine_proto_init() } | ||||
| @ -1198,7 +1303,7 @@ func file_headscale_v1_machine_proto_init() { | ||||
| 			} | ||||
| 		} | ||||
| 		file_headscale_v1_machine_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { | ||||
| 			switch v := v.(*ListMachinesRequest); i { | ||||
| 			switch v := v.(*ExpireMachineRequest); i { | ||||
| 			case 0: | ||||
| 				return &v.state | ||||
| 			case 1: | ||||
| @ -1210,7 +1315,7 @@ func file_headscale_v1_machine_proto_init() { | ||||
| 			} | ||||
| 		} | ||||
| 		file_headscale_v1_machine_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { | ||||
| 			switch v := v.(*ListMachinesResponse); i { | ||||
| 			switch v := v.(*ExpireMachineResponse); i { | ||||
| 			case 0: | ||||
| 				return &v.state | ||||
| 			case 1: | ||||
| @ -1222,7 +1327,7 @@ func file_headscale_v1_machine_proto_init() { | ||||
| 			} | ||||
| 		} | ||||
| 		file_headscale_v1_machine_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { | ||||
| 			switch v := v.(*ShareMachineRequest); i { | ||||
| 			switch v := v.(*ListMachinesRequest); i { | ||||
| 			case 0: | ||||
| 				return &v.state | ||||
| 			case 1: | ||||
| @ -1234,7 +1339,7 @@ func file_headscale_v1_machine_proto_init() { | ||||
| 			} | ||||
| 		} | ||||
| 		file_headscale_v1_machine_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { | ||||
| 			switch v := v.(*ShareMachineResponse); i { | ||||
| 			switch v := v.(*ListMachinesResponse); i { | ||||
| 			case 0: | ||||
| 				return &v.state | ||||
| 			case 1: | ||||
| @ -1246,7 +1351,7 @@ func file_headscale_v1_machine_proto_init() { | ||||
| 			} | ||||
| 		} | ||||
| 		file_headscale_v1_machine_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { | ||||
| 			switch v := v.(*UnshareMachineRequest); i { | ||||
| 			switch v := v.(*ShareMachineRequest); i { | ||||
| 			case 0: | ||||
| 				return &v.state | ||||
| 			case 1: | ||||
| @ -1258,7 +1363,7 @@ func file_headscale_v1_machine_proto_init() { | ||||
| 			} | ||||
| 		} | ||||
| 		file_headscale_v1_machine_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { | ||||
| 			switch v := v.(*UnshareMachineResponse); i { | ||||
| 			switch v := v.(*ShareMachineResponse); i { | ||||
| 			case 0: | ||||
| 				return &v.state | ||||
| 			case 1: | ||||
| @ -1270,7 +1375,7 @@ func file_headscale_v1_machine_proto_init() { | ||||
| 			} | ||||
| 		} | ||||
| 		file_headscale_v1_machine_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { | ||||
| 			switch v := v.(*DebugCreateMachineRequest); i { | ||||
| 			switch v := v.(*UnshareMachineRequest); i { | ||||
| 			case 0: | ||||
| 				return &v.state | ||||
| 			case 1: | ||||
| @ -1282,6 +1387,30 @@ func file_headscale_v1_machine_proto_init() { | ||||
| 			} | ||||
| 		} | ||||
| 		file_headscale_v1_machine_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { | ||||
| 			switch v := v.(*UnshareMachineResponse); i { | ||||
| 			case 0: | ||||
| 				return &v.state | ||||
| 			case 1: | ||||
| 				return &v.sizeCache | ||||
| 			case 2: | ||||
| 				return &v.unknownFields | ||||
| 			default: | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 		file_headscale_v1_machine_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { | ||||
| 			switch v := v.(*DebugCreateMachineRequest); i { | ||||
| 			case 0: | ||||
| 				return &v.state | ||||
| 			case 1: | ||||
| 				return &v.sizeCache | ||||
| 			case 2: | ||||
| 				return &v.unknownFields | ||||
| 			default: | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 		file_headscale_v1_machine_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { | ||||
| 			switch v := v.(*DebugCreateMachineResponse); i { | ||||
| 			case 0: | ||||
| 				return &v.state | ||||
| @ -1300,7 +1429,7 @@ func file_headscale_v1_machine_proto_init() { | ||||
| 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(), | ||||
| 			RawDescriptor: file_headscale_v1_machine_proto_rawDesc, | ||||
| 			NumEnums:      1, | ||||
| 			NumMessages:   15, | ||||
| 			NumMessages:   17, | ||||
| 			NumExtensions: 0, | ||||
| 			NumServices:   0, | ||||
| 		}, | ||||
|  | ||||
| @ -161,6 +161,37 @@ | ||||
|         ] | ||||
|       } | ||||
|     }, | ||||
|     "/api/v1/machine/{machineId}/expire": { | ||||
|       "post": { | ||||
|         "operationId": "HeadscaleService_ExpireMachine", | ||||
|         "responses": { | ||||
|           "200": { | ||||
|             "description": "A successful response.", | ||||
|             "schema": { | ||||
|               "$ref": "#/definitions/v1ExpireMachineResponse" | ||||
|             } | ||||
|           }, | ||||
|           "default": { | ||||
|             "description": "An unexpected error response.", | ||||
|             "schema": { | ||||
|               "$ref": "#/definitions/rpcStatus" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "parameters": [ | ||||
|           { | ||||
|             "name": "machineId", | ||||
|             "in": "path", | ||||
|             "required": true, | ||||
|             "type": "string", | ||||
|             "format": "uint64" | ||||
|           } | ||||
|         ], | ||||
|         "tags": [ | ||||
|           "HeadscaleService" | ||||
|         ] | ||||
|       } | ||||
|     }, | ||||
|     "/api/v1/machine/{machineId}/routes": { | ||||
|       "get": { | ||||
|         "summary": "--- Route start ---", | ||||
| @ -649,6 +680,14 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "v1ExpireMachineResponse": { | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "machine": { | ||||
|           "$ref": "#/definitions/v1Machine" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "v1ExpirePreAuthKeyRequest": { | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|  | ||||
							
								
								
									
										21
									
								
								grpcv1.go
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								grpcv1.go
									
									
									
									
									
								
							| @ -201,6 +201,27 @@ func (api headscaleV1APIServer) DeleteMachine( | ||||
| 	return &v1.DeleteMachineResponse{}, nil | ||||
| } | ||||
| 
 | ||||
| func (api headscaleV1APIServer) ExpireMachine( | ||||
| 	ctx context.Context, | ||||
| 	request *v1.ExpireMachineRequest, | ||||
| ) (*v1.ExpireMachineResponse, error) { | ||||
| 	machine, err := api.h.GetMachineByID(request.GetMachineId()) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	api.h.ExpireMachine( | ||||
| 		machine, | ||||
| 	) | ||||
| 
 | ||||
| 	log.Trace(). | ||||
| 		Str("machine", machine.Name). | ||||
| 		Time("expiry", *machine.Expiry). | ||||
| 		Msg("machine expired") | ||||
| 
 | ||||
| 	return &v1.ExpireMachineResponse{Machine: machine.toProto()}, nil | ||||
| } | ||||
| 
 | ||||
| func (api headscaleV1APIServer) ListMachines( | ||||
| 	ctx context.Context, | ||||
| 	request *v1.ListMachinesRequest, | ||||
|  | ||||
| @ -897,6 +897,133 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() { | ||||
| 	assert.Len(s.T(), listOnlyMachineNamespaceAfterUnshare, 4) | ||||
| } | ||||
| 
 | ||||
| func (s *IntegrationCLITestSuite) TestNodeExpireCommand() { | ||||
| 	namespace, err := s.createNamespace("machine-expire-namespace") | ||||
| 	assert.Nil(s.T(), err) | ||||
| 
 | ||||
| 	// Randomly generated machine keys
 | ||||
| 	machineKeys := []string{ | ||||
| 		"9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe", | ||||
| 		"6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c", | ||||
| 		"f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507", | ||||
| 		"8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1", | ||||
| 		"cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084", | ||||
| 	} | ||||
| 	machines := make([]*v1.Machine, len(machineKeys)) | ||||
| 	assert.Nil(s.T(), err) | ||||
| 
 | ||||
| 	for index, machineKey := range machineKeys { | ||||
| 		_, err := ExecuteCommand( | ||||
| 			&s.headscale, | ||||
| 			[]string{ | ||||
| 				"headscale", | ||||
| 				"debug", | ||||
| 				"create-node", | ||||
| 				"--name", | ||||
| 				fmt.Sprintf("machine-%d", index+1), | ||||
| 				"--namespace", | ||||
| 				namespace.Name, | ||||
| 				"--key", | ||||
| 				machineKey, | ||||
| 				"--output", | ||||
| 				"json", | ||||
| 			}, | ||||
| 			[]string{}, | ||||
| 		) | ||||
| 		assert.Nil(s.T(), err) | ||||
| 
 | ||||
| 		machineResult, err := ExecuteCommand( | ||||
| 			&s.headscale, | ||||
| 			[]string{ | ||||
| 				"headscale", | ||||
| 				"nodes", | ||||
| 				"--namespace", | ||||
| 				namespace.Name, | ||||
| 				"register", | ||||
| 				"--key", | ||||
| 				machineKey, | ||||
| 				"--output", | ||||
| 				"json", | ||||
| 			}, | ||||
| 			[]string{}, | ||||
| 		) | ||||
| 		assert.Nil(s.T(), err) | ||||
| 
 | ||||
| 		var machine v1.Machine | ||||
| 		err = json.Unmarshal([]byte(machineResult), &machine) | ||||
| 		assert.Nil(s.T(), err) | ||||
| 
 | ||||
| 		machines[index] = &machine | ||||
| 	} | ||||
| 
 | ||||
| 	assert.Len(s.T(), machines, len(machineKeys)) | ||||
| 
 | ||||
| 	listAllResult, err := ExecuteCommand( | ||||
| 		&s.headscale, | ||||
| 		[]string{ | ||||
| 			"headscale", | ||||
| 			"nodes", | ||||
| 			"list", | ||||
| 			"--output", | ||||
| 			"json", | ||||
| 		}, | ||||
| 		[]string{}, | ||||
| 	) | ||||
| 	assert.Nil(s.T(), err) | ||||
| 
 | ||||
| 	var listAll []v1.Machine | ||||
| 	err = json.Unmarshal([]byte(listAllResult), &listAll) | ||||
| 	assert.Nil(s.T(), err) | ||||
| 
 | ||||
| 	assert.Len(s.T(), listAll, 5) | ||||
| 
 | ||||
| 	assert.True(s.T(), listAll[0].Expiry.AsTime().IsZero()) | ||||
| 	assert.True(s.T(), listAll[1].Expiry.AsTime().IsZero()) | ||||
| 	assert.True(s.T(), listAll[2].Expiry.AsTime().IsZero()) | ||||
| 	assert.True(s.T(), listAll[3].Expiry.AsTime().IsZero()) | ||||
| 	assert.True(s.T(), listAll[4].Expiry.AsTime().IsZero()) | ||||
| 
 | ||||
| 	for i := 0; i < 3; i++ { | ||||
| 		_, err := ExecuteCommand( | ||||
| 			&s.headscale, | ||||
| 			[]string{ | ||||
| 				"headscale", | ||||
| 				"nodes", | ||||
| 				"expire", | ||||
| 				"--identifier", | ||||
| 				fmt.Sprintf("%d", listAll[i].Id), | ||||
| 			}, | ||||
| 			[]string{}, | ||||
| 		) | ||||
| 		assert.Nil(s.T(), err) | ||||
| 	} | ||||
| 
 | ||||
| 	listAllAfterExpiryResult, err := ExecuteCommand( | ||||
| 		&s.headscale, | ||||
| 		[]string{ | ||||
| 			"headscale", | ||||
| 			"nodes", | ||||
| 			"list", | ||||
| 			"--output", | ||||
| 			"json", | ||||
| 		}, | ||||
| 		[]string{}, | ||||
| 	) | ||||
| 	assert.Nil(s.T(), err) | ||||
| 
 | ||||
| 	var listAllAfterExpiry []v1.Machine | ||||
| 	err = json.Unmarshal([]byte(listAllAfterExpiryResult), &listAllAfterExpiry) | ||||
| 	assert.Nil(s.T(), err) | ||||
| 
 | ||||
| 	assert.Len(s.T(), listAllAfterExpiry, 5) | ||||
| 
 | ||||
| 	assert.True(s.T(), listAllAfterExpiry[0].Expiry.AsTime().Before(time.Now())) | ||||
| 	assert.True(s.T(), listAllAfterExpiry[1].Expiry.AsTime().Before(time.Now())) | ||||
| 	assert.True(s.T(), listAllAfterExpiry[2].Expiry.AsTime().Before(time.Now())) | ||||
| 	assert.True(s.T(), listAllAfterExpiry[3].Expiry.AsTime().IsZero()) | ||||
| 	assert.True(s.T(), listAllAfterExpiry[4].Expiry.AsTime().IsZero()) | ||||
| } | ||||
| 
 | ||||
| func (s *IntegrationCLITestSuite) TestRouteCommand() { | ||||
| 	namespace, err := s.createNamespace("routes-namespace") | ||||
| 	assert.Nil(s.T(), err) | ||||
|  | ||||
							
								
								
									
										110
									
								
								machine.go
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								machine.go
									
									
									
									
									
								
							| @ -45,7 +45,6 @@ type Machine struct { | ||||
| 	LastSeen             *time.Time | ||||
| 	LastSuccessfulUpdate *time.Time | ||||
| 	Expiry               *time.Time | ||||
| 	RequestedExpiry      *time.Time | ||||
| 
 | ||||
| 	HostInfo      datatypes.JSON | ||||
| 	Endpoints     datatypes.JSON | ||||
| @ -62,44 +61,20 @@ type ( | ||||
| ) | ||||
| 
 | ||||
| // For the time being this method is rather naive.
 | ||||
| func (machine Machine) isAlreadyRegistered() bool { | ||||
| func (machine Machine) isRegistered() bool { | ||||
| 	return machine.Registered | ||||
| } | ||||
| 
 | ||||
| // isExpired returns whether the machine registration has expired.
 | ||||
| func (machine Machine) isExpired() bool { | ||||
| 	return time.Now().UTC().After(*machine.Expiry) | ||||
| } | ||||
| 
 | ||||
| // If the Machine is expired, updateMachineExpiry updates the Machine Expiry time to the maximum allowed duration,
 | ||||
| // or the default duration if no Expiry time was requested by the client. The expiry time here does not (yet) cause
 | ||||
| // a client to be disconnected, however they will have to re-auth the machine if they attempt to reconnect after the
 | ||||
| // expiry time.
 | ||||
| func (h *Headscale) updateMachineExpiry(machine *Machine) { | ||||
| 	if machine.isExpired() { | ||||
| 		now := time.Now().UTC() | ||||
| 		maxExpiry := now.Add( | ||||
| 			h.cfg.MaxMachineRegistrationDuration, | ||||
| 		) // calculate the maximum expiry
 | ||||
| 		defaultExpiry := now.Add( | ||||
| 			h.cfg.DefaultMachineRegistrationDuration, | ||||
| 		) // calculate the default expiry
 | ||||
| 
 | ||||
| 		// clamp the expiry time of the machine registration to the maximum allowed, or use the default if none supplied
 | ||||
| 		if maxExpiry.Before(*machine.RequestedExpiry) { | ||||
| 			log.Debug(). | ||||
| 				Msgf("Clamping registration expiry time to maximum: %v (%v)", maxExpiry, h.cfg.MaxMachineRegistrationDuration) | ||||
| 			machine.Expiry = &maxExpiry | ||||
| 		} else if machine.RequestedExpiry.IsZero() { | ||||
| 			log.Debug().Msgf("Using default machine registration expiry time: %v (%v)", defaultExpiry, h.cfg.DefaultMachineRegistrationDuration) | ||||
| 			machine.Expiry = &defaultExpiry | ||||
| 		} else { | ||||
| 			log.Debug().Msgf("Using requested machine registration expiry time: %v", machine.RequestedExpiry) | ||||
| 			machine.Expiry = machine.RequestedExpiry | ||||
| 		} | ||||
| 
 | ||||
| 		h.db.Save(&machine) | ||||
| 	// If Expiry is not set, the client has not indicated that
 | ||||
| 	// it wants an expiry time, it is therefor considered
 | ||||
| 	// to mean "not expired"
 | ||||
| 	if machine.Expiry.IsZero() { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	return time.Now().UTC().After(*machine.Expiry) | ||||
| } | ||||
| 
 | ||||
| func (h *Headscale) getDirectPeers(machine *Machine) (Machines, error) { | ||||
| @ -232,6 +207,23 @@ func (h *Headscale) getPeers(machine *Machine) (Machines, error) { | ||||
| 	return peers, nil | ||||
| } | ||||
| 
 | ||||
| func (h *Headscale) getValidPeers(machine *Machine) (Machines, error) { | ||||
| 	validPeers := make(Machines, 0) | ||||
| 
 | ||||
| 	peers, err := h.getPeers(machine) | ||||
| 	if err != nil { | ||||
| 		return Machines{}, err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, peer := range peers { | ||||
| 		if peer.isRegistered() && !peer.isExpired() { | ||||
| 			validPeers = append(validPeers, peer) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return validPeers, nil | ||||
| } | ||||
| 
 | ||||
| func (h *Headscale) ListMachines() ([]Machine, error) { | ||||
| 	machines := []Machine{} | ||||
| 	if err := h.db.Preload("AuthKey").Preload("AuthKey.Namespace").Preload("Namespace").Find(&machines).Error; err != nil { | ||||
| @ -287,6 +279,28 @@ func (h *Headscale) UpdateMachine(machine *Machine) error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // ExpireMachine takes a Machine struct and sets the expire field to now.
 | ||||
| func (h *Headscale) ExpireMachine(machine *Machine) { | ||||
| 	now := time.Now() | ||||
| 	machine.Expiry = &now | ||||
| 
 | ||||
| 	h.setLastStateChangeToNow(machine.Namespace.Name) | ||||
| 
 | ||||
| 	h.db.Save(machine) | ||||
| } | ||||
| 
 | ||||
| // RefreshMachine takes a Machine struct and sets the expire field to now.
 | ||||
| func (h *Headscale) RefreshMachine(machine *Machine, expiry time.Time) { | ||||
| 	now := time.Now() | ||||
| 
 | ||||
| 	machine.LastSuccessfulUpdate = &now | ||||
| 	machine.Expiry = &expiry | ||||
| 
 | ||||
| 	h.setLastStateChangeToNow(machine.Namespace.Name) | ||||
| 
 | ||||
| 	h.db.Save(machine) | ||||
| } | ||||
| 
 | ||||
| // DeleteMachine softs deletes a Machine from the database.
 | ||||
| func (h *Headscale) DeleteMachine(machine *Machine) error { | ||||
| 	err := h.RemoveSharedMachineFromAllNamespaces(machine) | ||||
| @ -624,12 +638,37 @@ func (h *Headscale) RegisterMachine( | ||||
| 		return nil, errMachineNotFound | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO(kradalby): Currently, if it fails to find a requested expiry, non will be set
 | ||||
| 	// This means that if a user is to slow with register a machine, it will possibly not
 | ||||
| 	// have the correct expiry.
 | ||||
| 	requestedTime := time.Time{} | ||||
| 	if requestedTimeIf, found := h.requestedExpiryCache.Get(machineKey.HexString()); found { | ||||
| 		log.Trace(). | ||||
| 			Caller(). | ||||
| 			Str("machine", machine.Name). | ||||
| 			Msg("Expiry time found in cache, assigning to node") | ||||
| 		if reqTime, ok := requestedTimeIf.(time.Time); ok { | ||||
| 			requestedTime = reqTime | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if machine.isRegistered() { | ||||
| 		log.Trace(). | ||||
| 			Caller(). | ||||
| 			Str("machine", machine.Name). | ||||
| 			Msg("machine already registered, reauthenticating") | ||||
| 
 | ||||
| 		h.RefreshMachine(&machine, requestedTime) | ||||
| 
 | ||||
| 		return &machine, nil | ||||
| 	} | ||||
| 
 | ||||
| 	log.Trace(). | ||||
| 		Caller(). | ||||
| 		Str("machine", machine.Name). | ||||
| 		Msg("Attempting to register machine") | ||||
| 
 | ||||
| 	if machine.isAlreadyRegistered() { | ||||
| 	if machine.isRegistered() { | ||||
| 		err := errMachineAlreadyRegistered | ||||
| 		log.Error(). | ||||
| 			Caller(). | ||||
| @ -660,7 +699,8 @@ func (h *Headscale) RegisterMachine( | ||||
| 	machine.IPAddress = ip.String() | ||||
| 	machine.NamespaceID = namespace.ID | ||||
| 	machine.Registered = true | ||||
| 	machine.RegisterMethod = "cli" | ||||
| 	machine.RegisterMethod = RegisterMethodCLI | ||||
| 	machine.Expiry = &requestedTime | ||||
| 	h.db.Save(&machine) | ||||
| 
 | ||||
| 	log.Trace(). | ||||
|  | ||||
| @ -3,6 +3,7 @@ package headscale | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"gopkg.in/check.v1" | ||||
| ) | ||||
| @ -25,7 +26,7 @@ func (s *Suite) TestGetMachine(c *check.C) { | ||||
| 		Name:           "testmachine", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 	} | ||||
| 	app.db.Save(machine) | ||||
| @ -55,7 +56,7 @@ func (s *Suite) TestGetMachineByID(c *check.C) { | ||||
| 		Name:           "testmachine", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 	} | ||||
| 	app.db.Save(&machine) | ||||
| @ -78,7 +79,7 @@ func (s *Suite) TestDeleteMachine(c *check.C) { | ||||
| 		Name:           "testmachine", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		AuthKeyID:      uint(1), | ||||
| 	} | ||||
| 	app.db.Save(&machine) | ||||
| @ -113,7 +114,7 @@ func (s *Suite) TestHardDeleteMachine(c *check.C) { | ||||
| 		Name:           "testmachine3", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		AuthKeyID:      uint(1), | ||||
| 	} | ||||
| 	app.db.Save(&machine) | ||||
| @ -144,7 +145,7 @@ func (s *Suite) TestGetDirectPeers(c *check.C) { | ||||
| 			Name:           "testmachine" + strconv.Itoa(index), | ||||
| 			NamespaceID:    namespace.ID, | ||||
| 			Registered:     true, | ||||
| 			RegisterMethod: "authKey", | ||||
| 			RegisterMethod: RegisterMethodAuthKey, | ||||
| 			AuthKeyID:      uint(pak.ID), | ||||
| 		} | ||||
| 		app.db.Save(&machine) | ||||
| @ -164,3 +165,37 @@ func (s *Suite) TestGetDirectPeers(c *check.C) { | ||||
| 	c.Assert(peersOfMachine0[5].Name, check.Equals, "testmachine7") | ||||
| 	c.Assert(peersOfMachine0[8].Name, check.Equals, "testmachine10") | ||||
| } | ||||
| 
 | ||||
| func (s *Suite) TestExpireMachine(c *check.C) { | ||||
| 	namespace, err := app.CreateNamespace("test") | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 
 | ||||
| 	pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil) | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 
 | ||||
| 	_, err = app.GetMachine("test", "testmachine") | ||||
| 	c.Assert(err, check.NotNil) | ||||
| 
 | ||||
| 	machine := &Machine{ | ||||
| 		ID:             0, | ||||
| 		MachineKey:     "foo", | ||||
| 		NodeKey:        "bar", | ||||
| 		DiscoKey:       "faa", | ||||
| 		Name:           "testmachine", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 		Expiry:         &time.Time{}, | ||||
| 	} | ||||
| 	app.db.Save(machine) | ||||
| 
 | ||||
| 	machineFromDB, err := app.GetMachine("test", "testmachine") | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 
 | ||||
| 	c.Assert(machineFromDB.isExpired(), check.Equals, false) | ||||
| 
 | ||||
| 	app.ExpireMachine(machineFromDB) | ||||
| 
 | ||||
| 	c.Assert(machineFromDB.isExpired(), check.Equals, true) | ||||
| } | ||||
|  | ||||
| @ -53,7 +53,7 @@ func (s *Suite) TestDestroyNamespaceErrors(c *check.C) { | ||||
| 		Name:           "testmachine", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 	} | ||||
| 	app.db.Save(&machine) | ||||
| @ -145,7 +145,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) { | ||||
| 		NamespaceID:    namespaceShared1.ID, | ||||
| 		Namespace:      *namespaceShared1, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.1", | ||||
| 		AuthKeyID:      uint(preAuthKeyShared1.ID), | ||||
| 	} | ||||
| @ -163,7 +163,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) { | ||||
| 		NamespaceID:    namespaceShared2.ID, | ||||
| 		Namespace:      *namespaceShared2, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.2", | ||||
| 		AuthKeyID:      uint(preAuthKeyShared2.ID), | ||||
| 	} | ||||
| @ -181,7 +181,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) { | ||||
| 		NamespaceID:    namespaceShared3.ID, | ||||
| 		Namespace:      *namespaceShared3, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.3", | ||||
| 		AuthKeyID:      uint(preAuthKeyShared3.ID), | ||||
| 	} | ||||
| @ -199,7 +199,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) { | ||||
| 		NamespaceID:    namespaceShared1.ID, | ||||
| 		Namespace:      *namespaceShared1, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.4", | ||||
| 		AuthKeyID:      uint(preAuthKey2Shared1.ID), | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										113
									
								
								oidc.go
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								oidc.go
									
									
									
									
									
								
							| @ -4,6 +4,7 @@ import ( | ||||
| 	"context" | ||||
| 	"crypto/rand" | ||||
| 	"encoding/hex" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"regexp" | ||||
| @ -15,6 +16,7 @@ import ( | ||||
| 	"github.com/patrickmn/go-cache" | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"golang.org/x/oauth2" | ||||
| 	"gorm.io/gorm" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| @ -37,7 +39,10 @@ func (h *Headscale) initOIDC() error { | ||||
| 		h.oidcProvider, err = oidc.NewProvider(context.Background(), h.cfg.OIDC.Issuer) | ||||
| 
 | ||||
| 		if err != nil { | ||||
| 			log.Error().Msgf("Could not retrieve OIDC Config: %s", err.Error()) | ||||
| 			log.Error(). | ||||
| 				Err(err). | ||||
| 				Caller(). | ||||
| 				Msgf("Could not retrieve OIDC Config: %s", err.Error()) | ||||
| 
 | ||||
| 			return err | ||||
| 		} | ||||
| @ -69,16 +74,23 @@ func (h *Headscale) initOIDC() error { | ||||
| // Puts machine key in cache so the callback can retrieve it using the oidc state param
 | ||||
| // Listens in /oidc/register/:mKey.
 | ||||
| func (h *Headscale) RegisterOIDC(ctx *gin.Context) { | ||||
| 	mKeyStr := ctx.Param("mkey") | ||||
| 	if mKeyStr == "" { | ||||
| 	machineKeyStr := ctx.Param("mkey") | ||||
| 	if machineKeyStr == "" { | ||||
| 		ctx.String(http.StatusBadRequest, "Wrong params") | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	log.Trace(). | ||||
| 		Caller(). | ||||
| 		Str("machine_key", machineKeyStr). | ||||
| 		Msg("Received oidc register call") | ||||
| 
 | ||||
| 	randomBlob := make([]byte, randomByteSize) | ||||
| 	if _, err := rand.Read(randomBlob); err != nil { | ||||
| 		log.Error().Msg("could not read 16 bytes from rand") | ||||
| 		log.Error(). | ||||
| 			Caller(). | ||||
| 			Msg("could not read 16 bytes from rand") | ||||
| 		ctx.String(http.StatusInternalServerError, "could not read 16 bytes from rand") | ||||
| 
 | ||||
| 		return | ||||
| @ -87,7 +99,7 @@ func (h *Headscale) RegisterOIDC(ctx *gin.Context) { | ||||
| 	stateStr := hex.EncodeToString(randomBlob)[:32] | ||||
| 
 | ||||
| 	// place the machine key into the state cache, so it can be retrieved later
 | ||||
| 	h.oidcStateCache.Set(stateStr, mKeyStr, oidcStateCacheExpiration) | ||||
| 	h.oidcStateCache.Set(stateStr, machineKeyStr, oidcStateCacheExpiration) | ||||
| 
 | ||||
| 	authURL := h.oauth2Config.AuthCodeURL(stateStr) | ||||
| 	log.Debug().Msgf("Redirecting to %s for authentication", authURL) | ||||
| @ -117,7 +129,11 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	log.Debug().Msgf("AccessToken: %v", oauth2Token.AccessToken) | ||||
| 	log.Trace(). | ||||
| 		Caller(). | ||||
| 		Str("code", code). | ||||
| 		Str("state", state). | ||||
| 		Msg("Got oidc callback") | ||||
| 
 | ||||
| 	rawIDToken, rawIDTokenOK := oauth2Token.Extra("id_token").(string) | ||||
| 	if !rawIDTokenOK { | ||||
| @ -130,7 +146,11 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { | ||||
| 
 | ||||
| 	idToken, err := verifier.Verify(context.Background(), rawIDToken) | ||||
| 	if err != nil { | ||||
| 		ctx.String(http.StatusBadRequest, "Failed to verify id token: %s", err.Error()) | ||||
| 		log.Error(). | ||||
| 			Err(err). | ||||
| 			Caller(). | ||||
| 			Msg("failed to verify id token") | ||||
| 		ctx.String(http.StatusBadRequest, "Failed to verify id token") | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| @ -138,34 +158,38 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { | ||||
| 	// TODO: we can use userinfo at some point to grab additional information about the user (groups membership, etc)
 | ||||
| 	// userInfo, err := oidcProvider.UserInfo(context.Background(), oauth2.StaticTokenSource(oauth2Token))
 | ||||
| 	// if err != nil {
 | ||||
| 	// 	c.String(http.StatusBadRequest, fmt.Sprintf("Failed to retrieve userinfo: %s", err))
 | ||||
| 	// 	c.String(http.StatusBadRequest, fmt.Sprintf("Failed to retrieve userinfo"))
 | ||||
| 	// 	return
 | ||||
| 	// }
 | ||||
| 
 | ||||
| 	// Extract custom claims
 | ||||
| 	var claims IDTokenClaims | ||||
| 	if err = idToken.Claims(&claims); err != nil { | ||||
| 		log.Error(). | ||||
| 			Err(err). | ||||
| 			Caller(). | ||||
| 			Msg("Failed to decode id token claims") | ||||
| 		ctx.String( | ||||
| 			http.StatusBadRequest, | ||||
| 			fmt.Sprintf("Failed to decode id token claims: %s", err), | ||||
| 			"Failed to decode id token claims", | ||||
| 		) | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// retrieve machinekey from state cache
 | ||||
| 	mKeyIf, mKeyFound := h.oidcStateCache.Get(state) | ||||
| 	machineKeyIf, machineKeyFound := h.oidcStateCache.Get(state) | ||||
| 
 | ||||
| 	if !mKeyFound { | ||||
| 	if !machineKeyFound { | ||||
| 		log.Error(). | ||||
| 			Msg("requested machine state key expired before authorisation completed") | ||||
| 		ctx.String(http.StatusBadRequest, "state has expired") | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 	mKeyStr, mKeyOK := mKeyIf.(string) | ||||
| 	machineKey, machineKeyOK := machineKeyIf.(string) | ||||
| 
 | ||||
| 	if !mKeyOK { | ||||
| 	if !machineKeyOK { | ||||
| 		log.Error().Msg("could not get machine key from cache") | ||||
| 		ctx.String( | ||||
| 			http.StatusInternalServerError, | ||||
| @ -175,8 +199,16 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO(kradalby): Currently, if it fails to find a requested expiry, non will be set
 | ||||
| 	requestedTime := time.Time{} | ||||
| 	if requestedTimeIf, found := h.requestedExpiryCache.Get(machineKey); found { | ||||
| 		if reqTime, ok := requestedTimeIf.(time.Time); ok { | ||||
| 			requestedTime = reqTime | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// retrieve machine information
 | ||||
| 	machine, err := h.GetMachineByMachineKey(mKeyStr) | ||||
| 	machine, err := h.GetMachineByMachineKey(machineKey) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msg("machine key not found in database") | ||||
| 		ctx.String( | ||||
| @ -187,6 +219,29 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if machine.isRegistered() { | ||||
| 		log.Trace(). | ||||
| 			Caller(). | ||||
| 			Str("machine", machine.Name). | ||||
| 			Msg("machine already registered, reauthenticating") | ||||
| 
 | ||||
| 		h.RefreshMachine(machine, requestedTime) | ||||
| 
 | ||||
| 		ctx.Data(http.StatusOK, "text/html; charset=utf-8", []byte(fmt.Sprintf(` | ||||
| <html> | ||||
| <body> | ||||
| <h1>headscale</h1> | ||||
| <p> | ||||
|     Reuthenticated as %s, you can now close this window. | ||||
| </p> | ||||
| </body> | ||||
| </html> | ||||
| 
 | ||||
| `, claims.Email))) | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	now := time.Now().UTC() | ||||
| 
 | ||||
| 	if namespaceName, ok := h.getNamespaceFromEmail(claims.Email); ok { | ||||
| @ -195,12 +250,14 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { | ||||
| 			log.Debug().Msg("Registering new machine after successful callback") | ||||
| 
 | ||||
| 			namespace, err := h.GetNamespace(namespaceName) | ||||
| 			if err != nil { | ||||
| 			if errors.Is(err, gorm.ErrRecordNotFound) { | ||||
| 				namespace, err = h.CreateNamespace(namespaceName) | ||||
| 
 | ||||
| 				if err != nil { | ||||
| 					log.Error(). | ||||
| 						Msgf("could not create new namespace '%s'", claims.Email) | ||||
| 						Err(err). | ||||
| 						Caller(). | ||||
| 						Msgf("could not create new namespace '%s'", namespaceName) | ||||
| 					ctx.String( | ||||
| 						http.StatusInternalServerError, | ||||
| 						"could not create new namespace", | ||||
| @ -208,10 +265,26 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { | ||||
| 
 | ||||
| 					return | ||||
| 				} | ||||
| 			} else if err != nil { | ||||
| 				log.Error(). | ||||
| 					Caller(). | ||||
| 					Err(err). | ||||
| 					Str("namespace", namespaceName). | ||||
| 					Msg("could not find or create namespace") | ||||
| 				ctx.String( | ||||
| 					http.StatusInternalServerError, | ||||
| 					"could not find or create namespace", | ||||
| 				) | ||||
| 
 | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 			ip, err := h.getAvailableIP() | ||||
| 			if err != nil { | ||||
| 				log.Error(). | ||||
| 					Caller(). | ||||
| 					Err(err). | ||||
| 					Msg("could not get an IP from the pool") | ||||
| 				ctx.String( | ||||
| 					http.StatusInternalServerError, | ||||
| 					"could not get an IP from the pool", | ||||
| @ -223,13 +296,12 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { | ||||
| 			machine.IPAddress = ip.String() | ||||
| 			machine.NamespaceID = namespace.ID | ||||
| 			machine.Registered = true | ||||
| 			machine.RegisterMethod = "oidc" | ||||
| 			machine.RegisterMethod = RegisterMethodOIDC | ||||
| 			machine.LastSuccessfulUpdate = &now | ||||
| 			machine.Expiry = &requestedTime | ||||
| 			h.db.Save(&machine) | ||||
| 		} | ||||
| 
 | ||||
| 		h.updateMachineExpiry(machine) | ||||
| 
 | ||||
| 		ctx.Data(http.StatusOK, "text/html; charset=utf-8", []byte(fmt.Sprintf(` | ||||
| <html> | ||||
| <body> | ||||
| @ -241,9 +313,12 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { | ||||
| </html> | ||||
| 
 | ||||
| `, claims.Email))) | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	log.Error(). | ||||
| 		Caller(). | ||||
| 		Str("email", claims.Email). | ||||
| 		Str("username", claims.Username). | ||||
| 		Str("machine", machine.Name). | ||||
|  | ||||
| @ -81,7 +81,7 @@ func (*Suite) TestAlreadyUsedKey(c *check.C) { | ||||
| 		Name:           "testest", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 	} | ||||
| 	app.db.Save(&machine) | ||||
| @ -106,7 +106,7 @@ func (*Suite) TestReusableBeingUsedKey(c *check.C) { | ||||
| 		Name:           "testest", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 	} | ||||
| 	app.db.Save(&machine) | ||||
| @ -144,7 +144,7 @@ func (*Suite) TestEphemeralKey(c *check.C) { | ||||
| 		Name:           "testest", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		LastSeen:       &now, | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 	} | ||||
|  | ||||
| @ -92,6 +92,12 @@ service HeadscaleService { | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     rpc ExpireMachine(ExpireMachineRequest) returns (ExpireMachineResponse) { | ||||
|         option (google.api.http) = { | ||||
|             post: "/api/v1/machine/{machine_id}/expire" | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     rpc ListMachines(ListMachinesRequest) returns (ListMachinesResponse) { | ||||
|         option (google.api.http) = { | ||||
|             get: "/api/v1/machine" | ||||
|  | ||||
| @ -64,6 +64,14 @@ message DeleteMachineRequest { | ||||
| message DeleteMachineResponse { | ||||
| } | ||||
| 
 | ||||
| message ExpireMachineRequest { | ||||
|     uint64 machine_id = 1; | ||||
| } | ||||
| 
 | ||||
| message ExpireMachineResponse { | ||||
|     Machine machine = 1; | ||||
| } | ||||
| 
 | ||||
| message ListMachinesRequest { | ||||
|     string namespace = 1; | ||||
| } | ||||
|  | ||||
| @ -36,7 +36,7 @@ func (s *Suite) TestGetRoutes(c *check.C) { | ||||
| 		Name:           "test_get_route_machine", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 		HostInfo:       datatypes.JSON(hostinfo), | ||||
| 	} | ||||
| @ -90,7 +90,7 @@ func (s *Suite) TestGetEnableRoutes(c *check.C) { | ||||
| 		Name:           "test_enable_route_machine", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 		HostInfo:       datatypes.JSON(hostinfo), | ||||
| 	} | ||||
|  | ||||
| @ -25,7 +25,7 @@ func CreateNodeNamespace( | ||||
| 		Name:           node, | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      ip, | ||||
| 		AuthKeyID:      uint(pak1.ID), | ||||
| 	} | ||||
| @ -213,7 +213,7 @@ func (s *Suite) TestComplexSharingAcrossNamespaces(c *check.C) { | ||||
| 		Name:           "test_get_shared_nodes_4", | ||||
| 		NamespaceID:    namespace1.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.4", | ||||
| 		AuthKeyID:      uint(pak4.ID), | ||||
| 	} | ||||
| @ -293,7 +293,7 @@ func (s *Suite) TestDeleteSharedMachine(c *check.C) { | ||||
| 		Name:           "test_get_shared_nodes_4", | ||||
| 		NamespaceID:    namespace1.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		IPAddress:      "100.64.0.4", | ||||
| 		AuthKeyID:      uint(pak4n1.ID), | ||||
| 	} | ||||
|  | ||||
| @ -36,7 +36,7 @@ func (s *Suite) TestGetUsedIps(c *check.C) { | ||||
| 		Name:           "testmachine", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 		IPAddress:      ip.String(), | ||||
| 	} | ||||
| @ -78,7 +78,7 @@ func (s *Suite) TestGetMultiIp(c *check.C) { | ||||
| 			Name:           "testmachine", | ||||
| 			NamespaceID:    namespace.ID, | ||||
| 			Registered:     true, | ||||
| 			RegisterMethod: "authKey", | ||||
| 			RegisterMethod: RegisterMethodAuthKey, | ||||
| 			AuthKeyID:      uint(pak.ID), | ||||
| 			IPAddress:      ip.String(), | ||||
| 		} | ||||
| @ -151,7 +151,7 @@ func (s *Suite) TestGetAvailableIpMachineWithoutIP(c *check.C) { | ||||
| 		Name:           "testmachine", | ||||
| 		NamespaceID:    namespace.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		RegisterMethod: RegisterMethodAuthKey, | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 	} | ||||
| 	app.db.Save(&machine) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user