dkforest

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

web.go (34665B)


      1 package web
      2 
      3 import (
      4 	"context"
      5 	"dkforest/bindata"
      6 	"dkforest/pkg/config"
      7 	"dkforest/pkg/database"
      8 	"dkforest/pkg/staticbin"
      9 	tmp "dkforest/pkg/template"
     10 	"dkforest/pkg/utils"
     11 	"dkforest/pkg/web/clientFrontends"
     12 	"dkforest/pkg/web/handlers"
     13 	v1 "dkforest/pkg/web/handlers/api/v1"
     14 	"dkforest/pkg/web/middlewares"
     15 	"fmt"
     16 	"github.com/labstack/echo"
     17 	"github.com/nicksnyder/go-i18n/v2/i18n"
     18 	"github.com/sirupsen/logrus"
     19 	"github.com/ulule/limiter"
     20 	"github.com/ulule/limiter/drivers/store/memory"
     21 	"golang.org/x/text/language"
     22 	yaml "gopkg.in/yaml.v1"
     23 	"net"
     24 	"net/http"
     25 	"net/http/httputil"
     26 	"net/url"
     27 	"os"
     28 	"os/signal"
     29 	"regexp"
     30 	"strconv"
     31 	"strings"
     32 	"time"
     33 )
     34 
     35 func getMainServer(db *database.DkfDB, i18nBundle *i18n.Bundle, renderer *tmp.Templates, clientFE clientFrontends.ClientFrontend) echo.HandlerFunc {
     36 	e := newEcho()
     37 
     38 	e.Server.ReadHeaderTimeout = 10 * time.Second
     39 	e.Server.ReadTimeout = 10 * time.Second
     40 	e.Server.WriteTimeout = 10 * time.Second
     41 
     42 	e.Use(staticbin.Static(bindata.Asset, staticbin.Options{Dir: "/public", SkipLogging: true}))
     43 	e.Renderer = renderer
     44 	e.Use(middlewares.SetDatabaseMiddleware(db))
     45 	e.Use(middlewares.SetClientFEMiddleware(clientFE))
     46 	e.Use(middlewares.FirstUseMiddleware)
     47 	e.Use(middlewares.DdosMiddleware)
     48 	e.Use(middlewares.MaintenanceMiddleware)
     49 	e.Use(middlewares.SecureMiddleware)
     50 	e.Use(middlewares.SetUserMiddleware)
     51 	e.Use(middlewares.GzipMiddleware)
     52 	e.Use(middlewares.CSRFMiddleware())
     53 	e.Use(middlewares.I18nMiddleware(i18nBundle, "en"))
     54 	e.Use(middlewares.BodyLimit)
     55 	e.Use(middlewares.HellbannedCookieMiddleware)
     56 	e.Use(middlewares.AprilFoolMiddleware())
     57 	e.GET("/", handlers.HomeHandler, middlewares.CircuitRateLimitMiddleware(15*time.Second, 4, true))
     58 	e.POST("/", handlers.HomeHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 4, false))
     59 	e.GET("/bhcli", handlers.BhcliHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 5, false))
     60 	e.GET("/torchess", handlers.TorchessHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 5, false))
     61 	e.GET("/captcha-help", handlers.CaptchaHelpHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 5, false))
     62 	e.GET("/pow-help", handlers.PowHelpHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 5, false))
     63 	e.GET("/werewolf", handlers.WerewolfHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 5, false))
     64 	e.GET("/gists/:gistUUID", handlers.GistHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 5, false))
     65 	e.POST("/gists/:gistUUID", handlers.GistHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 3, false))
     66 	e.GET("/chat/:roomName", handlers.ChatHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 4, false))
     67 	e.POST("/chat/:roomName", handlers.ChatHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 2, false))
     68 	e.GET("/bhc", handlers.BHCHandler, middlewares.CircuitRateLimitMiddleware(5*time.Second, 4, true))
     69 	e.POST("/bhc", handlers.BHCHandler, middlewares.CircuitRateLimitMiddleware(5*time.Second, 4, true))
     70 	e.GET("/public/css/:signupToken/signup.css", handlers.SignupCss, middlewares.CircuitRateLimitMiddleware(15*time.Second, 4, false))
     71 	e.GET("/public/img/:signupToken/:signal/:data", handlers.SignalCss, middlewares.CircuitRateLimitMiddleware(15*time.Second, 4, false))
     72 	noAuthGroup := e.Group("", middlewares.NoAuthMiddleware)
     73 	noAuthGroup.GET("/login", handlers.LoginHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 4, false))
     74 	noAuthGroup.POST("/login", handlers.LoginHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 4, false))
     75 	noAuthGroup.GET("/login/:loginToken", handlers.LoginAttackHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 4, false))
     76 	noAuthGroup.POST("/login/:loginToken", handlers.LoginAttackHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 2, false))
     77 	noAuthGroup.GET("/signup", handlers.SignupHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 5, false))
     78 	noAuthGroup.POST("/signup", handlers.SignupHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 4, false))
     79 	noAuthGroup.GET("/signup/invitation", handlers.SignupInvitationHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 5, false))
     80 	noAuthGroup.GET("/signup/invitation/:invitationToken", handlers.SignupInvitationHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 5, false))
     81 	noAuthGroup.POST("/signup/invitation/:invitationToken", handlers.SignupInvitationHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 5, false))
     82 	noAuthGroup.GET("/signup/:signupToken", handlers.SignupAttackHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 5, false))
     83 	noAuthGroup.POST("/signup/:signupToken", handlers.SignupAttackHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 2, false))
     84 	noAuthGroup.GET("/forgot-password", handlers.ForgotPasswordHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 4, false))
     85 	noAuthGroup.POST("/forgot-password", handlers.ForgotPasswordHandler, middlewares.CircuitRateLimitMiddleware(1*time.Second, 2, false))
     86 	maybeAuthGroup := e.Group("", middlewares.MaybeAuthMiddleware)
     87 	maybeAuthGroup.GET("/u/:username", handlers.PublicUserProfileHandler, middlewares.GenericRateLimitMiddleware(time.Second, 2))
     88 	maybeAuthGroup.GET("/u/:username/pgp", handlers.PublicUserProfilePGPHandler, middlewares.GenericRateLimitMiddleware(time.Second, 2))
     89 	maybeAuthGroup.GET("/t/:threadUUID", handlers.ThreadHandler, middlewares.GenericRateLimitMiddleware(time.Second, 2))
     90 	authGroup := e.Group("", middlewares.IsAuthMiddleware, middlewares.ForceCaptchaMiddleware)
     91 	authGroup.GET("/public/css/meta.css", handlers.MetaCss)
     92 	authGroup.GET("/public/img/signal/:signal/:data", handlers.SignalCss1)
     93 	authGroup.GET("/captcha-required", handlers.CaptchaRequiredHandler, middlewares.AuthRateLimitMiddleware(time.Second, 1))
     94 	authGroup.POST("/captcha-required", handlers.CaptchaRequiredHandler, middlewares.AuthRateLimitMiddleware(time.Second, 1))
     95 	authGroup.GET("/odometer", handlers.OdometerHandler, middlewares.AuthRateLimitMiddleware(time.Second, 1))
     96 	authGroup.GET("/captcha", handlers.CaptchaHandler, middlewares.AuthRateLimitMiddleware(time.Second, 1))
     97 	authGroup.POST("/captcha", handlers.CaptchaHandler, middlewares.AuthRateLimitMiddleware(time.Second, 1))
     98 	authGroup.GET("/donate", handlers.DonateHandler)
     99 	authGroup.GET("/shop", handlers.ShopHandler)
    100 	authGroup.GET("/poker", handlers.PokerHomeHandler)
    101 	authGroup.POST("/poker", handlers.PokerHomeHandler, middlewares.AuthRateLimitMiddleware(time.Second, 1))
    102 	authGroup.GET("/poker/rake-back", handlers.PokerRakeBackHandler)
    103 	authGroup.POST("/poker/rake-back", handlers.PokerRakeBackHandler, middlewares.AuthRateLimitMiddleware(time.Second, 1))
    104 	authGroup.GET("/poker/:roomID", handlers.PokerTableHandler)
    105 	authGroup.GET("/poker/:roomID/stream", handlers.PokerStreamHandler)
    106 	authGroup.GET("/poker/:roomID/logs", handlers.PokerLogsHandler)
    107 	authGroup.GET("/poker/:roomID/bet", handlers.PokerBetHandler)
    108 	authGroup.POST("/poker/:roomID/bet", handlers.PokerBetHandler)
    109 	authGroup.GET("/poker/:roomID/deal", handlers.PokerDealHandler)
    110 	authGroup.POST("/poker/:roomID/deal", handlers.PokerDealHandler)
    111 	authGroup.GET("/poker/:roomID/unsit", handlers.PokerUnSitHandler)
    112 	authGroup.POST("/poker/:roomID/unsit", handlers.PokerUnSitHandler)
    113 	authGroup.GET("/poker/:roomID/sit/:pos", handlers.PokerSitHandler)
    114 	authGroup.POST("/poker/:roomID/sit/:pos", handlers.PokerSitHandler)
    115 	authGroup.GET("/chess", handlers.ChessHandler)
    116 	authGroup.POST("/chess", handlers.ChessHandler)
    117 	authGroup.GET("/chess/analyze", handlers.ChessAnalyzeHandler)
    118 	authGroup.POST("/chess/analyze", handlers.ChessAnalyzeHandler)
    119 	authGroup.GET("/chess/:key", handlers.ChessGameHandler)
    120 	authGroup.POST("/chess/:key", handlers.ChessGameHandler)
    121 	authGroup.GET("/chess/:key/analyze", handlers.ChessGameAnalyzeHandler)
    122 	authGroup.POST("/chess/:key/analyze", handlers.ChessGameAnalyzeHandler)
    123 	authGroup.GET("/chess/:key/form", handlers.ChessGameFormHandler)
    124 	authGroup.POST("/chess/:key/form", handlers.ChessGameFormHandler)
    125 	authGroup.GET("/chess/:key/stats", handlers.ChessGameStatsHandler)
    126 	authGroup.POST("/chess/:key/stats", handlers.ChessGameStatsHandler)
    127 	authGroup.GET("/settings/chat", handlers.SettingsChatHandler)
    128 	authGroup.POST("/settings/chat", handlers.SettingsChatHandler, middlewares.AuthRateLimitMiddleware(2*time.Second, 1))
    129 	authGroup.GET("/settings/chat/pm", handlers.SettingsChatPMHandler)
    130 	authGroup.POST("/settings/chat/pm", handlers.SettingsChatPMHandler, middlewares.AuthRateLimitMiddleware(2*time.Second, 5))
    131 	authGroup.GET("/settings/chat/ignore", handlers.SettingsChatIgnoreHandler)
    132 	authGroup.POST("/settings/chat/ignore", handlers.SettingsChatIgnoreHandler, middlewares.AuthRateLimitMiddleware(2*time.Second, 5))
    133 	authGroup.GET("/settings/chat/snippets", handlers.SettingsChatSnippetsHandler)
    134 	authGroup.POST("/settings/chat/snippets", handlers.SettingsChatSnippetsHandler, middlewares.AuthRateLimitMiddleware(2*time.Second, 5))
    135 	authGroup.GET("/settings/public-notes", handlers.SettingsPublicNotesHandler)
    136 	authGroup.POST("/settings/public-notes", handlers.SettingsPublicNotesHandler)
    137 	authGroup.GET("/settings/private-notes", handlers.SettingsPrivateNotesHandler)
    138 	authGroup.POST("/settings/private-notes", handlers.SettingsPrivateNotesHandler)
    139 	authGroup.GET("/settings/sessions", handlers.SettingsSessionsHandler)
    140 	authGroup.POST("/settings/sessions", handlers.SettingsSessionsHandler)
    141 	authGroup.GET("/settings/api", handlers.SettingsAPIHandler)
    142 	authGroup.POST("/settings/api", handlers.SettingsAPIHandler)
    143 	authGroup.GET("/settings/security", handlers.SettingsSecurityHandler)
    144 	authGroup.GET("/settings/account", handlers.SettingsAccountHandler)
    145 	authGroup.POST("/settings/account", handlers.SettingsAccountHandler, middlewares.AuthRateLimitMiddleware(2*time.Second, 1))
    146 	authGroup.GET("/settings/password", handlers.SettingsPasswordHandler)
    147 	authGroup.POST("/settings/password", handlers.SettingsPasswordHandler, middlewares.AuthRateLimitMiddleware(2*time.Second, 1))
    148 	authGroup.GET("/settings/uploads", handlers.SettingsUploadsHandler)
    149 	authGroup.POST("/settings/uploads", handlers.SettingsUploadsHandler, middlewares.AuthRateLimitMiddleware(2*time.Second, 5))
    150 	authGroup.GET("/settings/inbox", handlers.SettingsInboxHandler)
    151 	authGroup.POST("/settings/inbox", handlers.SettingsInboxHandler, middlewares.AuthRateLimitMiddleware(2*time.Second, 1))
    152 	authGroup.GET("/settings/inbox/sent", handlers.SettingsInboxSentHandler)
    153 	authGroup.POST("/settings/inbox/sent", handlers.SettingsInboxSentHandler, middlewares.AuthRateLimitMiddleware(2*time.Second, 1))
    154 	authGroup.GET("/settings/pgp/add", handlers.AddPGPHandler)
    155 	authGroup.POST("/settings/pgp/add", handlers.AddPGPHandler)
    156 	authGroup.GET("/settings/pgp", handlers.SettingsPGPHandler)
    157 	authGroup.GET("/settings/age", handlers.SettingsAgeHandler)
    158 	authGroup.GET("/settings/age/add", handlers.AddAgeHandler)
    159 	authGroup.POST("/settings/age/add", handlers.AddAgeHandler)
    160 	authGroup.GET("/gpg-two-factor-authentication/toggle", handlers.GpgTwoFactorAuthenticationToggleHandler)
    161 	authGroup.POST("/gpg-two-factor-authentication/toggle", handlers.GpgTwoFactorAuthenticationToggleHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 4))
    162 	authGroup.GET("/two-factor-authentication/verify", handlers.TwoFactorAuthenticationVerifyHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 4))
    163 	authGroup.POST("/two-factor-authentication/verify", handlers.TwoFactorAuthenticationVerifyHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    164 	authGroup.GET("/two-factor-authentication/disable", handlers.TwoFactorAuthenticationDisableHandler)
    165 	authGroup.POST("/two-factor-authentication/disable", handlers.TwoFactorAuthenticationDisableHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    166 	authGroup.GET("/api/v1/captcha-svc", v1.GetCaptchaHandler)
    167 	authGroup.POST("/api/v1/chat/:roomName/notifier", v1.RoomNotifierHandler)
    168 	authGroup.POST("/api/v1/battleship", v1.BattleshipHandler)
    169 	authGroup.POST("/api/v1/werewolf", v1.WerewolfHandler)
    170 	authGroup.POST("/api/v1/captcha/solver", v1.CaptchaSolverHandler)
    171 	authGroup.GET("/api/v1/chat/controls/:roomName/:isStream", v1.ChatControlsHandler)
    172 	authGroup.POST("/api/v1/chat/controls/:roomName/:isStream", v1.ChatControlsHandler)
    173 	authGroup.GET("/api/v1/chat/top-bar/:roomName", v1.ChatTopBarHandler)
    174 	authGroup.POST("/api/v1/chat/top-bar/:roomName", v1.ChatTopBarHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 3))
    175 	authGroup.GET("/api/v1/chat/messages/:roomName", v1.ChatMessagesHandler)
    176 	authGroup.GET("/api/v1/chat/messages/:roomName/refresh", v1.ChatStreamMessagesRefreshHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 4))
    177 	authGroup.GET("/api/v1/chat/messages/:roomName/stream", v1.ChatStreamMessagesHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 4))
    178 	authGroup.GET("/api/v1/chat/messages/:roomName/stream/menu", v1.ChatStreamMenuHandler)
    179 	authGroup.POST("/api/v1/notifications/delete/:notificationID", v1.DeleteNotificationHandler)
    180 	authGroup.POST("/api/v1/session-notifications/delete/:sessionNotificationID", v1.DeleteSessionNotificationHandler)
    181 	authGroup.POST("/api/v1/inbox/delete/:messageID", v1.ChatInboxDeleteMessageHandler)
    182 	authGroup.POST("/api/v1/inbox/delete-all", v1.ChatInboxDeleteAllMessageHandler)
    183 	authGroup.GET("/api/v1/chat/messages/delete/:messageUUID", v1.ChatDeleteMessageHandler)
    184 	authGroup.POST("/api/v1/chat/messages/delete/:messageUUID", v1.ChatDeleteMessageHandler)
    185 	authGroup.POST("/api/v1/chat/messages/reactions", v1.ChatMessageReactionHandler)
    186 	authGroup.POST("/api/v1/rooms/:roomName/subscribe", v1.SubscribeHandler)
    187 	authGroup.POST("/api/v1/rooms/:roomName/unsubscribe", v1.UnsubscribeHandler)
    188 	authGroup.POST("/api/v1/threads/:threadUUID/subscribe", v1.ThreadSubscribeHandler)
    189 	authGroup.POST("/api/v1/threads/:threadUUID/unsubscribe", v1.ThreadUnsubscribeHandler)
    190 	authGroup.POST("/logout", handlers.LogoutHandler)
    191 	authGroup.GET("/uploads/:filename", handlers.UploadsDownloadHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    192 	authGroup.POST("/uploads/:filename", handlers.UploadsDownloadHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    193 	authGroup.GET("/torchess/downloads", handlers.TorchessDownloadsHandler)
    194 	authGroup.GET("/torchess/downloads/:filename", handlers.TorChessDownloadFileHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2), middlewares.CaptchaMiddleware())
    195 	authGroup.POST("/torchess/downloads/:filename", handlers.TorChessDownloadFileHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2), middlewares.CaptchaMiddleware())
    196 	authGroup.GET("/bhcli/downloads", handlers.BhcliDownloadsHandler)
    197 	authGroup.GET("/bhcli/downloads/:filename", handlers.BhcliDownloadFileHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2), middlewares.CaptchaMiddleware())
    198 	authGroup.POST("/bhcli/downloads/:filename", handlers.BhcliDownloadFileHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2), middlewares.CaptchaMiddleware())
    199 	authGroup.GET("/memes/:slug", handlers.MemeHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    200 	authGroup.GET("/news", handlers.NewsHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    201 	authGroup.GET("/links", handlers.LinksHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    202 	authGroup.GET("/links/download", handlers.LinksDownloadHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    203 	authGroup.POST("/links/download", handlers.LinksDownloadHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    204 	authGroup.GET("/l/:shorthand", handlers.LinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    205 	authGroup.GET("/links/claim-instructions", handlers.LinksClaimInstructionsHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    206 	authGroup.GET("/links/:linkUUID", handlers.LinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    207 	authGroup.POST("/links/:linkUUID/restore", handlers.RestoreLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    208 	authGroup.GET("/links/:linkUUID/claim", handlers.ClaimLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    209 	authGroup.POST("/links/:linkUUID/claim", handlers.ClaimLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    210 	authGroup.POST("/links/:linkUUID/claim/download-certificate", handlers.ClaimDownloadCertificateLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    211 	authGroup.GET("/links/:linkUUID/claim-certificate", handlers.ClaimCertificateLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    212 	authGroup.GET("/links/:linkUUID/edit", handlers.EditLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    213 	authGroup.POST("/links/:linkUUID/edit", handlers.EditLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    214 	authGroup.GET("/links/:linkUUID/delete", handlers.LinkDeleteHandler)
    215 	authGroup.POST("/links/:linkUUID/delete", handlers.LinkDeleteHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    216 	authGroup.POST("/api/v1/pgp/:linkPgpID/download", handlers.LinkPgpDownloadHandler)
    217 	authGroup.GET("/links/pgp/:linkPgpID/delete", handlers.LinkPgpDeleteHandler)
    218 	authGroup.POST("/links/pgp/:linkPgpID/delete", handlers.LinkPgpDeleteHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    219 	authGroup.GET("/links/mirrors/:linkMirrorID/delete", handlers.LinkMirrorDeleteHandler)
    220 	authGroup.POST("/links/mirrors/:linkMirrorID/delete", handlers.LinkMirrorDeleteHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    221 	authGroup.GET("/links/upload", handlers.LinksUploadHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    222 	authGroup.POST("/links/upload", handlers.LinksUploadHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    223 	authGroup.GET("/new-link", handlers.NewLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    224 	authGroup.POST("/new-link", handlers.NewLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    225 	authGroup.GET("/forum", handlers.ForumHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    226 	authGroup.GET("/forum/c/:categorySlug", handlers.ForumCategoryHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    227 	authGroup.GET("/forum/search", handlers.ForumSearchHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2))
    228 	authGroup.GET("/t/:threadUUID/edit", handlers.ThreadEditHandler)
    229 	authGroup.POST("/t/:threadUUID/edit", handlers.ThreadEditHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    230 	authGroup.GET("/t/:threadUUID/delete", handlers.ThreadDeleteHandler)
    231 	authGroup.POST("/t/:threadUUID/delete", handlers.ThreadDeleteHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    232 	authGroup.GET("/t/:threadUUID/reply", handlers.ThreadReplyHandler)
    233 	authGroup.POST("/t/:threadUUID/reply", handlers.ThreadReplyHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    234 	authGroup.GET("/t/:threadUUID/messages/:messageUUID/raw", handlers.ThreadRawMessageHandler)
    235 	authGroup.GET("/t/:threadUUID/messages/:messageUUID/edit", handlers.ThreadEditMessageHandler)
    236 	authGroup.POST("/t/:threadUUID/messages/:messageUUID/edit", handlers.ThreadEditMessageHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    237 	authGroup.GET("/t/:threadUUID/messages/:messageUUID/delete", handlers.ThreadDeleteMessageHandler)
    238 	authGroup.POST("/t/:threadUUID/messages/:messageUUID/delete", handlers.ThreadDeleteMessageHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    239 	authGroup.GET("/new-thread", handlers.NewThreadHandler)
    240 	authGroup.POST("/new-thread", handlers.NewThreadHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    241 	authGroup.GET("/red-room", handlers.RedRoomHandler)
    242 	authGroup.GET("/rooms", handlers.RoomsHandler)
    243 	authGroup.GET("/chat", handlers.ChatHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 4))
    244 	authGroup.POST("/chat", handlers.ChatHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    245 	authGroup.GET("/chat/help", handlers.ChatHelpHandler)
    246 	authGroup.GET("/chat-code/:messageUUID/:idx", handlers.ChatCodeHandler)
    247 	authGroup.GET("/chat/create-room", handlers.ChatCreateRoomHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    248 	authGroup.POST("/chat/create-room", handlers.ChatCreateRoomHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    249 	authGroup.GET("/chat/:roomName/stream", handlers.ChatStreamHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 4))
    250 	authGroup.GET("/chat/:roomName/archive", handlers.ChatArchiveHandler)
    251 	authGroup.GET("/chat/:roomName/delete", handlers.ChatDeleteHandler)
    252 	authGroup.POST("/chat/:roomName/delete", handlers.ChatDeleteHandler)
    253 	authGroup.GET("/chat/:roomName/settings", handlers.RoomChatSettingsHandler)
    254 	authGroup.POST("/chat/:roomName/settings", handlers.RoomChatSettingsHandler)
    255 	authGroup.GET("/external-link/:original", handlers.ExternalLink1Handler)
    256 	authGroup.GET("/external-link/:service/:original", handlers.ExternalLinkHandler)
    257 	moderatorGroup := e.Group("", middlewares.IsModeratorMiddleware)
    258 	moderatorGroup.POST("/api/v1/users/:userID/hellban", v1.UserHellbanHandler)
    259 	moderatorGroup.POST("/api/v1/users/:userID/unhellban", v1.UserUnHellbanHandler)
    260 	moderatorGroup.POST("/api/v1/users/:userID/kick", v1.KickHandler)
    261 	moderatorGroup.POST("/links/reindex", handlers.LinksReindexHandler)
    262 	moderatorGroup.GET("/forum/reindex", handlers.ForumReindexHandler)
    263 	moderatorGroup.GET("/settings/website", handlers.SettingsWebsiteHandler)
    264 	moderatorGroup.POST("/settings/website", handlers.SettingsWebsiteHandler)
    265 	moderatorGroup.GET("/settings/invitations", handlers.SettingsInvitationsHandler)
    266 	moderatorGroup.POST("/settings/invitations", handlers.SettingsInvitationsHandler)
    267 	adminGroup := e.Group("", middlewares.IsAdminMiddleware)
    268 	adminGroup.GET("/debug/*", echo.WrapHandler(http.DefaultServeMux))
    269 	adminGroup.GET("/admin", handlers.AdminHandler)
    270 	adminGroup.POST("/admin", handlers.AdminHandler)
    271 	adminGroup.GET("/admin/ignored", handlers.IgnoredHandler)
    272 	adminGroup.POST("/admin/ignored/delete", handlers.IgnoredDeleteHandler)
    273 	adminGroup.GET("/admin/sessions", handlers.SessionsHandler)
    274 	adminGroup.GET("/admin/backup", handlers.BackupHandler)
    275 	adminGroup.POST("/admin/backup", handlers.BackupHandler)
    276 	adminGroup.GET("/admin/poker-transactions", handlers.AdminPokerTransactionsHandler)
    277 	adminGroup.GET("/admin/poker-addresses", handlers.AdminPokerAddressesHandler)
    278 	adminGroup.GET("/admin/spam-filters", handlers.AdminSpamFiltersHandler)
    279 	adminGroup.POST("/admin/spam-filters", handlers.AdminSpamFiltersHandler)
    280 	adminGroup.GET("/admin/ddos", handlers.DdosHandler)
    281 	adminGroup.POST("/admin/ddos", handlers.DdosHandler)
    282 	adminGroup.GET("/admin/audits", handlers.AdminAuditsHandler)
    283 	adminGroup.POST("/admin/users/:userID/delete", handlers.AdminDeleteUserHandler)
    284 	adminGroup.GET("/admin/users/:userID/security-logs", handlers.AdminUserSecurityLogsHandler)
    285 	adminGroup.GET("/admin/users/:userID/edit", handlers.AdminEditUserHandler)
    286 	adminGroup.POST("/admin/users/:userID/edit", handlers.AdminEditUserHandler)
    287 	adminGroup.GET("/admin/captcha", handlers.AdminCaptchaHandler)
    288 	adminGroup.GET("/admin/rooms", handlers.AdminRoomsHandler)
    289 	adminGroup.GET("/admin/rooms/:roomID/edit", handlers.AdminEditRoomHandler)
    290 	adminGroup.POST("/admin/rooms/:roomID/edit", handlers.AdminEditRoomHandler)
    291 	adminGroup.POST("/admin/rooms/:roomID/delete", handlers.AdminDeleteRoomHandler)
    292 	adminGroup.GET("/admin/settings", handlers.AdminSettingsHandler)
    293 	adminGroup.POST("/admin/settings", handlers.AdminSettingsHandler)
    294 	adminGroup.GET("/admin/uploads", handlers.AdminUploadsHandler)
    295 	adminGroup.POST("/admin/uploads", handlers.AdminUploadsHandler)
    296 	adminGroup.GET("/admin/filedrops", handlers.AdminFiledropsHandler)
    297 	adminGroup.POST("/admin/filedrops", handlers.AdminFiledropsHandler)
    298 	adminGroup.GET("/admin/file-drop/:filename", handlers.FiledropDownloadHandler)
    299 	adminGroup.GET("/admin/downloads", handlers.AdminDownloadsHandler)
    300 	adminGroup.POST("/admin/downloads/:downloadID/delete", handlers.AdminDeleteDownloadHandler)
    301 	adminGroup.GET("/admin/gists", handlers.AdminGistsHandler)
    302 	adminGroup.GET("/admin/gists/new", handlers.AdminNewGistHandler)
    303 	adminGroup.POST("/admin/gists/new", handlers.AdminNewGistHandler)
    304 	adminGroup.GET("/admin/gists/:gistUUID/edit", handlers.AdminEditGistHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    305 	adminGroup.POST("/admin/gists/:gistUUID/edit", handlers.AdminEditGistHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    306 	adminGroup.GET("/admin/stream-users", handlers.StreamUsersHandler)
    307 	clubGroup := authGroup.Group("", middlewares.ClubMiddleware)
    308 	clubGroup.GET("/club", handlers.ClubHandler)
    309 	clubGroup.GET("/club/threads/:threadID", handlers.ClubThreadHandler)
    310 	clubGroup.GET("/club/threads/:threadID/reply", handlers.ClubThreadReplyHandler)
    311 	clubGroup.POST("/club/threads/:threadID/reply", handlers.ClubThreadReplyHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    312 	clubGroup.GET("/club/threads/:threadID/messages/:messageID/edit", handlers.ClubThreadEditMessageHandler)
    313 	clubGroup.POST("/club/threads/:threadID/messages/:messageID/edit", handlers.ClubThreadEditMessageHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    314 	clubGroup.POST("/api/v1/club/messages/:messageID/delete", v1.ClubDeleteMessageHandler)
    315 	clubGroup.GET("/club/new-thread", handlers.ClubNewThreadHandler)
    316 	clubGroup.POST("/club/new-thread", handlers.ClubNewThreadHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2))
    317 	clubGroup.GET("/club/members", handlers.ClubMembersHandler)
    318 	vipGroup := authGroup.Group("", middlewares.VipMiddleware)
    319 	vipGroup.GET("/vip", handlers.VipHandler)
    320 	vipGroup.GET("/vip/challenges/stego1", handlers.Stego1ChallengeHandler)
    321 	vipGroup.POST("/vip/challenges/stego1", handlers.Stego1ChallengeHandler)
    322 	vipGroup.GET("/vip/challenges/forgot-password-bypass", handlers.ForgotPasswordBypassChallengeHandler)
    323 	vipGroup.GET("/vip/challenges/byte-road", handlers.ByteRoadChallengeHandler, middlewares.AuthRateLimitMiddleware(1*time.Minute, 500))
    324 	vipGroup.POST("/vip/challenges/byte-road", handlers.ByteRoadChallengeHandler, middlewares.AuthRateLimitMiddleware(1*time.Minute, 500))
    325 	vipGroup.GET("/vip/challenges/re-1", handlers.VipDownloadsHandler)
    326 	vipGroup.POST("/vip/challenges/re-1", handlers.VipDownloadsHandler)
    327 	vipGroup.GET("/vip/challenges/re-1/:filename", handlers.VipDownloadFileHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2), middlewares.CaptchaMiddleware())
    328 	vipGroup.POST("/vip/challenges/re-1/:filename", handlers.VipDownloadFileHandler, middlewares.AuthRateLimitMiddleware(1*time.Second, 2), middlewares.CaptchaMiddleware())
    329 	vipGroup.GET("/vip/projects", handlers.VipProjectsHandler)
    330 	vipGroup.GET("/vip/projects/ip-grabber", handlers.VipProjectsIPGrabberHandler)
    331 	vipGroup.GET("/vip/projects/malware-dropper", handlers.VipProjectsMalwareDropperHandler)
    332 	vipGroup.GET("/vip/projects/rust-ransomware", handlers.VipProjectsRustRansomwareHandler)
    333 
    334 	return func(c echo.Context) error {
    335 		e.ServeHTTP(c.Response(), c.Request())
    336 		return nil
    337 	}
    338 }
    339 
    340 func getBaseServer(db *database.DkfDB, clientFE clientFrontends.ClientFrontend) *echo.Echo {
    341 	e := newEcho()
    342 	renderer := tmp.GetRenderer(e)
    343 	i18nBundle := getI18nBundle()
    344 	e.Renderer = renderer
    345 	e.Use(middlewares.SetUselessHeadersMiddleware)
    346 	e.GET("/file-drop/:uuid", handlers.FileDropHandler, middlewares.SetDatabaseMiddleware(db), middlewares.I18nMiddleware(i18nBundle, "en"))
    347 	e.POST("/file-drop/:uuid", handlers.FileDropHandler, middlewares.SetDatabaseMiddleware(db), middlewares.I18nMiddleware(i18nBundle, "en"))
    348 	e.POST("/file-drop/:uuid/dkfupload", handlers.FileDropDkfUploadHandler, middlewares.SetDatabaseMiddleware(db), middlewares.I18nMiddleware(i18nBundle, "en"))
    349 	e.POST("/api/v1/file-drop/:uuid/dkfdownload", handlers.FileDropDkfDownloadHandler, middlewares.SetDatabaseMiddleware(db), middlewares.I18nMiddleware(i18nBundle, "en"), middlewares.SetUserMiddleware, middlewares.IsAuthMiddleware)
    350 	e.GET("/downloads/:fileName", handlers.FileDropDownloadHandler, middlewares.SetDatabaseMiddleware(db), middlewares.I18nMiddleware(i18nBundle, "en"), middlewares.SetUserMiddleware)
    351 	e.POST("/downloads/:fileName", handlers.FileDropDownloadHandler, middlewares.SetDatabaseMiddleware(db), middlewares.I18nMiddleware(i18nBundle, "en"), middlewares.SetUserMiddleware)
    352 	e.Any("*", getMainServer(db, i18nBundle, renderer, clientFE))
    353 	return e
    354 }
    355 
    356 func getSubdomainServer(db *database.DkfDB, clientFE clientFrontends.ClientFrontend) *echo.Echo {
    357 	rp := getReverseProxy(config.GogsURL)
    358 	be := getBaseServer(db, clientFE)
    359 	e := newEcho()
    360 	e.Any("*", func(c echo.Context) error {
    361 		res := c.Response()
    362 		req := c.Request()
    363 		host := req.Host
    364 		hostParts := strings.SplitN(host, ".", 2)
    365 		if hostParts[0] == "git" {
    366 			rp.ServeHTTP(res, req)
    367 			return nil
    368 		}
    369 		be.ServeHTTP(res, req)
    370 		return nil
    371 	})
    372 	return e
    373 }
    374 
    375 func getI2pServer(db *database.DkfDB) *echo.Echo {
    376 	if config.Development.IsTrue() {
    377 		return nil
    378 	}
    379 	return getSubdomainServer(db, clientFrontends.I2PClientFE)
    380 }
    381 
    382 func getTorServer(db *database.DkfDB) *echo.Echo {
    383 	e := getSubdomainServer(db, clientFrontends.TorClientFE)
    384 	configTorProdServer(e)
    385 	return e
    386 }
    387 
    388 // Start ...
    389 func Start(db *database.DkfDB, host string, port int) {
    390 	// Server for Tor/dev
    391 	e1 := getTorServer(db)
    392 	// Start server for I2P
    393 	e2 := getI2pServer(db)
    394 
    395 	serverError1 := make(chan struct{})
    396 	serverError2 := make(chan struct{})
    397 
    398 	utils.SGo(func() {
    399 		address := host + ":" + strconv.Itoa(port)
    400 		logrus.Info("start tor server on " + address)
    401 		if err := e1.Start(address); err != nil {
    402 			if err != http.ErrServerClosed {
    403 				logrus.Error(err)
    404 			}
    405 			close(serverError1)
    406 		}
    407 	})
    408 
    409 	utils.SGo(func() {
    410 		if e2 != nil {
    411 			address := host + ":" + strconv.Itoa(port+1)
    412 			logrus.Info("start i2p server on " + address)
    413 			if err := e2.Start(address); err != nil {
    414 				if err != http.ErrServerClosed {
    415 					logrus.Error(err)
    416 				}
    417 				close(serverError2)
    418 			}
    419 		}
    420 	})
    421 
    422 	// Wait for interrupt signal to gracefully shutdown the server with
    423 	// a timeout of 10 seconds.
    424 	quit := make(chan os.Signal)
    425 	signal.Notify(quit, os.Interrupt)
    426 	select {
    427 	case <-quit:
    428 	case <-serverError1:
    429 	case <-serverError2:
    430 	}
    431 
    432 	logrus.Info("graceful shutdown")
    433 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    434 	defer cancel()
    435 	if err := e1.Shutdown(ctx); err != nil {
    436 		logrus.Errorf("tor graceful shutdown failed: %s", err.Error())
    437 	}
    438 
    439 	if e2 != nil {
    440 		ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second)
    441 		defer cancel()
    442 		if err := e2.Shutdown(ctx); err != nil {
    443 			logrus.Errorf("i2p graceful shutdown failed: %s", err.Error())
    444 		}
    445 	}
    446 
    447 	logrus.Info("Bye!")
    448 }
    449 
    450 func extractGlobalCircuitIdentifier(m string) int64 {
    451 	// You can compute the global circuit identifier using the following formula given the IPv6 address "fc00:dead:beef:4dad::AABB:CCDD":
    452 	// global_circuit_id = (0xAA << 24) + (0xBB << 16) + (0xCC << 8) + 0xDD;
    453 	s1 := strings.Split(m, "::")[1]
    454 	s2 := strings.Split(s1, ":")
    455 	aabb := fmt.Sprintf("%04s", s2[0])
    456 	ccdd := fmt.Sprintf("%04s", s2[1])
    457 	aa, _ := strconv.ParseInt(aabb[0:2], 16, 64)
    458 	bb, _ := strconv.ParseInt(aabb[2:4], 16, 64)
    459 	cc, _ := strconv.ParseInt(ccdd[0:2], 16, 64)
    460 	dd, _ := strconv.ParseInt(ccdd[2:4], 16, 64)
    461 	globalCircuitID := (aa << 24) + (bb << 16) + (cc << 8) + dd
    462 	return globalCircuitID
    463 }
    464 
    465 func getReverseProxy(u string) *httputil.ReverseProxy {
    466 	remote, err := url.Parse(u)
    467 	if err != nil {
    468 		panic(err)
    469 	}
    470 	reverseProxy := httputil.NewSingleHostReverseProxy(remote)
    471 	reverseProxy.FlushInterval = 1000 * time.Millisecond
    472 	reverseProxy.ErrorHandler = func(w http.ResponseWriter, req *http.Request, e error) {
    473 		if e.Error() != "context canceled" {
    474 			logrus.Error(e.Error())
    475 		}
    476 		w.WriteHeader(http.StatusBadGateway)
    477 	}
    478 	return reverseProxy
    479 }
    480 
    481 func newEcho() *echo.Echo {
    482 	e := echo.New()
    483 	e.HideBanner = true
    484 	e.HidePort = true
    485 	e.Debug = true
    486 	return e
    487 }
    488 
    489 func configTorProdServer(e *echo.Echo) {
    490 	if config.Development.IsTrue() {
    491 		return
    492 	}
    493 	rate := limiter.Rate{Period: 5 * time.Second, Limit: 25}
    494 	store := memory.NewStore()
    495 	limiterInstance := limiter.New(store, rate)
    496 
    497 	var haproxyRgx = regexp.MustCompile(`PROXY TCP6 (\S+)`)
    498 	e.Server.ConnState = func(conn net.Conn, state http.ConnState) {
    499 		if state == http.StateNew {
    500 			buf := make([]byte, 1024)
    501 			_, err := conn.Read(buf)
    502 			if err != nil {
    503 				return
    504 			}
    505 			m := haproxyRgx.FindStringSubmatch(string(buf))
    506 			if len(m) == 2 {
    507 				globalCircuitID := extractGlobalCircuitIdentifier(m[1])
    508 				config.ConnMap.Set(conn, globalCircuitID)
    509 
    510 				limiterCtx, _ := limiterInstance.Get(context.Background(), utils.FormatInt64(globalCircuitID))
    511 				if limiterCtx.Reached {
    512 					config.ConnMap.CloseCircuit(globalCircuitID)
    513 				}
    514 			}
    515 		} else if state == http.StateClosed {
    516 			config.ConnMap.Delete(conn)
    517 		}
    518 	}
    519 	e.Server.ConnContext = func(ctx context.Context, c net.Conn) context.Context {
    520 		return context.WithValue(ctx, "conn", c)
    521 	}
    522 
    523 	// Open a tcp connection to each of tor process & authenticate
    524 	servers := []string{"127.0.0.1:6668"}
    525 	conns := make([]net.Conn, 0)
    526 	for _, server := range servers {
    527 		conn1, err := net.Dial("tcp", server)
    528 		if err != nil {
    529 			logrus.Errorf("failed to connect to tor port %s : %v", server, err)
    530 		}
    531 		_, _ = conn1.Write([]byte("AUTHENTICATE \"\"\n"))
    532 		buf := make([]byte, 1024)
    533 		n, _ := conn1.Read(buf)
    534 		fmt.Println("AUTHENTICATE", strings.TrimSpace(string(buf[0:n])))
    535 		conns = append(conns, conn1)
    536 	}
    537 	// Listen for circuit to close
    538 	go func() {
    539 		for circuitID := range config.ConnMap.CircuitIDCh {
    540 			res := ""
    541 			for _, conn := range conns {
    542 				_, _ = fmt.Fprintf(conn, "CLOSECIRCUIT %d\n", circuitID)
    543 				buf1 := make([]byte, 1024)
    544 				n1, _ := conn.Read(buf1)
    545 				res += " : " + strings.TrimSpace(string(buf1[0:n1]))
    546 			}
    547 			logrus.Warnf("CLOSECIRCUIT %d -> %s", circuitID, res)
    548 		}
    549 	}()
    550 }
    551 
    552 func getI18nBundle() *i18n.Bundle {
    553 	bundle := i18n.NewBundle(language.English)
    554 	bundle.RegisterUnmarshalFunc("yaml", yaml.Unmarshal)
    555 	dir, _ := config.LocalsFs.ReadDir(".")
    556 	fileNames := make([]string, 0)
    557 	for _, d := range dir {
    558 		fileNames = append(fileNames, d.Name())
    559 	}
    560 	for _, fileName := range fileNames {
    561 		if strings.HasSuffix(fileName, ".yaml") && !strings.HasSuffix(fileName, "sample.yaml") {
    562 			if _, err := bundle.ParseMessageFileBytes(utils.Must(config.LocalsFs.ReadFile(fileName)), fileName); err != nil {
    563 				logrus.Errorf("failed to parse %s : %s", fileName, err.Error())
    564 			}
    565 		}
    566 	}
    567 
    568 	if err := utils.LoadLocals(bundle); err != nil {
    569 		logrus.Fatal(err)
    570 	}
    571 	return bundle
    572 }