package matrix import ( "fmt" "html" "net/url" "strings" ) // safeHref returns raw if it is an http(s) URL, else "". Keeps feed-supplied // links from injecting javascript:/data: schemes into the formatted_body href // (html.EscapeString blocks attribute breakout but not the scheme itself). func safeHref(raw string) string { u, err := url.Parse(strings.TrimSpace(raw)) if err != nil || (u.Scheme != "http" && u.Scheme != "https") { return "" } return raw } // PostableStory contains the data needed to format and send a story. type PostableStory struct { ImageURL string Headline string ArticleURL string Lede string Source string Channel string Platforms []string } // formatPost returns plain text and HTML bodies for a Matrix message. func formatPost(s *PostableStory) (plain, htmlBody string) { // Plain text body var plainParts []string plainParts = append(plainParts, fmt.Sprintf("**%s** \u2192 %s", s.Headline, s.ArticleURL)) if s.Lede != "" { plainParts = append(plainParts, s.Lede) } plainParts = append(plainParts, formatSourceTag(s.Source, s.Platforms, false)) plain = strings.Join(plainParts, "\n") // HTML body var htmlParts []string if href := safeHref(s.ArticleURL); href != "" { htmlParts = append(htmlParts, fmt.Sprintf( `%s`, html.EscapeString(href), html.EscapeString(s.Headline), )) } else { // Non-http(s) link: render the headline without an anchor. htmlParts = append(htmlParts, fmt.Sprintf(`%s`, html.EscapeString(s.Headline))) } if s.Lede != "" { htmlParts = append(htmlParts, html.EscapeString(s.Lede)) } htmlParts = append(htmlParts, formatSourceTag(s.Source, s.Platforms, true)) htmlBody = strings.Join(htmlParts, "
") return plain, htmlBody } // formatSourceTag builds the source + platform tags line. func formatSourceTag(source string, platforms []string, isHTML bool) string { if isHTML { parts := []string{fmt.Sprintf("%s", html.EscapeString(strings.ToLower(source)))} for _, p := range platforms { parts = append(parts, fmt.Sprintf("%s", html.EscapeString(p))) } return strings.Join(parts, " \u00b7 ") } parts := []string{fmt.Sprintf("`%s`", strings.ToLower(source))} for _, p := range platforms { parts = append(parts, fmt.Sprintf("`%s`", p)) } return strings.Join(parts, " \u00b7 ") }