@@ -17,6 +17,55 @@ import (
1717 "github.com/gin-gonic/gin"
1818)
1919
20+ // createCaptchaHTML writes the captcha.html file to the host filesystem under cfg.ConfigDir.
21+ // It returns the absolute path of the written file, or an error.
22+ func createCaptchaHTML (cfg * config.Config , provider , siteKey string ) error {
23+ captchaHTML := strings .ReplaceAll (captchaHTMLTemplate , "{{.SiteKey}}" , siteKey )
24+ captchaHTML = strings .ReplaceAll (captchaHTML , "{{.RedirectURL}}" , "" )
25+ captchaHTML = strings .ReplaceAll (captchaHTML , "{{.CaptchaValue}}" , "" )
26+
27+ traefikConfigDir := filepath .Join (cfg .ConfigDir , "traefik" )
28+ if _ , err := os .Stat (traefikConfigDir ); err != nil {
29+ return fmt .Errorf ("traefik configuration directory not found: %w" , err )
30+ }
31+
32+ confDir := filepath .Join (traefikConfigDir , "conf" )
33+ if err := os .MkdirAll (confDir , 0755 ); err != nil {
34+ return fmt .Errorf ("failed to create conf directory: %w" , err )
35+ }
36+
37+ captchaHTMLPath := filepath .Join (confDir , "captcha.html" )
38+ if err := os .WriteFile (captchaHTMLPath , []byte (captchaHTML ), 0644 ); err != nil {
39+ return fmt .Errorf ("failed to write captcha.html: %w" , err )
40+ }
41+
42+ logger .Info ("Captcha HTML file created" , "path" , captchaHTMLPath , "provider" , provider )
43+ return nil
44+ }
45+
46+ // restartTraefikContainer performs a clean stop+start of the Traefik container.
47+ func restartTraefikContainer (dockerClient * docker.Client , cfg * config.Config ) error {
48+ if err := dockerClient .StopContainer (cfg .TraefikContainerName ); err != nil {
49+ logger .Warn ("Failed to stop Traefik (continuing)" , "error" , err )
50+ } else {
51+ time .Sleep (1 * time .Second )
52+ }
53+ if err := dockerClient .StartContainer (cfg .TraefikContainerName ); err != nil {
54+ return fmt .Errorf ("failed to start Traefik: %w" , err )
55+ }
56+ time .Sleep (3 * time .Second )
57+ return nil
58+ }
59+
60+ // restartCrowdSecContainer restarts the CrowdSec container.
61+ func restartCrowdSecContainer (dockerClient * docker.Client , cfg * config.Config ) error {
62+ if err := dockerClient .RestartContainer (cfg .CrowdsecContainerName ); err != nil {
63+ return fmt .Errorf ("failed to restart CrowdSec: %w" , err )
64+ }
65+ time .Sleep (3 * time .Second )
66+ return nil
67+ }
68+
2069// SetupCaptcha sets up Cloudflare Turnstile captcha
2170func SetupCaptcha (dockerClient * docker.Client , cfg * config.Config ) gin.HandlerFunc {
2271 return func (c * gin.Context ) {
@@ -43,49 +92,19 @@ func SetupCaptcha(dockerClient *docker.Client, cfg *config.Config) gin.HandlerFu
4392
4493 // STEP 1: Create captcha.html file on host
4594 logger .Info ("Creating captcha.html file" )
46- captchaHTML := strings .ReplaceAll (captchaHTMLTemplate , "{{.SiteKey}}" , req .SiteKey )
47- captchaHTML = strings .ReplaceAll (captchaHTML , "{{.RedirectURL}}" , "" )
48- captchaHTML = strings .ReplaceAll (captchaHTML , "{{.CaptchaValue}}" , "" )
49-
50- // Use local path for Traefik config directory (mapped via /app/config)
51- traefikConfigDir := filepath .Join (cfg .ConfigDir , "traefik" )
52-
53- // Verify the directory exists
54- if _ , err := os .Stat (traefikConfigDir ); err != nil {
55- logger .Error ("Traefik config directory not found" , "path" , traefikConfigDir , "error" , err )
56- c .JSON (http .StatusInternalServerError , models.Response {
57- Success : false ,
58- Error : "Traefik configuration directory not found" ,
59- })
60- return
61- }
62-
63- // Create conf directory if it doesn't exist
64- confDir := filepath .Join (traefikConfigDir , "conf" )
65- if err := os .MkdirAll (confDir , 0755 ); err != nil {
66- logger .Error ("Failed to create conf directory" , "error" , err , "path" , confDir )
67- c .JSON (http .StatusInternalServerError , models.Response {
68- Success : false ,
69- Error : fmt .Sprintf ("Failed to create conf directory: %v" , err ),
70- })
71- return
72- }
73- logger .Info ("Ensured conf directory exists" , "path" , confDir )
74-
75- // Write captcha.html to conf directory
76- captchaHTMLPath := filepath .Join (confDir , "captcha.html" )
77- if err := os .WriteFile (captchaHTMLPath , []byte (captchaHTML ), 0644 ); err != nil {
78- logger .Error ("Failed to write captcha.html" , "error" , err , "path" , captchaHTMLPath )
95+ if err := createCaptchaHTML (cfg , req .Provider , req .SiteKey ); err != nil {
96+ logger .Error ("Failed to create captcha.html" , "error" , err )
7997 c .JSON (http .StatusInternalServerError , models.Response {
8098 Success : false ,
8199 Error : fmt .Sprintf ("Failed to create captcha.html: %v" , err ),
82100 })
83101 return
84102 }
85- logger . Info ( "Captcha HTML file created" , "path " , captchaHTMLPath )
103+ captchaHTMLPath := filepath . Join ( cfg . ConfigDir , "traefik" , "conf " , "captcha.html" )
86104
87105 // STEP 2: Update Traefik dynamic_config.yml
88106 logger .Info ("Updating Traefik dynamic configuration" )
107+ traefikConfigDir := filepath .Join (cfg .ConfigDir , "traefik" )
89108 if err := updateTraefikCaptchaConfig (dockerClient , cfg , req , traefikConfigDir ); err != nil {
90109 logger .Error ("Failed to update Traefik config" , "error" , err )
91110 c .JSON (http .StatusInternalServerError , models.Response {
@@ -107,33 +126,23 @@ func SetupCaptcha(dockerClient *docker.Client, cfg *config.Config) gin.HandlerFu
107126 }
108127
109128 // STEP 4: Stop and Start Traefik container (for clean reload)
110- logger .Info ("Stopping Traefik container" )
111- if err := dockerClient .StopContainer (cfg .TraefikContainerName ); err != nil {
112- logger .Warn ("Failed to stop Traefik" , "error" , err )
113- } else {
114- logger .Info ("Traefik stopped successfully" )
115- time .Sleep (1 * time .Second )
116- }
117-
118- logger .Info ("Starting Traefik container" )
119- if err := dockerClient .StartContainer (cfg .TraefikContainerName ); err != nil {
120- logger .Error ("Failed to start Traefik" , "error" , err )
129+ logger .Info ("Restarting Traefik container" )
130+ if err := restartTraefikContainer (dockerClient , cfg ); err != nil {
131+ logger .Error ("Failed to restart Traefik" , "error" , err )
121132 c .JSON (http .StatusInternalServerError , models.Response {
122133 Success : false ,
123- Error : fmt .Sprintf ("Failed to start Traefik after configuration update: %v" , err ),
134+ Error : fmt .Sprintf ("Failed to restart Traefik after configuration update: %v" , err ),
124135 })
125136 return
126137 }
127- logger .Info ("Traefik started successfully" )
128- time .Sleep (3 * time .Second )
138+ logger .Info ("Traefik restarted successfully" )
129139
130140 // STEP 5: Restart CrowdSec container
131141 logger .Info ("Restarting CrowdSec container" )
132- if err := dockerClient . RestartContainer ( cfg . CrowdsecContainerName ); err != nil {
142+ if err := restartCrowdSecContainer ( dockerClient , cfg ); err != nil {
133143 logger .Warn ("Failed to restart CrowdSec" , "error" , err )
134144 } else {
135145 logger .Info ("CrowdSec restarted successfully" )
136- time .Sleep (3 * time .Second )
137146 }
138147
139148 // STEP 6: Verify setup
@@ -147,13 +156,13 @@ func SetupCaptcha(dockerClient *docker.Client, cfg *config.Config) gin.HandlerFu
147156 Success : true ,
148157 Message : "Captcha configured successfully" ,
149158 Data : gin.H {
150- "captcha_html_created" : true ,
151- "traefik_config_updated" : true ,
159+ "captcha_html_created" : true ,
160+ "traefik_config_updated" : true ,
152161 "crowdsec_config_updated" : true ,
153- "traefik_restarted" : true ,
154- "crowdsec_restarted" : true ,
155- "verified" : verified ,
156- "captcha_html_path" : captchaHTMLPath ,
162+ "traefik_restarted" : true ,
163+ "crowdsec_restarted" : true ,
164+ "verified" : verified ,
165+ "captcha_html_path" : captchaHTMLPath ,
157166 },
158167 })
159168 }
0 commit comments