mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-31 16:11:03 +01:00 
			
		
		
		
	Add helper function to create a unique givenname
This commit is contained in:
		
							parent
							
								
									f4873d9387
								
							
						
					
					
						commit
						177c21b294
					
				
							
								
								
									
										30
									
								
								machine.go
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								machine.go
									
									
									
									
									
								
							| @ -26,6 +26,7 @@ const ( | ||||
| 	) | ||||
| 	errCouldNotConvertMachineInterface = Error("failed to convert machine interface") | ||||
| 	errHostnameTooLong                 = Error("Hostname too long") | ||||
| 	MachineGivenNameHashLength         = 8 | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| @ -813,3 +814,32 @@ func (machine *Machine) RoutesToProto() *v1.Routes { | ||||
| 		EnabledRoutes:    ipPrefixToString(enabledRoutes), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (h *Headscale) GenerateGivenName(suppliedName string) (string, error) { | ||||
| 	// If a hostname is or will be longer than 63 chars after adding the hash, | ||||
| 	// it needs to be trimmed. | ||||
| 	trimmedHostnameLength := labelHostnameLength - MachineGivenNameHashLength - 2 | ||||
| 
 | ||||
| 	normalizedHostname, err := NormalizeToFQDNRules( | ||||
| 		suppliedName, | ||||
| 		h.cfg.OIDC.StripEmaildomain, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	postfix, err := GenerateRandomStringDNSSafe(MachineGivenNameHashLength) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	// Verify that that the new unique name is shorter than the maximum allowed | ||||
| 	// DNS segment. | ||||
| 	if len(normalizedHostname) <= trimmedHostnameLength { | ||||
| 		normalizedHostname = fmt.Sprintf("%s-%s", normalizedHostname, postfix) | ||||
| 	} else { | ||||
| 		normalizedHostname = fmt.Sprintf("%s-%s", normalizedHostname[:trimmedHostnameLength], postfix) | ||||
| 	} | ||||
| 
 | ||||
| 	return normalizedHostname, nil | ||||
| } | ||||
|  | ||||
							
								
								
									
										134
									
								
								machine_test.go
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								machine_test.go
									
									
									
									
									
								
							| @ -4,6 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| @ -654,3 +655,136 @@ func Test_getFilteredByACLPeers(t *testing.T) { | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestHeadscale_GenerateGivenName(t *testing.T) { | ||||
| 	type args struct { | ||||
| 		suppliedName string | ||||
| 	} | ||||
| 	tests := []struct { | ||||
| 		name    string | ||||
| 		h       *Headscale | ||||
| 		args    args | ||||
| 		want    string | ||||
| 		wantErr bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "simple machine name generation", | ||||
| 			h: &Headscale{ | ||||
| 				cfg: Config{ | ||||
| 					OIDC: OIDCConfig{ | ||||
| 						StripEmaildomain: true, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			args: args{ | ||||
| 				suppliedName: "testmachine", | ||||
| 			}, | ||||
| 			want:    "testmachine", | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "machine name with 53 chars", | ||||
| 			h: &Headscale{ | ||||
| 				cfg: Config{ | ||||
| 					OIDC: OIDCConfig{ | ||||
| 						StripEmaildomain: true, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			args: args{ | ||||
| 				suppliedName: "testmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaachine", | ||||
| 			}, | ||||
| 			want:    "testmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaachine", | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "machine name with 60 chars", | ||||
| 			h: &Headscale{ | ||||
| 				cfg: Config{ | ||||
| 					OIDC: OIDCConfig{ | ||||
| 						StripEmaildomain: true, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			args: args{ | ||||
| 				suppliedName: "testmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaachine1234567", | ||||
| 			}, | ||||
| 			want:    "testmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaachine", | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "machine name with 63 chars", | ||||
| 			h: &Headscale{ | ||||
| 				cfg: Config{ | ||||
| 					OIDC: OIDCConfig{ | ||||
| 						StripEmaildomain: true, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			args: args{ | ||||
| 				suppliedName: "testmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaachine1234567890", | ||||
| 			}, | ||||
| 			want:    "testmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "machine name with 64 chars", | ||||
| 			h: &Headscale{ | ||||
| 				cfg: Config{ | ||||
| 					OIDC: OIDCConfig{ | ||||
| 						StripEmaildomain: true, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			args: args{ | ||||
| 				suppliedName: "testmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaachine1234567891", | ||||
| 			}, | ||||
| 			want:    "testmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "machine name with 73 chars", | ||||
| 			h: &Headscale{ | ||||
| 				cfg: Config{ | ||||
| 					OIDC: OIDCConfig{ | ||||
| 						StripEmaildomain: true, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			args: args{ | ||||
| 				suppliedName: "testmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaachine12345678901234567890", | ||||
| 			}, | ||||
| 			want:    "", | ||||
| 			wantErr: true, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 			got, err := tt.h.GenerateGivenName(tt.args.suppliedName) | ||||
| 			if (err != nil) != tt.wantErr { | ||||
| 				t.Errorf( | ||||
| 					"Headscale.GenerateGivenName() error = %v, wantErr %v", | ||||
| 					err, | ||||
| 					tt.wantErr, | ||||
| 				) | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 			if tt.want != "" && strings.Contains(tt.want, got) { | ||||
| 				t.Errorf( | ||||
| 					"Headscale.GenerateGivenName() = %v, is not a substring of %v", | ||||
| 					tt.want, | ||||
| 					got, | ||||
| 				) | ||||
| 			} | ||||
| 
 | ||||
| 			if len(got) > labelHostnameLength { | ||||
| 				t.Errorf( | ||||
| 					"Headscale.GenerateGivenName() = %v is larger than allowed DNS segment %d", | ||||
| 					got, | ||||
| 					labelHostnameLength, | ||||
| 				) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
							
								
								
									
										13
									
								
								utils.go
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								utils.go
									
									
									
									
									
								
							| @ -317,3 +317,16 @@ func GenerateRandomStringURLSafe(n int) (string, error) { | ||||
| 
 | ||||
| 	return base64.RawURLEncoding.EncodeToString(b), err | ||||
| } | ||||
| 
 | ||||
| // GenerateRandomStringDNSSafe returns a DNS-safe | ||||
| // securely generated random string. | ||||
| // It will return an error if the system's secure random | ||||
| // number generator fails to function correctly, in which | ||||
| // case the caller should not continue. | ||||
| func GenerateRandomStringDNSSafe(n int) (string, error) { | ||||
| 	str, err := GenerateRandomStringURLSafe(n) | ||||
| 
 | ||||
| 	str = strings.ReplaceAll(str, "_", "-") | ||||
| 
 | ||||
| 	return str[:n], err | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user