OTP support
This commit is contained in:
		
							parent
							
								
									07b37e9bc4
								
							
						
					
					
						commit
						e9f6a04864
					
				| @ -7,16 +7,16 @@ type DailymotionVPN struct { | |||||||
| 
 | 
 | ||||||
| func (s *DailymotionVPN) ServerList() (error, *map[string]string) { | func (s *DailymotionVPN) ServerList() (error, *map[string]string) { | ||||||
| 	VPNNames := map[string]string{ | 	VPNNames := map[string]string{ | ||||||
| 		"Paris 1":          "gate-01.dc3.dailmotion.com", | 		"Paris 1":          "gate-01.dc3.dailymotion.com", | ||||||
| 		"New-York 1":       "gate-01.nyc.dailmotion.com", | 		"New-York 1":       "gate-01.nyc.dailymotion.com", | ||||||
| 		"Silicon Valley 1": "gate-01.sv6.dailmotion.com", | 		"Silicon Valley 1": "gate-01.sv6.dailymotion.com", | ||||||
| 		"Singapore 1":      "gate-01.sg1.dailmotion.com", | 		"Singapore 1":      "gate-01.sg1.dailymotion.com", | ||||||
| 		"Tokyo 1":          "gate-01.ty4.dailmotion.com", | 		"Tokyo 1":          "gate-01.ty4.dailymotion.com", | ||||||
| 		"Paris 2":          "gate-01.dc3.dailmotion.com", | 		"Paris 2":          "gate-02.dc3.dailymotion.com", | ||||||
| 		"New-York 2":       "gate-01.nyc.dailmotion.com", | 		"New-York 2":       "gate-02.nyc.dailymotion.com", | ||||||
| 		"Silicon Valley 2": "gate-01.sv6.dailmotion.com", | 		"Silicon Valley 2": "gate-02.sv6.dailymotion.com", | ||||||
| 		"Singapore 2":      "gate-01.sg1.dailmotion.com", | 		"Singapore 2":      "gate-02.sg1.dailymotion.com", | ||||||
| 		"Tokyo 2":          "gate-01.ty4.dailmotion.com", | 		"Tokyo 2":          "gate-02.ty4.dailymotion.com", | ||||||
| 		"default":          "vpn.dailymotion.com", | 		"default":          "vpn.dailymotion.com", | ||||||
| 	} | 	} | ||||||
| 	return nil, &VPNNames | 	return nil, &VPNNames | ||||||
|  | |||||||
							
								
								
									
										3
									
								
								httpd.go
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								httpd.go
									
									
									
									
									
								
							| @ -22,6 +22,7 @@ type jsonInputParams struct { | |||||||
| 	Session int    `json:"session"` | 	Session int    `json:"session"` | ||||||
| 	User    string `json:"user"` | 	User    string `json:"user"` | ||||||
| 	Pass    string `json:"password"` | 	Pass    string `json:"password"` | ||||||
|  | 	OTP     string `json:"otp"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type HttpServer struct { | type HttpServer struct { | ||||||
| @ -84,7 +85,7 @@ func (h *HttpServer) ajaxHandler(w http.ResponseWriter, r *http.Request) { | |||||||
| 		err = h.ovpn.SetRemote(req.Params.Server, req.Params.Session) | 		err = h.ovpn.SetRemote(req.Params.Server, req.Params.Session) | ||||||
| 		jsonStr = []byte("{\"status\": \"ok\"}") | 		jsonStr = []byte("{\"status\": \"ok\"}") | ||||||
| 	case "auth-user-pass": | 	case "auth-user-pass": | ||||||
| 		err = h.ovpn.AuthUserPass(req.Params.Session, req.Params.User, req.Params.Pass) | 		err = h.ovpn.AuthUserPass(req.Params.Session, req.Params.User, req.Params.Pass, req.Params.OTP) | ||||||
| 		jsonStr = []byte("{\"status\": \"ok\"}") | 		jsonStr = []byte("{\"status\": \"ok\"}") | ||||||
| 	case "get-sessions": | 	case "get-sessions": | ||||||
| 		jsonStr, err = json.Marshal(h.ovpn) | 		jsonStr, err = json.Marshal(h.ovpn) | ||||||
|  | |||||||
							
								
								
									
										97
									
								
								openvpn.go
									
									
									
									
									
								
							
							
						
						
									
										97
									
								
								openvpn.go
									
									
									
									
									
								
							| @ -2,6 +2,7 @@ package main | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bufio" | 	"bufio" | ||||||
|  | 	"encoding/base64" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net" | 	"net" | ||||||
| @ -14,6 +15,7 @@ import ( | |||||||
| type OpenVpnPassword struct { | type OpenVpnPassword struct { | ||||||
| 	User string | 	User string | ||||||
| 	Pass string | 	Pass string | ||||||
|  | 	OTP  string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type OpenVpnSrv struct { | type OpenVpnSrv struct { | ||||||
| @ -21,6 +23,7 @@ type OpenVpnSrv struct { | |||||||
| 	Status     string `json:"status"` | 	Status     string `json:"status"` | ||||||
| 	Provider   string `json:"provider"` | 	Provider   string `json:"provider"` | ||||||
| 	Identifier string `json:"identifier"` | 	Identifier string `json:"identifier"` | ||||||
|  | 	Message    string `json:"message"` | ||||||
| 	chanHold   chan bool | 	chanHold   chan bool | ||||||
| 	chanPass   chan OpenVpnPassword | 	chanPass   chan OpenVpnPassword | ||||||
| 	m          sync.RWMutex | 	m          sync.RWMutex | ||||||
| @ -28,6 +31,7 @@ type OpenVpnSrv struct { | |||||||
| 	buf        *bufio.ReadWriter | 	buf        *bufio.ReadWriter | ||||||
| 	mgt        *OpenVpnMgt | 	mgt        *OpenVpnMgt | ||||||
| 	hold       bool | 	hold       bool | ||||||
|  | 	authWait   bool | ||||||
| 	authCache  *OpenVpnPassword | 	authCache  *OpenVpnPassword | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -47,12 +51,21 @@ func NewOpenVpnSrv(conn net.Conn, mgt *OpenVpnMgt) *OpenVpnSrv { | |||||||
| 		ret:        make(chan []string), | 		ret:        make(chan []string), | ||||||
| 		mgt:        mgt, | 		mgt:        mgt, | ||||||
| 		hold:       false, | 		hold:       false, | ||||||
|  | 		authWait:   false, | ||||||
| 		Status:     "Starting", | 		Status:     "Starting", | ||||||
| 		Identifier: "Unknown", | 		Identifier: "Unknown", | ||||||
| 		Provider:   "Unknown", | 		Provider:   "Unknown", | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (v *OpenVpnSrv) B64OTP() string { | ||||||
|  | 	return base64.StdEncoding.EncodeToString([]byte(v.authCache.OTP)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (v *OpenVpnSrv) B64Pass() string { | ||||||
|  | 	return base64.StdEncoding.EncodeToString([]byte(v.authCache.Pass)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // send a command to the server. Set the channel to receive the response | // send a command to the server. Set the channel to receive the response | ||||||
| func (v *OpenVpnSrv) sendCommand(msg []string) (error, []string) { | func (v *OpenVpnSrv) sendCommand(msg []string) (error, []string) { | ||||||
| 	v.Lock() | 	v.Lock() | ||||||
| @ -149,7 +162,9 @@ func (v *OpenVpnSrv) GetLine() (string, error) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (v *OpenVpnSrv) ValidRemote(server, port, proto string) { | func (v *OpenVpnSrv) ValidRemote(server, port, proto string) { | ||||||
| 	v.Status = "Connected" | 	if !v.authWait { | ||||||
|  | 		v.Status = "Connected" | ||||||
|  | 	} | ||||||
| 	if v.Remote != "" { | 	if v.Remote != "" { | ||||||
| 		v.sendCommand([]string{fmt.Sprintf("remote MOD %s %s %s", v.Remote, port, proto)}) | 		v.sendCommand([]string{fmt.Sprintf("remote MOD %s %s %s", v.Remote, port, proto)}) | ||||||
| 		return | 		return | ||||||
| @ -182,12 +197,31 @@ func (v *OpenVpnSrv) SetRemote(server string) error { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (v *OpenVpnSrv) NeedPassword(line string) { | func (v *OpenVpnSrv) NeedPassword(line string) { | ||||||
|  | 	if v.authWait { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	v.authWait = true | ||||||
| 	v.mgt.Debug(line) | 	v.mgt.Debug(line) | ||||||
| 	v.Status = "Need Password" | 	v.Status = "Need Password" | ||||||
| 	switch line { | 	v.Message = "" | ||||||
| 	case ">PASSWORD:Need 'Auth' username/password": | 	backup := v.authCache | ||||||
|  | 
 | ||||||
|  | 	OtpPassRegexp := rcache.Get("^>PASSWORD:Need 'Auth' username/password SC:([01]),(.*)$") | ||||||
|  | 	OtpPassMatch := OtpPassRegexp.FindStringSubmatch(line) | ||||||
|  | 
 | ||||||
|  | 	CRV1Regexep := rcache.Get(">PASSWORD:Verification Failed: 'Auth' \\['CRV1:([R,E]*):(.*):(.*):(.*)'\\]") | ||||||
|  | 	CRV1Match := CRV1Regexep.FindStringSubmatch(line) | ||||||
|  | 	switch { | ||||||
|  | 	case len(CRV1Match) > 1: | ||||||
|  | 		v.Status = "Need OTP" | ||||||
|  | 		v.Message = CRV1Match[4] | ||||||
|  | 		v.authCache = nil | ||||||
|  | 	case len(OtpPassMatch) > 1: | ||||||
|  | 		v.Status = "Need Password and OTP" | ||||||
|  | 		v.Message = OtpPassMatch[2] | ||||||
|  | 	case line == ">PASSWORD:Need 'Auth' username/password": | ||||||
| 		v.Status = "Need Password" | 		v.Status = "Need Password" | ||||||
| 	case ">PASSWORD:Verification Failed: 'Auth'": | 	case line == ">PASSWORD:Verification Failed: 'Auth'": | ||||||
| 		v.authCache = nil | 		v.authCache = nil | ||||||
| 		v.Status = "Auth Failed" | 		v.Status = "Auth Failed" | ||||||
| 		return | 		return | ||||||
| @ -196,20 +230,55 @@ func (v *OpenVpnSrv) NeedPassword(line string) { | |||||||
| 		ident := <-v.chanPass | 		ident := <-v.chanPass | ||||||
| 		v.authCache = &ident | 		v.authCache = &ident | ||||||
| 	} | 	} | ||||||
| 	switch line { | 	var cmd []string | ||||||
| 	case ">PASSWORD:Need 'Auth' username/password": | 	switch { | ||||||
| 		v.sendCommand([]string{fmt.Sprintf("username \"Auth\" %s", v.authCache.User)}) | 	case len(CRV1Match) > 1: | ||||||
| 		v.sendCommand([]string{fmt.Sprintf("password \"Auth\" %s", v.authCache.Pass)}) | 		cmd = []string{ | ||||||
|  | 			fmt.Sprintf("username \"Auth\" %s", B64decode(CRV1Match[3])), | ||||||
|  | 			fmt.Sprintf("password \"Auth\" CRV1::%s::%s", CRV1Match[2], v.authCache.OTP), | ||||||
|  | 		} | ||||||
|  | 		// restore auth backup | ||||||
|  | 		v.authCache = backup | ||||||
|  | 
 | ||||||
|  | 	case len(OtpPassMatch) > 1: | ||||||
|  | 		cmd = []string{ | ||||||
|  | 			fmt.Sprintf("username \"Auth\" %s", v.authCache.User), | ||||||
|  | 			fmt.Sprintf("password \"Auth\" SCRV1:%s:%s", v.B64Pass(), v.B64OTP()), | ||||||
|  | 		} | ||||||
|  | 	case line == ">PASSWORD:Need 'Auth' username/password": | ||||||
|  | 		cmd = []string{ | ||||||
|  | 			fmt.Sprintf("username \"Auth\" %s", v.authCache.User), | ||||||
|  | 			fmt.Sprintf("password \"Auth\" %s", v.authCache.Pass), | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  | 	for _, c := range cmd { | ||||||
|  | 		v.sendCommand([]string{c}) | ||||||
|  | 	} | ||||||
|  | 	v.authWait = false | ||||||
|  | 	v.Message = "" | ||||||
|  | 	v.Status = "Connected" | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (v *OpenVpnSrv) AuthUserPass(user, pass string) { | func (v *OpenVpnSrv) AuthUserPass(user, pass, otp string) { | ||||||
| 	auth := OpenVpnPassword{user, pass} | 	auth := OpenVpnPassword{user, pass, otp} | ||||||
| 	v.authCache = &auth | 	if v.authCache == nil { | ||||||
| 	if v.Status == "Need Password" { | 		v.authCache = &auth | ||||||
| 		v.Status = "Authenticate" |  | ||||||
| 		v.chanPass <- auth |  | ||||||
| 	} | 	} | ||||||
|  | 	switch v.Status { | ||||||
|  | 	case "Need Password and OTP": | ||||||
|  | 		v.authCache.User = user | ||||||
|  | 		v.authCache.Pass = pass | ||||||
|  | 		v.authCache.OTP = otp | ||||||
|  | 	case "Need OTP": | ||||||
|  | 		v.authCache.OTP = otp | ||||||
|  | 	case "Need Password": | ||||||
|  | 		v.authCache.User = user | ||||||
|  | 		v.authCache.Pass = pass | ||||||
|  | 	default: | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	v.chanPass <- auth | ||||||
|  | 	v.Status = "Check Password" | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (v *OpenVpnSrv) waitForRelase() { | func (v *OpenVpnSrv) waitForRelase() { | ||||||
|  | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										9
									
								
								utils.go
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								utils.go
									
									
									
									
									
								
							| @ -1,6 +1,7 @@ | |||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"encoding/base64" | ||||||
| 	"math/big" | 	"math/big" | ||||||
| 	"net" | 	"net" | ||||||
| 	"sort" | 	"sort" | ||||||
| @ -8,6 +9,14 @@ import ( | |||||||
| 	"github.com/pyke369/golang-support/uconfig" | 	"github.com/pyke369/golang-support/uconfig" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | func B64decode(s string) string { | ||||||
|  | 	data, err := base64.StdEncoding.DecodeString(s) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	return string(data) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // check if there is a member of "search" in "list". sort list to be more | // check if there is a member of "search" in "list". sort list to be more | ||||||
| // efficiant. adapt with sorting "search" too | // efficiant. adapt with sorting "search" too | ||||||
| func inArray(search, list []string) bool { | func inArray(search, list []string) bool { | ||||||
|  | |||||||
| @ -102,13 +102,13 @@ func (s *OpenVpnMgt) Restart(pid int) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (s *OpenVpnMgt) AuthUserPass(pid int, user, pass string) error { | func (s *OpenVpnMgt) AuthUserPass(pid int, user, pass, otp string) error { | ||||||
| 	// check if the session is valid | 	// check if the session is valid | ||||||
| 	err, session := s.GetSession(pid) | 	err, session := s.GetSession(pid) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	session.AuthUserPass(user, pass) | 	session.AuthUserPass(user, pass, otp) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -142,7 +142,9 @@ select.interface { | |||||||
|     function auth(pid) { |     function auth(pid) { | ||||||
|         ajax({action: "auth-user-pass", params:{session: pid, |         ajax({action: "auth-user-pass", params:{session: pid, | ||||||
|             user:$('#auth_'+pid+'>input.user').val(),  |             user:$('#auth_'+pid+'>input.user').val(),  | ||||||
|             password:$('#auth_'+pid+'>input.pass').val()}}); |             password:$('#auth_'+pid+'>input.pass').val(), | ||||||
|  |             otp:$('#auth_'+pid+'>input.otp').val() | ||||||
|  |         }}); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function refresh(data) { |     function refresh(data) { | ||||||
| @ -201,11 +203,16 @@ select.interface { | |||||||
|                     line += '</td>\n'; |                     line += '</td>\n'; | ||||||
|                     line += '</tr>\n'; |                     line += '</tr>\n'; | ||||||
| 
 | 
 | ||||||
|                     if(infos['status']=="Need Password") { |                     if(infos['status'].startsWith("Need")) { | ||||||
|                         line +='<tr><td colspan="4">'; |                         line +='<tr><td colspan="4">'; | ||||||
|                         line +='<form id="auth_'+pid+'" action="#" onsubmit="auth('+pid+') ; return false"  >'; |                         line +='<form id="auth_'+pid+'" action="#" onsubmit="auth('+pid+') ; return false"  >'; | ||||||
|                         line +='<input class="user" placeholder="Enter login" size="15">'; |                         if (infos['status'].includes("Password")) { | ||||||
|                         line +='<input type="password" placeholder="Password" size="15" class="pass">'; |                           line +='<input class="user" placeholder="Enter login" size="15">'; | ||||||
|  |                           line +='<input type="password" placeholder="Password" size="15" class="pass">'; | ||||||
|  |                         } | ||||||
|  |                         if (infos['status'].includes("OTP")) { | ||||||
|  |                           line +='<input class="otp" placeholder="'+infos["message"]+'" size="15">'; | ||||||
|  |                         } | ||||||
|                         line +='<input type="submit" value="G0">'; |                         line +='<input type="submit" value="G0">'; | ||||||
|                         line +='</form>'; |                         line +='</form>'; | ||||||
|                         line +='</td></tr>\n'; |                         line +='</td></tr>\n'; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user