dkforest

A forum and chat platform (onion)
git clone https://git.dasho.dev/n0tr1v/dkforest.git
Log | Files | Refs | LICENSE

commit 5c61614a49ca566388cf4952a09786ed6717e733
parent 1d0e28b7273bea0f2647bc302308ba593c1de742
Author: n0tr1v <n0tr1v@protonmail.com>
Date:   Wed, 14 Dec 2022 12:42:53 -0500

simplify code, make it possible to reuse wait page for other endpoints

Diffstat:
Mpkg/web/handlers/handlers.go | 84++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
1 file changed, 49 insertions(+), 35 deletions(-)

diff --git a/pkg/web/handlers/handlers.go b/pkg/web/handlers/handlers.go @@ -569,10 +569,6 @@ func createSessionCookie(value string) *http.Cookie { return hutils.CreateCookie(hutils.AuthCookieName, value, utils.OneMonthSecs) } -func createSignupCookie(value string, maxAge int64) *http.Cookie { - return hutils.CreateCookie(hutils.SignupCookieName, value, maxAge) -} - // FlashResponse ... type FlashResponse struct { Message string @@ -603,7 +599,7 @@ func SignupInvitationHandler(c echo.Context) error { if _, err := database.GetUnusedInvitationByToken(invitationToken); err != nil { return c.Redirect(http.StatusFound, "/") } - return signupHandler(c) + return waitPageWrapper(c, signupHandler, hutils.SignupCookieName) } func AesNB64(in string) string { @@ -724,16 +720,41 @@ func SignupHandler(c echo.Context) error { if config.SignupFakeEnabled.IsFalse() && config.SignupEnabled.IsFalse() { return c.Render(http.StatusOK, "signup-invite", nil) } - return signupHandler(c) + return waitPageWrapper(c, signupHandler, hutils.SignupCookieName) } -// The random wait time 0-15 seconds make sure the load is evenly distributed while under DDoS. -// Not all requests to the signup endpoint will get the captcha at the same time, -// so you cannot just refresh the page until you get a captcha that is easier to crack. -func signupHandler(c echo.Context) error { +func waitPageWrapper(c echo.Context, clb echo.HandlerFunc, cookieName string) error { start := time.Now().UnixNano() var signupToken string - if cc, err := c.Cookie(hutils.SignupCookieName); err == nil { + if cc, err := c.Cookie(hutils.SignupCookieName); err != nil { + // No cookie found, we create one and display the waiting page. + waitTime := utils.Random(5, 15) + signupToken = utils.GenerateToken10() + payload := map[string]string{ + "token": signupToken, + "count": "1", + "now": utils.FormatInt64(time.Now().UnixMilli()), + "unix": utils.FormatInt64(time.Now().Unix() + waitTime - 1), // unix time at which the wait time is over + } + by, _ := json.Marshal(payload) + encryptedVal, _ := utils.EncryptAES(by, []byte(config.Global.MasterKey())) + valB64 := base64.URLEncoding.EncodeToString(encryptedVal) + c.SetCookie(hutils.CreateCookie(cookieName, valB64, utils.OneMinuteSecs*5)) + + var data1 signupWaitData + // Generate css frames + step := 100.0 / float64(waitTime) + pct := 0.0 + for i := int64(0); i <= waitTime; i++ { + data1.Frames = append(data1.Frames, fmt.Sprintf(`%.2f%% { content: "%d"; }`, pct, waitTime-i)) + pct += step + } + data1.WaitTime = waitTime + data1.SignupToken = signupToken + return c.Render(http.StatusOK, "signup-wait", data1) + + } else { + // Cookie was found, incr counter then call callback valB64 := cc.Value val, err := base64.URLEncoding.DecodeString(valB64) if err != nil { @@ -752,16 +773,19 @@ func signupHandler(c echo.Context) error { if c.Request().Method == http.MethodGet { count := utils.DoParseInt64(payload["count"]) unix := utils.DoParseInt64(payload["unix"]) - if time.Now().Unix() < unix { + // If you reload the page before the wait time is over, we kill the circuit. + if time.Now().Unix() < unix { // Kill circuit if conn, ok := c.Request().Context().Value("conn").(net.Conn); ok { config.ConnMap.Close(conn) } return c.String(http.StatusFound, "DDoS filter killed your path") } + + // If the wait time is over, and you reload the protected page more than 4 times, we make you wait 1min if count >= 4 { - c.SetCookie(createSignupCookie(valB64, utils.OneMinuteSecs)) + c.SetCookie(hutils.CreateCookie(cookieName, valB64, utils.OneMinuteSecs)) return c.String(http.StatusFound, "You tried to reload the page to many times. Now you have to wait one minute.") } newPayload := map[string]string{ @@ -772,30 +796,20 @@ func signupHandler(c echo.Context) error { by, _ := json.Marshal(newPayload) newEncryptedVal, _ := utils.EncryptAES(by, []byte(config.Global.MasterKey())) newValB64 := base64.URLEncoding.EncodeToString(newEncryptedVal) - c.SetCookie(createSignupCookie(newValB64, utils.OneMinuteSecs*5)) + c.SetCookie(hutils.CreateCookie(cookieName, newValB64, utils.OneMinuteSecs*5)) } - } else { - // No cookie found, we create one and display the waiting page. - waitTime := utils.Random(5, 15) - signupToken = utils.GenerateToken10() - payload := map[string]string{"token": signupToken, "count": "1", "now": utils.FormatInt64(time.Now().UnixMilli()), "unix": utils.FormatInt64(time.Now().Unix() + waitTime - 1)} - by, _ := json.Marshal(payload) - encryptedVal, _ := utils.EncryptAES(by, []byte(config.Global.MasterKey())) - valB64 := base64.URLEncoding.EncodeToString(encryptedVal) - c.SetCookie(createSignupCookie(valB64, utils.OneMinuteSecs*5)) - - var data1 signupWaitData - // Generate css frames - step := 100.0 / float64(waitTime) - pct := 0.0 - for i := int64(0); i <= waitTime; i++ { - data1.Frames = append(data1.Frames, fmt.Sprintf(`%.2f%% { content: "%d"; }`, pct, waitTime-i)) - pct += step - } - data1.WaitTime = waitTime - data1.SignupToken = signupToken - return c.Render(http.StatusOK, "signup-wait", data1) } + c.Set("start", start) + c.Set("signupToken", signupToken) + return clb(c) +} + +// The random wait time 0-15 seconds make sure the load is evenly distributed while under DDoS. +// Not all requests to the signup endpoint will get the captcha at the same time, +// so you cannot just refresh the page until you get a captcha that is easier to crack. +func signupHandler(c echo.Context) error { + start := c.Get("start").(int64) + signupToken := c.Get("signupToken").(string) var data signupData config.SignupPageLoad.Inc()