package dashboard import ( "fmt" "html/template" "os" "path/filepath" "strings" ) // WebTemplateManager manages HTML templates for web honeypot services type WebTemplateManager struct { templateDir string } // NewWebTemplateManager creates a new web template manager func NewWebTemplateManager(templateDir string) *WebTemplateManager { // Ensure template directory exists if err := os.MkdirAll(templateDir, 0755); err != nil { // Log error but continue - directory will be created when first template is saved } return &WebTemplateManager{ templateDir: templateDir, } } // GetTemplate retrieves a template by name func (wtm *WebTemplateManager) GetTemplate(templateName string) (string, error) { if !wtm.isValidTemplateName(templateName) { return "", fmt.Errorf("invalid template name: %s", templateName) } templatePath := filepath.Join(wtm.templateDir, templateName) content, err := os.ReadFile(templatePath) if err != nil { return "", fmt.Errorf("failed to read template %s: %w", templateName, err) } return string(content), nil } // SaveTemplate saves a template with the given name and content func (wtm *WebTemplateManager) SaveTemplate(templateName, content string) error { if !wtm.isValidTemplateName(templateName) { return fmt.Errorf("invalid template name: %s", templateName) } // Ensure template directory exists if err := os.MkdirAll(wtm.templateDir, 0755); err != nil { return fmt.Errorf("failed to create template directory: %w", err) } templatePath := filepath.Join(wtm.templateDir, templateName) if err := os.WriteFile(templatePath, []byte(content), 0644); err != nil { return fmt.Errorf("failed to save template %s: %w", templateName, err) } return nil } // ListTemplates returns a list of available template names func (wtm *WebTemplateManager) ListTemplates() ([]string, error) { if _, err := os.Stat(wtm.templateDir); os.IsNotExist(err) { return []string{}, nil } entries, err := os.ReadDir(wtm.templateDir) if err != nil { return nil, fmt.Errorf("failed to read template directory: %w", err) } var templates []string for _, entry := range entries { if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".html") { templates = append(templates, entry.Name()) } } return templates, nil } // DeleteTemplate removes a template func (wtm *WebTemplateManager) DeleteTemplate(templateName string) error { if !wtm.isValidTemplateName(templateName) { return fmt.Errorf("invalid template name: %s", templateName) } templatePath := filepath.Join(wtm.templateDir, templateName) if err := os.Remove(templatePath); err != nil { return fmt.Errorf("failed to delete template %s: %w", templateName, err) } return nil } // ValidateTemplate validates template content for basic HTML structure func (wtm *WebTemplateManager) ValidateTemplate(content string) error { // Basic validation - check if it's valid HTML template _, err := template.New("test").Parse(content) if err != nil { return fmt.Errorf("invalid template syntax: %w", err) } // Additional validation - ensure it contains basic HTML structure content = strings.ToLower(content) if !strings.Contains(content, " tag") } if !strings.Contains(content, " tag") } return nil } // CreateDefaultTemplate creates a default template with the given name func (wtm *WebTemplateManager) CreateDefaultTemplate(templateName string) error { if !wtm.isValidTemplateName(templateName) { return fmt.Errorf("invalid template name: %s", templateName) } defaultContent := ` Login - {{ .ServiceName }} ` return wtm.SaveTemplate(templateName, defaultContent) } // isValidTemplateName validates template name for security func (wtm *WebTemplateManager) isValidTemplateName(name string) bool { name = strings.TrimSpace(name) // Must end with .html if !strings.HasSuffix(strings.ToLower(name), ".html") { return false } // Disallow path separators and traversal, but allow single dots if strings.Contains(name, "/") || strings.Contains(name, "\\") || strings.Contains(name, "..") { return false } // Must not be empty or too long if len(name) == 0 || len(name) > 100 { return false } // Must be a valid filename if name != filepath.Base(name) { return false } return true }