Fix webmention

This commit is contained in:
Jan-Lukas Else 2022-03-28 18:02:16 +02:00
parent 6c115b1491
commit c38c5e8ed9
8 changed files with 48 additions and 22 deletions

View File

@ -67,13 +67,14 @@ func (a *goBlog) openDatabase(file string, logging bool) (*database, error) {
ConnectHook: func(c *sqlite.SQLiteConn) error { ConnectHook: func(c *sqlite.SQLiteConn) error {
// Register functions // Register functions
for n, f := range map[string]any{ for n, f := range map[string]any{
"mdtext": a.renderText, "mdtext": a.renderText,
"tolocal": toLocalSafe, "tolocal": toLocalSafe,
"toutc": toUTCSafe, "toutc": toUTCSafe,
"wordcount": wordCount, "wordcount": wordCount,
"charcount": charCount, "charcount": charCount,
"urlize": urlize, "urlize": urlize,
"lowerx": strings.ToLower, "lowerx": strings.ToLower,
"lowerunescaped": lowerUnescapedPath,
} { } {
if err := c.RegisterFunc(n, f, true); err != nil { if err := c.RegisterFunc(n, f, true); err != nil {
return err return err

2
go.mod
View File

@ -57,7 +57,7 @@ require (
// master // master
github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38 github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064
golang.org/x/net v0.0.0-20220225172249-27dd8689420f golang.org/x/net v0.0.0-20220325170049-de3da57026de
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/text v0.3.7 golang.org/x/text v0.3.7
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b

4
go.sum
View File

@ -575,8 +575,8 @@ golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= golang.org/x/net v0.0.0-20220325170049-de3da57026de h1:pZB1TWnKi+o4bENlbzAgLrEbY4RMYmUIRobMcSmfeYc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=

View File

@ -116,6 +116,10 @@ func unescapedPath(p string) string {
return p return p
} }
func lowerUnescapedPath(p string) string {
return strings.ToLower(unescapedPath(p))
}
type stringGroup struct { type stringGroup struct {
Identifier string Identifier string
Strings []string Strings []string

View File

@ -134,3 +134,13 @@ func Test_matchTimeDiffLocale(t *testing.T) {
assert.Equal(t, "pt", string(matchTimeDiffLocale("pt-BR"))) assert.Equal(t, "pt", string(matchTimeDiffLocale("pt-BR")))
assert.Equal(t, "pt", string(matchTimeDiffLocale("pt"))) assert.Equal(t, "pt", string(matchTimeDiffLocale("pt")))
} }
func Test_unescapedPath(t *testing.T) {
assert.Equal(t, "/de/posts/fahrradanhänger", unescapedPath("/de/posts/fahrradanh%C3%A4nger"))
assert.Equal(t, "/de/posts/fahrradanhänger", unescapedPath("/de/posts/fahrradanhänger"))
}
func Test_lowerUnescaptedPath(t *testing.T) {
assert.Equal(t, "/de/posts/fahrradanhänger", lowerUnescapedPath("/de/posts/fahrradanh%C3%84nger"))
assert.Equal(t, "/de/posts/fahrradanhänger", lowerUnescapedPath("/de/posts/fahrradanhÄnger"))
}

View File

@ -89,7 +89,7 @@ func (a *goBlog) extractMention(r *http.Request) (*mention, error) {
return nil, err return nil, err
} }
source := r.Form.Get("source") source := r.Form.Get("source")
target := unescapedPath(r.Form.Get("target")) target := r.Form.Get("target")
if source == "" || target == "" || !isAbsoluteURL(source) || !isAbsoluteURL(target) { if source == "" || target == "" || !isAbsoluteURL(source) || !isAbsoluteURL(target) {
a.debug("Invalid webmention request, source:", source, "target:", target) a.debug("Invalid webmention request, source:", source, "target:", target)
return nil, errors.New("invalid request") return nil, errors.New("invalid request")
@ -109,8 +109,8 @@ func (db *database) webmentionExists(m *mention) bool {
select 1 select 1
from webmentions from webmentions
where where
lowerx(source) in (lowerx(@source), lowerx(@newsource)) lowerunescaped(source) in (lowerunescaped(@source), lowerunescaped(@newsource))
and lowerx(target) in (lowerx(@target), lowerx(@newtarget)) and lowerunescaped(target) in (lowerunescaped(@target), lowerunescaped(@newtarget))
) )
`, `,
sql.Named("source", m.Source), sql.Named("newsource", defaultIfEmpty(m.NewSource, m.Source)), sql.Named("source", m.Source), sql.Named("newsource", defaultIfEmpty(m.NewSource, m.Source)),
@ -128,7 +128,7 @@ func (db *database) webmentionExists(m *mention) bool {
func (a *goBlog) createWebmention(source, target string) (err error) { func (a *goBlog) createWebmention(source, target string) (err error) {
return a.queueMention(&mention{ return a.queueMention(&mention{
Source: source, Source: source,
Target: unescapedPath(target), Target: target,
Created: time.Now().Unix(), Created: time.Now().Unix(),
}) })
} }
@ -137,7 +137,7 @@ func (db *database) insertWebmention(m *mention, status webmentionStatus) error
_, err := db.exec( _, err := db.exec(
` `
insert into webmentions (source, target, url, created, status, title, content, author) insert into webmentions (source, target, url, created, status, title, content, author)
values (@source, @target, @url, @created, @status, @title, @content, @author) values (@source, lowerunescaped(@target), @url, @created, @status, @title, @content, @author)
`, `,
sql.Named("source", m.Source), sql.Named("source", m.Source),
sql.Named("target", m.Target), sql.Named("target", m.Target),
@ -156,15 +156,15 @@ func (db *database) updateWebmention(m *mention, newStatus webmentionStatus) err
update webmentions update webmentions
set set
source = @newsource, source = @newsource,
target = @newtarget, target = lowerunescaped(@newtarget),
url = @url, url = @url,
status = @status, status = @status,
title = @title, title = @title,
content = @content, content = @content,
author = @author author = @author
where where
lowerx(source) in (lowerx(@source), lowerx(@newsource2)) lowerunescaped(source) in (lowerunescaped(@source), lowerunescaped(@newsource2))
and lowerx(target) in (lowerx(@target), lowerx(@newtarget2)) and lowerunescaped(target) in (lowerunescaped(@target), lowerunescaped(@newtarget2))
`, `,
sql.Named("newsource", defaultIfEmpty(m.NewSource, m.Source)), sql.Named("newsource", defaultIfEmpty(m.NewSource, m.Source)),
sql.Named("newtarget", defaultIfEmpty(m.NewTarget, m.Target)), sql.Named("newtarget", defaultIfEmpty(m.NewTarget, m.Target)),
@ -188,7 +188,7 @@ func (db *database) deleteWebmentionId(id int) error {
func (db *database) deleteWebmention(m *mention) error { func (db *database) deleteWebmention(m *mention) error {
_, err := db.exec( _, err := db.exec(
"delete from webmentions where lowerx(source) in (lowerx(@source), lowerx(@newsource)) and lowerx(target) in (lowerx(@target), lowerx(@newtarget))", "delete from webmentions where lowerunescaped(source) in (lowerunescaped(@source), lowerunescaped(@newsource)) and lowerunescaped(target) in (lowerunescaped(@target), lowerunescaped(@newtarget))",
sql.Named("source", m.Source), sql.Named("source", m.Source),
sql.Named("newsource", defaultIfEmpty(m.NewSource, m.Source)), sql.Named("newsource", defaultIfEmpty(m.NewSource, m.Source)),
sql.Named("target", m.Target), sql.Named("target", m.Target),
@ -233,7 +233,7 @@ func buildWebmentionsQuery(config *webmentionsRequestConfig) (query string, args
if config != nil { if config != nil {
queryBuilder.WriteString("where 1") queryBuilder.WriteString("where 1")
if config.target != "" { if config.target != "" {
queryBuilder.WriteString(" and lowerx(target) = lowerx(@target)") queryBuilder.WriteString(" and lowerunescaped(target) = lowerunescaped(@target)")
args = append(args, sql.Named("target", config.target)) args = append(args, sql.Named("target", config.target))
} }
if config.status != "" { if config.status != "" {
@ -241,7 +241,7 @@ func buildWebmentionsQuery(config *webmentionsRequestConfig) (query string, args
args = append(args, sql.Named("status", config.status)) args = append(args, sql.Named("status", config.status))
} }
if config.sourcelike != "" { if config.sourcelike != "" {
queryBuilder.WriteString(" and lowerx(source) like ('%' || lowerx(@sourcelike) || '%')") queryBuilder.WriteString(" and lowerunescaped(source) like ('%' || lowerunescaped(@sourcelike) || '%')")
args = append(args, sql.Named("sourcelike", config.sourcelike)) args = append(args, sql.Named("sourcelike", config.sourcelike))
} }
if config.id != 0 { if config.id != 0 {

View File

@ -180,7 +180,7 @@ func (a *goBlog) verifyReader(m *mention, body io.Reader) error {
return false return false
} }
_ = resp.Body.Close() _ = resp.Body.Close()
if resp.StatusCode == http.StatusOK && unescapedPath(resp.Request.URL.String()) == unescapedPath(defaultIfEmpty(m.NewTarget, m.Target)) { if resp.StatusCode == http.StatusOK && lowerUnescapedPath(resp.Request.URL.String()) == lowerUnescapedPath(defaultIfEmpty(m.NewTarget, m.Target)) {
return true return true
} }
return false return false

View File

@ -73,4 +73,15 @@ func Test_webmentions(t *testing.T) {
mentions = app.db.getWebmentionsByAddress("https://example.com/täst") mentions = app.db.getWebmentionsByAddress("https://example.com/täst")
assert.Len(t, mentions, 1) assert.Len(t, mentions, 1)
mentions = app.db.getWebmentionsByAddress("https://example.com/t%C3%A4st")
assert.Len(t, mentions, 1)
app.db.deleteWebmention(&mention{
Source: "https://example.net/test",
Target: "https://example.com/T%C3%84ST",
})
mentions = app.db.getWebmentionsByAddress("https://example.com/täst")
assert.Len(t, mentions, 0)
} }