You've already forked docker-ldap-change-password-web-ui
							
							Add captcha support
This commit is contained in:
		| @@ -24,3 +24,6 @@ | |||||||
| [[constraint]] | [[constraint]] | ||||||
|   name = "gopkg.in/ldap.v2" |   name = "gopkg.in/ldap.v2" | ||||||
|   version = "2.5.1" |   version = "2.5.1" | ||||||
|  | [[constraint]] | ||||||
|  |   name = "github.com/dchest/captcha" | ||||||
|  |   branch = "master" | ||||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | |||||||
| REPO=npenkov/docker-ldap-passwd-webui | REPO=npenkov/docker-ldap-passwd-webui | ||||||
| VER=1.0 | VER=1.1 | ||||||
|  |  | ||||||
| .PHONY: all build push | .PHONY: all build push | ||||||
|  |  | ||||||
|   | |||||||
| @@ -55,4 +55,5 @@ make | |||||||
| ## Credits | ## Credits | ||||||
|  |  | ||||||
|  * [Web UI for changing LDAP password - python](https://github.com/jirutka/ldap-passwd-webui) |  * [Web UI for changing LDAP password - python](https://github.com/jirutka/ldap-passwd-webui) | ||||||
|  * [Gitea](https://github.com/go-gitea/gitea) |  * [Gitea](https://github.com/go-gitea/gitea) | ||||||
|  |  * [dchest/captcha](https://github.com/dchest/captcha) | ||||||
							
								
								
									
										32
									
								
								app/web.go
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								app/web.go
									
									
									
									
									
								
							| @@ -8,6 +8,8 @@ import ( | |||||||
|  |  | ||||||
| 	"html/template" | 	"html/template" | ||||||
|  |  | ||||||
|  | 	"github.com/dchest/captcha" | ||||||
|  |  | ||||||
| 	"regexp" | 	"regexp" | ||||||
|  |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| @@ -46,9 +48,10 @@ func (h *RegexpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |||||||
| } | } | ||||||
|  |  | ||||||
| type pageData struct { | type pageData struct { | ||||||
| 	Title    string | 	Title     string | ||||||
| 	Username string | 	Username  string | ||||||
| 	Alerts   map[string]string | 	Alerts    map[string]string | ||||||
|  | 	CaptchaId string | ||||||
| } | } | ||||||
|  |  | ||||||
| // ServeAssets : Serves the static assets | // ServeAssets : Serves the static assets | ||||||
| @@ -58,7 +61,7 @@ func ServeAssets(w http.ResponseWriter, req *http.Request) { | |||||||
|  |  | ||||||
| // ServeIndex : Serves index page on GET request | // ServeIndex : Serves index page on GET request | ||||||
| func ServeIndex(w http.ResponseWriter, req *http.Request) { | func ServeIndex(w http.ResponseWriter, req *http.Request) { | ||||||
| 	p := &pageData{Title: getTitle()} | 	p := &pageData{Title: getTitle(), CaptchaId: captcha.New()} | ||||||
| 	t, e := template.ParseFiles(path.Join("templates", "index.html")) | 	t, e := template.ParseFiles(path.Join("templates", "index.html")) | ||||||
| 	if e != nil { | 	if e != nil { | ||||||
| 		log.Printf("Error parsing file %v\n", e) | 		log.Printf("Error parsing file %v\n", e) | ||||||
| @@ -75,27 +78,36 @@ func ChangePassword(w http.ResponseWriter, req *http.Request) { | |||||||
| 	oldPassword := req.Form["old-password"] | 	oldPassword := req.Form["old-password"] | ||||||
| 	newPassword := req.Form["new-password"] | 	newPassword := req.Form["new-password"] | ||||||
| 	confirmPassword := req.Form["confirm-password"] | 	confirmPassword := req.Form["confirm-password"] | ||||||
|  | 	captchaID := req.Form["captchaId"] | ||||||
|  | 	captchaSolution := req.Form["captchaSolution"] | ||||||
|  |  | ||||||
| 	alerts := map[string]string{} | 	alerts := map[string]string{} | ||||||
|  |  | ||||||
| 	if len(username) < 1 || username[0] == "" { | 	if len(username) < 1 || username[0] == "" { | ||||||
| 		alerts["error"] = "Username not specified.<br/>" | 		alerts["error"] = "Username not specified." | ||||||
| 	} else { | 	} else { | ||||||
| 		un = username[0] | 		un = username[0] | ||||||
| 	} | 	} | ||||||
| 	if len(oldPassword) < 1 || oldPassword[0] == "" { | 	if len(oldPassword) < 1 || oldPassword[0] == "" { | ||||||
| 		alerts["error"] = alerts["error"] + "Old password not specified.<br/>" | 		alerts["error"] = "Old password not specified." | ||||||
| 	} | 	} | ||||||
| 	if len(newPassword) < 1 || newPassword[0] == "" { | 	if len(newPassword) < 1 || newPassword[0] == "" { | ||||||
| 		alerts["error"] = alerts["error"] + "New password not specified.<br/>" | 		alerts["error"] = "New password not specified." | ||||||
| 	} | 	} | ||||||
| 	if len(confirmPassword) < 1 || confirmPassword[0] == "" { | 	if len(confirmPassword) < 1 || confirmPassword[0] == "" { | ||||||
| 		alerts["error"] = alerts["error"] + "Confirmation password not specified.<br/>" | 		alerts["error"] = "Confirmation password not specified." | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if len(confirmPassword) >= 1 && len(newPassword) >= 1 && strings.Compare(newPassword[0], confirmPassword[0]) != 0 { | 	if len(confirmPassword) >= 1 && len(newPassword) >= 1 && strings.Compare(newPassword[0], confirmPassword[0]) != 0 { | ||||||
| 		alerts["error"] = alerts["error"] + "New and confirmation passwords does not match.<br/>" | 		alerts["error"] = "New and confirmation passwords does not match. " | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if len(captchaID) < 1 || captchaID[0] == "" || | ||||||
|  | 		len(captchaSolution) < 1 || captchaSolution[0] == "" || | ||||||
|  | 		!captcha.VerifyString(captchaID[0], captchaSolution[0]) { | ||||||
|  | 		alerts["error"] = "Wrong captcha." | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if len(alerts) == 0 { | 	if len(alerts) == 0 { | ||||||
| 		client := NewLDAPClient() | 		client := NewLDAPClient() | ||||||
| 		if err := client.ModifyPassword(un, oldPassword[0], newPassword[0]); err != nil { | 		if err := client.ModifyPassword(un, oldPassword[0], newPassword[0]); err != nil { | ||||||
| @@ -105,7 +117,7 @@ func ChangePassword(w http.ResponseWriter, req *http.Request) { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	p := &pageData{Title: getTitle(), Alerts: alerts, Username: un} | 	p := &pageData{Title: getTitle(), Alerts: alerts, Username: un, CaptchaId: captcha.New()} | ||||||
|  |  | ||||||
| 	t, e := template.ParseFiles(path.Join("templates", "index.html")) | 	t, e := template.ParseFiles(path.Join("templates", "index.html")) | ||||||
| 	if e != nil { | 	if e != nil { | ||||||
|   | |||||||
							
								
								
									
										9
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								main.go
									
									
									
									
									
								
							| @@ -2,8 +2,10 @@ package main | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"github.com/npenkov/ldap-passwd-webui/app" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  |  | ||||||
|  | 	"github.com/dchest/captcha" | ||||||
|  | 	"github.com/npenkov/ldap-passwd-webui/app" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func main() { | func main() { | ||||||
| @@ -12,7 +14,8 @@ func main() { | |||||||
| 	reHandler.HandleFunc(".*.[js|css|png|eof|svg|ttf|woff]", "GET", app.ServeAssets) | 	reHandler.HandleFunc(".*.[js|css|png|eof|svg|ttf|woff]", "GET", app.ServeAssets) | ||||||
| 	reHandler.HandleFunc("/", "GET", app.ServeIndex) | 	reHandler.HandleFunc("/", "GET", app.ServeIndex) | ||||||
| 	reHandler.HandleFunc("/", "POST", app.ChangePassword) | 	reHandler.HandleFunc("/", "POST", app.ChangePassword) | ||||||
|  | 	http.Handle("/captcha/", captcha.Server(captcha.StdWidth, captcha.StdHeight)) | ||||||
|  | 	http.Handle("/", reHandler) | ||||||
| 	fmt.Println("Starting server on port 8080") | 	fmt.Println("Starting server on port 8080") | ||||||
| 	http.ListenAndServe(":8080", reHandler) | 	http.ListenAndServe(":8080", nil) | ||||||
| } | } | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 109 KiB | 
| @@ -12,6 +12,36 @@ | |||||||
|   </head> |   </head> | ||||||
|  |  | ||||||
|   <body> |   <body> | ||||||
|  |     <script> | ||||||
|  |       function setSrcQuery(e, q) { | ||||||
|  |         var src = e.src; | ||||||
|  |         var p = src.indexOf('?'); | ||||||
|  |         if (p >= 0) { | ||||||
|  |           src = src.substr(0, p); | ||||||
|  |         } | ||||||
|  |         e.src = src + "?" + q | ||||||
|  |       } | ||||||
|  |       function playAudio() { | ||||||
|  |         var le = document.getElementById("lang"); | ||||||
|  |         var lang = le.options[le.selectedIndex].value; | ||||||
|  |         var e = document.getElementById('audio') | ||||||
|  |         setSrcQuery(e, "lang=" + lang) | ||||||
|  |         e.style.display = 'block'; | ||||||
|  |         e.autoplay = 'true'; | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  |       function changeLang() { | ||||||
|  |         var e = document.getElementById('audio') | ||||||
|  |         if (e.style.display == 'block') { | ||||||
|  |           playAudio(); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       function reload() { | ||||||
|  |         setSrcQuery(document.getElementById('image'), "reload=" + (new Date()).getTime()); | ||||||
|  |         setSrcQuery(document.getElementById('audio'), (new Date()).getTime()); | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  |     </script> | ||||||
|     <main> |     <main> | ||||||
|       <h1>{{.Title}}</h1> |       <h1>{{.Title}}</h1> | ||||||
|  |  | ||||||
| @@ -30,6 +60,14 @@ | |||||||
|         <input id="confirm-password" name="confirm-password" type="password" |         <input id="confirm-password" name="confirm-password" type="password" | ||||||
|             pattern=".{8,}" x-moz-errormessage="Password must be at least 8 characters long." required> |             pattern=".{8,}" x-moz-errormessage="Password must be at least 8 characters long." required> | ||||||
|  |  | ||||||
|  |         <p>Type the numbers you see in the picture below:</p> | ||||||
|  |         <p> | ||||||
|  |           <img id=image src="/captcha/{{.CaptchaId}}.png" alt="Captcha image"> | ||||||
|  |         </p> | ||||||
|  |         <a href="#" onclick="reload()">Reload</a> | ||||||
|  |         <input type=hidden name=captchaId value="{{.CaptchaId}}"> | ||||||
|  |         <br> | ||||||
|  |         <input id="captchaSolution" name="captchaSolution" type="text" required> | ||||||
|         <button type="submit">Update password</button> |         <button type="submit">Update password</button> | ||||||
|       </form> |       </form> | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user