mirror of
https://github.com/boringproxy/boringproxy.git
synced 2025-02-25 18:55:29 -06:00
Replace email login with direct token login
This commit is contained in:
parent
1e25527ab2
commit
2ca7800ca6
61
auth.go
61
auth.go
@ -2,10 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"net/smtp"
|
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,64 +34,6 @@ func (a *Auth) Authorized(token string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Auth) Login(email string, config *BoringProxyConfig) (string, error) {
|
|
||||||
|
|
||||||
key, err := genRandomKey()
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.New("Error generating key")
|
|
||||||
}
|
|
||||||
|
|
||||||
link := fmt.Sprintf("https://%s/login?key=%s", config.WebUiDomain, key)
|
|
||||||
|
|
||||||
bodyTemplate := "From: %s <%s>\r\n" +
|
|
||||||
"To: %s\r\n" +
|
|
||||||
"Subject: Email Verification\r\n" +
|
|
||||||
"\r\n" +
|
|
||||||
"This is email verification request from %s. Please click the following link to complete the verification:\r\n" +
|
|
||||||
"\r\n" +
|
|
||||||
"%s\r\n"
|
|
||||||
|
|
||||||
fromText := "boringproxy email verifier"
|
|
||||||
fromEmail := fmt.Sprintf("auth@%s", config.WebUiDomain)
|
|
||||||
emailBody := fmt.Sprintf(bodyTemplate, fromText, fromEmail, email, config.WebUiDomain, link)
|
|
||||||
|
|
||||||
emailAuth := smtp.PlainAuth("", config.Smtp.Username, config.Smtp.Password, config.Smtp.Server)
|
|
||||||
srv := fmt.Sprintf("%s:%d", config.Smtp.Server, config.Smtp.Port)
|
|
||||||
msg := []byte(emailBody)
|
|
||||||
err = smtp.SendMail(srv, emailAuth, fromEmail, []string{email}, msg)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.New("Sending email failed. Probably a bad email address.")
|
|
||||||
}
|
|
||||||
|
|
||||||
a.mutex.Lock()
|
|
||||||
a.pendingRequests[key] = &LoginRequest{email}
|
|
||||||
a.mutex.Unlock()
|
|
||||||
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Auth) Verify(key string) (string, error) {
|
|
||||||
a.mutex.Lock()
|
|
||||||
defer a.mutex.Unlock()
|
|
||||||
|
|
||||||
request, ok := a.pendingRequests[key]
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return "", errors.New("No pending request for that key. It may have expired.")
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(a.pendingRequests, key)
|
|
||||||
|
|
||||||
token, err := genRandomKey()
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.New("Error generating key")
|
|
||||||
}
|
|
||||||
|
|
||||||
a.db.SetTokenData(token, TokenData{Id: request.Email})
|
|
||||||
|
|
||||||
return token, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const chars string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
const chars string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|
||||||
func genRandomKey() (string, error) {
|
func genRandomKey() (string, error) {
|
||||||
|
@ -19,9 +19,9 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<form class='dialog' action="/login" method="post">
|
<form class='dialog' action="/login" method="GET">
|
||||||
<label for="mail">E-mail:</label>
|
<label for="token">Token:</label>
|
||||||
<input type="email" id="mail" name="email">
|
<input type="password" id="token" name="token">
|
||||||
<button class='button green-button' type="submit">Login</button>
|
<button class='button green-button' type="submit">Login</button>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
|
@ -226,51 +226,33 @@ func (h *WebUiHandler) handleTunnels(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func (h *WebUiHandler) handleLogin(w http.ResponseWriter, r *http.Request) {
|
func (h *WebUiHandler) handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
switch r.Method {
|
// Using GET requests to avoid form resubmission warnings in browsers
|
||||||
case "GET":
|
if r.Method != "GET" {
|
||||||
query := r.URL.Query()
|
|
||||||
key, exists := query["key"]
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
w.WriteHeader(400)
|
|
||||||
fmt.Fprintf(w, "Must provide key for verification")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
token, err := h.auth.Verify(key[0])
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(400)
|
|
||||||
fmt.Fprintf(w, "Invalid key")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cookie := &http.Cookie{Name: "access_token", Value: token, Secure: true, HttpOnly: true}
|
|
||||||
http.SetCookie(w, cookie)
|
|
||||||
|
|
||||||
http.Redirect(w, r, "/", 307)
|
|
||||||
|
|
||||||
case "POST":
|
|
||||||
|
|
||||||
r.ParseForm()
|
|
||||||
|
|
||||||
toEmail, ok := r.Form["email"]
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
w.WriteHeader(400)
|
|
||||||
w.Write([]byte("Email required for login"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// run in goroutine because it can take some time to send the
|
|
||||||
// email
|
|
||||||
go h.auth.Login(toEmail[0], h.config)
|
|
||||||
|
|
||||||
io.WriteString(w, "Check your email to finish logging in")
|
|
||||||
default:
|
|
||||||
w.WriteHeader(405)
|
w.WriteHeader(405)
|
||||||
w.Write([]byte("Invalid method for login"))
|
w.Write([]byte("Invalid method for login"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.ParseForm()
|
||||||
|
|
||||||
|
tokenList, ok := r.Form["token"]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
w.WriteHeader(400)
|
||||||
|
w.Write([]byte("Token required for login"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token := tokenList[0]
|
||||||
|
|
||||||
|
if h.auth.Authorized(token) {
|
||||||
|
cookie := &http.Cookie{Name: "access_token", Value: token, Secure: true, HttpOnly: true}
|
||||||
|
http.SetCookie(w, cookie)
|
||||||
|
http.Redirect(w, r, "/", 307)
|
||||||
|
} else {
|
||||||
|
w.WriteHeader(401)
|
||||||
|
w.Write([]byte("Invalid token"))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *WebUiHandler) handleCreateTunnel(w http.ResponseWriter, r *http.Request) {
|
func (h *WebUiHandler) handleCreateTunnel(w http.ResponseWriter, r *http.Request) {
|
||||||
|
Loading…
Reference in New Issue
Block a user