Limit OTP requests to one per expiry window. Closes #2000
This commit is contained in:
parent
c40eaa47e9
commit
0b5ddf433b
@ -19,9 +19,19 @@ type OTPRegistration struct {
|
|||||||
// to be active at a time.
|
// to be active at a time.
|
||||||
var pendingAuthRequests = make(map[string]OTPRegistration)
|
var pendingAuthRequests = make(map[string]OTPRegistration)
|
||||||
|
|
||||||
|
const registrationTimeout = time.Minute * 10
|
||||||
|
|
||||||
// RegisterFediverseOTP will start the OTP flow for a user, creating a new
|
// RegisterFediverseOTP will start the OTP flow for a user, creating a new
|
||||||
// code and returning it to be sent to a destination.
|
// code and returning it to be sent to a destination.
|
||||||
func RegisterFediverseOTP(accessToken, userID, userDisplayName, account string) OTPRegistration {
|
func RegisterFediverseOTP(accessToken, userID, userDisplayName, account string) (OTPRegistration, bool) {
|
||||||
|
request, requestExists := pendingAuthRequests[accessToken]
|
||||||
|
|
||||||
|
// If a request is already registered and has not expired then return that
|
||||||
|
// existing request.
|
||||||
|
if requestExists && time.Since(request.Timestamp) < registrationTimeout {
|
||||||
|
return request, false
|
||||||
|
}
|
||||||
|
|
||||||
code, _ := createCode()
|
code, _ := createCode()
|
||||||
r := OTPRegistration{
|
r := OTPRegistration{
|
||||||
Code: code,
|
Code: code,
|
||||||
@ -32,14 +42,14 @@ func RegisterFediverseOTP(accessToken, userID, userDisplayName, account string)
|
|||||||
}
|
}
|
||||||
pendingAuthRequests[accessToken] = r
|
pendingAuthRequests[accessToken] = r
|
||||||
|
|
||||||
return r
|
return r, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateFediverseOTP will verify a OTP code for a auth request.
|
// ValidateFediverseOTP will verify a OTP code for a auth request.
|
||||||
func ValidateFediverseOTP(accessToken, code string) (bool, *OTPRegistration) {
|
func ValidateFediverseOTP(accessToken, code string) (bool, *OTPRegistration) {
|
||||||
request, ok := pendingAuthRequests[accessToken]
|
request, ok := pendingAuthRequests[accessToken]
|
||||||
|
|
||||||
if !ok || request.Code != code || time.Since(request.Timestamp) > time.Minute*10 {
|
if !ok || request.Code != code || time.Since(request.Timestamp) > registrationTimeout {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,11 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestOTPFlowValidation(t *testing.T) {
|
func TestOTPFlowValidation(t *testing.T) {
|
||||||
r := RegisterFediverseOTP(accessToken, userID, userDisplayName, account)
|
r, success := RegisterFediverseOTP(accessToken, userID, userDisplayName, account)
|
||||||
|
|
||||||
|
if !success {
|
||||||
|
t.Error("Registration should be permitted.")
|
||||||
|
}
|
||||||
|
|
||||||
if r.Code == "" {
|
if r.Code == "" {
|
||||||
t.Error("Code is empty")
|
t.Error("Code is empty")
|
||||||
@ -41,3 +45,16 @@ func TestOTPFlowValidation(t *testing.T) {
|
|||||||
t.Error("UserDisplayName is not set correctly")
|
t.Error("UserDisplayName is not set correctly")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSingleOTPFlowRequest(t *testing.T) {
|
||||||
|
r1, _ := RegisterFediverseOTP(accessToken, userID, userDisplayName, account)
|
||||||
|
r2, s2 := RegisterFediverseOTP(accessToken, userID, userDisplayName, account)
|
||||||
|
|
||||||
|
if r1.Code != r2.Code {
|
||||||
|
t.Error("Only one registration should be permitted.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s2 {
|
||||||
|
t.Error("Second registration should not be permitted.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -29,7 +29,12 @@ func RegisterFediverseOTPRequest(u user.User, w http.ResponseWriter, r *http.Req
|
|||||||
}
|
}
|
||||||
|
|
||||||
accessToken := r.URL.Query().Get("accessToken")
|
accessToken := r.URL.Query().Get("accessToken")
|
||||||
reg := fediverseauth.RegisterFediverseOTP(accessToken, u.ID, u.DisplayName, req.FediverseAccount)
|
reg, success := fediverseauth.RegisterFediverseOTP(accessToken, u.ID, u.DisplayName, req.FediverseAccount)
|
||||||
|
if !success {
|
||||||
|
controllers.WriteSimpleResponse(w, false, "Could not register auth request. One may already be pending. Try again later.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
msg := fmt.Sprintf("<p>This is an automated message from %s. If you did not request this message please ignore or block. Your requested one-time code is:</p><p>%s</p>", data.GetServerName(), reg.Code)
|
msg := fmt.Sprintf("<p>This is an automated message from %s. If you did not request this message please ignore or block. Your requested one-time code is:</p><p>%s</p>", data.GetServerName(), reg.Code)
|
||||||
if err := activitypub.SendDirectFederatedMessage(msg, reg.Account); err != nil {
|
if err := activitypub.SendDirectFederatedMessage(msg, reg.Account); err != nil {
|
||||||
controllers.WriteSimpleResponse(w, false, "Could not send code to fediverse: "+err.Error())
|
controllers.WriteSimpleResponse(w, false, "Could not send code to fediverse: "+err.Error())
|
||||||
|
Loading…
Reference in New Issue
Block a user