commit 2deda54d412f8d2b9e170901542cceda7781725b
parent ea5318ae9b2a8642a4786496fa5a9f6b46314942
Author: n0tr1v <n0tr1v@protonmail.com>
Date: Sat, 10 Jun 2023 22:49:34 -0700
option to confirm before opening external links
Diffstat:
10 files changed, 57 insertions(+), 5 deletions(-)
diff --git a/cmd/dkf/migrations/140.sql b/cmd/dkf/migrations/140.sql
@@ -0,0 +1,4 @@
+-- +migrate Up
+ALTER TABLE users ADD COLUMN confirm_external_links TINYINT(1) NOT NULL DEFAULT 0;
+
+-- +migrate Down
diff --git a/pkg/database/tableChatMessages.go b/pkg/database/tableChatMessages.go
@@ -11,6 +11,7 @@ import (
"fmt"
"io"
"math"
+ "net/url"
"regexp"
"strings"
"time"
@@ -255,11 +256,25 @@ func (m *ChatMessage) TrimMe() string {
return "<p>" + strings.TrimPrefix(m.Message, "<p>/me ")
}
-func (m *ChatMessage) MsgToDisplay() string {
+var externalLinkRgx = regexp.MustCompile(`<a href="([^"]+)" rel="noopener noreferrer" target="_blank">`)
+
+func (m *ChatMessage) MsgToDisplay(authUser *User) string {
+ var msg string
if m.IsMe() {
- return m.TrimMe()
+ msg = m.TrimMe()
+ } else {
+ msg = m.Message
}
- return m.Message
+ if authUser.ConfirmExternalLinks {
+ msg = externalLinkRgx.ReplaceAllStringFunc(msg, func(s string) string {
+ original := externalLinkRgx.FindStringSubmatch(s)[1]
+ if strings.HasPrefix(original, "/external-link/") {
+ return s
+ }
+ return `<a href="/external-link/` + url.PathEscape(original) + `" rel="noopener noreferrer" target="_blank">`
+ })
+ }
+ return msg
}
func (m *ChatMessage) Delete(db *DkfDB) error {
diff --git a/pkg/database/tableUsers.go b/pkg/database/tableUsers.go
@@ -118,6 +118,7 @@ type User struct {
AFK bool
UseStream bool
SyntaxHighlightCode string
+ ConfirmExternalLinks bool
HighlightOwnMessages bool `gorm:"-"`
}
diff --git a/pkg/web/handlers/api/v1/messages.qtpl b/pkg/web/handlers/api/v1/messages.qtpl
@@ -419,7 +419,7 @@
{%- endif -%}
{%- endif -%}
{%- endif -%}
- <span {%= unesc(e.User.GenerateChatStyle()) %}><span class="o-wrap">{%s= unesc(e.MsgToDisplay()) %}</span></span>
+ <span {%= unesc(e.User.GenerateChatStyle()) %}><span class="o-wrap">{%s= unesc(e.MsgToDisplay(AuthUser)) %}</span></span>
{%- endif -%}
</div>
{%- endif -%}
diff --git a/pkg/web/handlers/api/v1/messages.qtpl.go b/pkg/web/handlers/api/v1/messages.qtpl.go
@@ -1109,7 +1109,7 @@ func StreamRenderMessage(qw422016 *qt422016.Writer, idx int, e database.ChatMess
//line messages.qtpl:422
qw422016.N().S(`><span class="o-wrap">`)
//line messages.qtpl:422
- qw422016.N().S(unesc(e.MsgToDisplay()))
+ qw422016.N().S(unesc(e.MsgToDisplay(AuthUser)))
//line messages.qtpl:422
qw422016.N().S(`</span></span>
`)
diff --git a/pkg/web/handlers/data.go b/pkg/web/handlers/data.go
@@ -672,6 +672,7 @@ type settingsChatData struct {
DisplayKickButton bool
DisplayHellbanButton bool
UseStream bool
+ ConfirmExternalLinks bool
NotifyChessGames bool
NotifyChessMove bool
NotifyNewMessage bool
@@ -926,3 +927,7 @@ type chessData struct {
type powHelperData struct {
Difficulty int64
}
+
+type externalLink1Data struct {
+ Link string
+}
diff --git a/pkg/web/handlers/handlers.go b/pkg/web/handlers/handlers.go
@@ -2448,6 +2448,13 @@ func RoomChatSettingsHandler(c echo.Context) error {
return c.Render(http.StatusOK, "chat-room-settings", data)
}
+func ExternalLink1Handler(c echo.Context) error {
+ original, _ := url.PathUnescape(c.Param("original"))
+ var data externalLink1Data
+ data.Link = original
+ return c.Render(http.StatusOK, "external-link1", data)
+}
+
func ExternalLinkHandler(c echo.Context) error {
service := c.Param("service")
original, _ := url.PathUnescape(c.Param("original"))
@@ -2565,6 +2572,7 @@ func SettingsChatHandler(c echo.Context) error {
data.NotifyChessGames = authUser.NotifyChessGames
data.NotifyChessMove = authUser.NotifyChessMove
data.UseStream = authUser.UseStream
+ data.ConfirmExternalLinks = authUser.ConfirmExternalLinks
if c.Request().Method == http.MethodGet {
return c.Render(http.StatusOK, "settings.chat", data)
@@ -3211,6 +3219,7 @@ func changeSettingsForm(c echo.Context, data settingsChatData) error {
data.NotifyChessGames = utils.DoParseBool(c.Request().PostFormValue("notify_chess_games"))
data.NotifyChessMove = utils.DoParseBool(c.Request().PostFormValue("notify_chess_move"))
data.UseStream = utils.DoParseBool(c.Request().PostFormValue("use_stream"))
+ data.ConfirmExternalLinks = utils.DoParseBool(c.Request().PostFormValue("confirm_external_links"))
data.HellbanOpacity = utils.DoParseF64(c.Request().PostFormValue("hellban_opacity"))
data.CodeBlockHeight = utils.DoParseInt64(c.Request().PostFormValue("code_block_height"))
//data.NotifyNewMessageSound = utils.DoParseInt64(c.Request().PostFormValue("notify_new_message_sound"))
@@ -3254,6 +3263,7 @@ func changeSettingsForm(c echo.Context, data settingsChatData) error {
authUser.NotifyChessGames = data.NotifyChessGames
authUser.NotifyChessMove = data.NotifyChessMove
authUser.UseStream = data.UseStream
+ authUser.ConfirmExternalLinks = data.ConfirmExternalLinks
authUser.Theme = data.Theme
//authUser.NotifyNewMessageSound = data.NotifyNewMessageSound
//authUser.NotifyTaggedSound = data.NotifyTaggedSound
diff --git a/pkg/web/public/views/pages/external-link1.gohtml b/pkg/web/public/views/pages/external-link1.gohtml
@@ -0,0 +1,8 @@
+{{ define "content" }}
+<div class="container">
+ Navigate to external link:
+ <div>
+ <a href="{{ .Data.Link }}">{{ .Data.Link }}</a>
+ </div>
+</div>
+{{ end }}
+\ No newline at end of file
diff --git a/pkg/web/public/views/pages/settings/chat.gohtml b/pkg/web/public/views/pages/settings/chat.gohtml
@@ -194,6 +194,13 @@
</div>
<label class="form-check-label" for="use_stream">{{ t "Use chat stream version" . }}</label>
</div>
+ <div class="form-check form-check-1">
+ <div class="checkbox-wrapper form-check-input">
+ <input class="my-cbx" type="checkbox" name="confirm_external_links" id="confirm_external_links" value="1"{{ if .AuthUser.ConfirmExternalLinks }} checked{{ end }} />
+ <label for="confirm_external_links" class="toggle"><span></span></label>
+ </div>
+ <label class="form-check-label" for="confirm_external_links">Confirm before opening external links</label>
+ </div>
{{ if $.AuthUser.IsModerator }}
<div class="form-check form-check-1">
<div class="checkbox-wrapper form-check-input">
diff --git a/pkg/web/web.go b/pkg/web/web.go
@@ -229,6 +229,7 @@ func getMainServer(db *database.DkfDB, i18nBundle *i18n.Bundle, renderer *tmp.Te
authGroup.POST("/chat/:roomName/delete", handlers.ChatDeleteHandler)
authGroup.GET("/chat/:roomName/settings", handlers.RoomChatSettingsHandler)
authGroup.POST("/chat/:roomName/settings", handlers.RoomChatSettingsHandler)
+ authGroup.GET("/external-link/:original", handlers.ExternalLink1Handler)
authGroup.GET("/external-link/:service/:original", handlers.ExternalLinkHandler)
moderatorGroup := e.Group("", middlewares.IsModeratorMiddleware)
moderatorGroup.POST("/api/v1/users/:userID/hellban", v1.UserHellbanHandler)