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) {
|
||||
VPNNames := map[string]string{
|
||||
"Paris 1": "gate-01.dc3.dailmotion.com",
|
||||
"New-York 1": "gate-01.nyc.dailmotion.com",
|
||||
"Silicon Valley 1": "gate-01.sv6.dailmotion.com",
|
||||
"Singapore 1": "gate-01.sg1.dailmotion.com",
|
||||
"Tokyo 1": "gate-01.ty4.dailmotion.com",
|
||||
"Paris 2": "gate-01.dc3.dailmotion.com",
|
||||
"New-York 2": "gate-01.nyc.dailmotion.com",
|
||||
"Silicon Valley 2": "gate-01.sv6.dailmotion.com",
|
||||
"Singapore 2": "gate-01.sg1.dailmotion.com",
|
||||
"Tokyo 2": "gate-01.ty4.dailmotion.com",
|
||||
"Paris 1": "gate-01.dc3.dailymotion.com",
|
||||
"New-York 1": "gate-01.nyc.dailymotion.com",
|
||||
"Silicon Valley 1": "gate-01.sv6.dailymotion.com",
|
||||
"Singapore 1": "gate-01.sg1.dailymotion.com",
|
||||
"Tokyo 1": "gate-01.ty4.dailymotion.com",
|
||||
"Paris 2": "gate-02.dc3.dailymotion.com",
|
||||
"New-York 2": "gate-02.nyc.dailymotion.com",
|
||||
"Silicon Valley 2": "gate-02.sv6.dailymotion.com",
|
||||
"Singapore 2": "gate-02.sg1.dailymotion.com",
|
||||
"Tokyo 2": "gate-02.ty4.dailymotion.com",
|
||||
"default": "vpn.dailymotion.com",
|
||||
}
|
||||
return nil, &VPNNames
|
||||
|
|
3
httpd.go
3
httpd.go
|
@ -22,6 +22,7 @@ type jsonInputParams struct {
|
|||
Session int `json:"session"`
|
||||
User string `json:"user"`
|
||||
Pass string `json:"password"`
|
||||
OTP string `json:"otp"`
|
||||
}
|
||||
|
||||
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)
|
||||
jsonStr = []byte("{\"status\": \"ok\"}")
|
||||
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\"}")
|
||||
case "get-sessions":
|
||||
jsonStr, err = json.Marshal(h.ovpn)
|
||||
|
|
97
openvpn.go
97
openvpn.go
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
@ -14,6 +15,7 @@ import (
|
|||
type OpenVpnPassword struct {
|
||||
User string
|
||||
Pass string
|
||||
OTP string
|
||||
}
|
||||
|
||||
type OpenVpnSrv struct {
|
||||
|
@ -21,6 +23,7 @@ type OpenVpnSrv struct {
|
|||
Status string `json:"status"`
|
||||
Provider string `json:"provider"`
|
||||
Identifier string `json:"identifier"`
|
||||
Message string `json:"message"`
|
||||
chanHold chan bool
|
||||
chanPass chan OpenVpnPassword
|
||||
m sync.RWMutex
|
||||
|
@ -28,6 +31,7 @@ type OpenVpnSrv struct {
|
|||
buf *bufio.ReadWriter
|
||||
mgt *OpenVpnMgt
|
||||
hold bool
|
||||
authWait bool
|
||||
authCache *OpenVpnPassword
|
||||
}
|
||||
|
||||
|
@ -47,12 +51,21 @@ func NewOpenVpnSrv(conn net.Conn, mgt *OpenVpnMgt) *OpenVpnSrv {
|
|||
ret: make(chan []string),
|
||||
mgt: mgt,
|
||||
hold: false,
|
||||
authWait: false,
|
||||
Status: "Starting",
|
||||
Identifier: "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
|
||||
func (v *OpenVpnSrv) sendCommand(msg []string) (error, []string) {
|
||||
v.Lock()
|
||||
|
@ -149,7 +162,9 @@ func (v *OpenVpnSrv) GetLine() (string, error) {
|
|||
}
|
||||
|
||||
func (v *OpenVpnSrv) ValidRemote(server, port, proto string) {
|
||||
v.Status = "Connected"
|
||||
if !v.authWait {
|
||||
v.Status = "Connected"
|
||||
}
|
||||
if v.Remote != "" {
|
||||
v.sendCommand([]string{fmt.Sprintf("remote MOD %s %s %s", v.Remote, port, proto)})
|
||||
return
|
||||
|
@ -182,12 +197,31 @@ func (v *OpenVpnSrv) SetRemote(server string) error {
|
|||
}
|
||||
|
||||
func (v *OpenVpnSrv) NeedPassword(line string) {
|
||||
if v.authWait {
|
||||
return
|
||||
}
|
||||
v.authWait = true
|
||||
v.mgt.Debug(line)
|
||||
v.Status = "Need Password"
|
||||
switch line {
|
||||
case ">PASSWORD:Need 'Auth' username/password":
|
||||
v.Message = ""
|
||||
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"
|
||||
case ">PASSWORD:Verification Failed: 'Auth'":
|
||||
case line == ">PASSWORD:Verification Failed: 'Auth'":
|
||||
v.authCache = nil
|
||||
v.Status = "Auth Failed"
|
||||
return
|
||||
|
@ -196,20 +230,55 @@ func (v *OpenVpnSrv) NeedPassword(line string) {
|
|||
ident := <-v.chanPass
|
||||
v.authCache = &ident
|
||||
}
|
||||
switch line {
|
||||
case ">PASSWORD:Need 'Auth' username/password":
|
||||
v.sendCommand([]string{fmt.Sprintf("username \"Auth\" %s", v.authCache.User)})
|
||||
v.sendCommand([]string{fmt.Sprintf("password \"Auth\" %s", v.authCache.Pass)})
|
||||
var cmd []string
|
||||
switch {
|
||||
case len(CRV1Match) > 1:
|
||||
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) {
|
||||
auth := OpenVpnPassword{user, pass}
|
||||
v.authCache = &auth
|
||||
if v.Status == "Need Password" {
|
||||
v.Status = "Authenticate"
|
||||
v.chanPass <- auth
|
||||
func (v *OpenVpnSrv) AuthUserPass(user, pass, otp string) {
|
||||
auth := OpenVpnPassword{user, pass, otp}
|
||||
if v.authCache == nil {
|
||||
v.authCache = &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() {
|
||||
|
|
File diff suppressed because one or more lines are too long
9
utils.go
9
utils.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"math/big"
|
||||
"net"
|
||||
"sort"
|
||||
|
@ -8,6 +9,14 @@ import (
|
|||
"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
|
||||
// efficiant. adapt with sorting "search" too
|
||||
func inArray(search, list []string) bool {
|
||||
|
|
|
@ -102,13 +102,13 @@ func (s *OpenVpnMgt) Restart(pid int) error {
|
|||
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
|
||||
err, session := s.GetSession(pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session.AuthUserPass(user, pass)
|
||||
session.AuthUserPass(user, pass, otp)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -142,7 +142,9 @@ select.interface {
|
|||
function auth(pid) {
|
||||
ajax({action: "auth-user-pass", params:{session: pid,
|
||||
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) {
|
||||
|
@ -201,11 +203,16 @@ select.interface {
|
|||
line += '</td>\n';
|
||||
line += '</tr>\n';
|
||||
|
||||
if(infos['status']=="Need Password") {
|
||||
if(infos['status'].startsWith("Need")) {
|
||||
line +='<tr><td colspan="4">';
|
||||
line +='<form id="auth_'+pid+'" action="#" onsubmit="auth('+pid+') ; return false" >';
|
||||
line +='<input class="user" placeholder="Enter login" size="15">';
|
||||
line +='<input type="password" placeholder="Password" size="15" class="pass">';
|
||||
if (infos['status'].includes("Password")) {
|
||||
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 +='</form>';
|
||||
line +='</td></tr>\n';
|
||||
|
|
Loading…
Reference in New Issue