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) } if tag := formatSourceTag(s.Source, s.Platforms, false); tag != "" { plainParts = append(plainParts, tag) } 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)) } if tag := formatSourceTag(s.Source, s.Platforms, true); tag != "" { htmlParts = append(htmlParts, tag) } htmlBody = strings.Join(htmlParts, "
") return plain, htmlBody } // formatSourceTag builds the source + platform tags line. An empty source is // omitted rather than tagged: Pete's own reporting has no outlet to credit, and // an empty tag would read as him signing his own name. func formatSourceTag(source string, platforms []string, isHTML bool) string { var parts []string if source != "" { parts = append(parts, strings.ToLower(source)) } parts = append(parts, platforms...) if len(parts) == 0 { return "" } for i, p := range parts { if isHTML { parts[i] = fmt.Sprintf("%s", html.EscapeString(p)) } else { parts[i] = fmt.Sprintf("`%s`", p) } } return strings.Join(parts, " \u00b7 ") }