package wireguard import ( "fmt" "os" "path/filepath" ) type ClientProfile struct { OS string Architecture string ConfigContent string ConfigPath string } func GenerateClientProfiles(serverConfig *ServerConfig, serverIP string, count int) ([]ClientProfile, error) { var profiles []ClientProfile platforms := []struct { OS string Architecture string }{ {"linux", "amd64"}, {"linux", "arm64"}, {"darwin", "amd64"}, {"darwin", "arm64"}, {"windows", "amd64"}, } numProfiles := count if numProfiles <= 0 { numProfiles = len(platforms) } for i := 0; i < numProfiles; i++ { platform := platforms[i%len(platforms)] clientPrivateKey, clientPublicKey, err := GenerateClientKeyPair() if err != nil { return nil, fmt.Errorf("failed to generate client key pair: %w", err) } clientAddress := fmt.Sprintf("10.0.0.%d/24", i+2) clientConfig := GenerateClientConfig( serverIP, serverConfig.Port, serverConfig.PublicKey, clientPrivateKey, clientPublicKey, clientAddress, "0.0.0.0/0", ) profile := ClientProfile{ OS: platform.OS, Architecture: platform.Architecture, ConfigContent: clientConfig.ToConfigFile(), } profiles = append(profiles, profile) } return profiles, nil } func SaveClientProfile(profile ClientProfile, outputDir string) (string, error) { if err := os.MkdirAll(outputDir, 0755); err != nil { return "", fmt.Errorf("failed to create output directory: %w", err) } var filename string switch profile.OS { case "darwin": filename = fmt.Sprintf("wg-%s-%s.conf", profile.OS, profile.Architecture) case "linux": filename = fmt.Sprintf("wg-%s-%s.conf", profile.OS, profile.Architecture) case "windows": filename = fmt.Sprintf("wg-%s-%s.conf", profile.OS, profile.Architecture) default: filename = fmt.Sprintf("wg-%s-%s.conf", profile.OS, profile.Architecture) } configPath := filepath.Join(outputDir, filename) if err := os.WriteFile(configPath, []byte(profile.ConfigContent), 0600); err != nil { return "", fmt.Errorf("failed to write client config: %w", err) } return configPath, nil }