Skip to content

Commit

Permalink
Email: Mark HTML comments as "safe" in email templates (grafana#64546)
Browse files Browse the repository at this point in the history
  • Loading branch information
gillesdemey authored Mar 28, 2023
1 parent 48f5825 commit ed82f96
Show file tree
Hide file tree
Showing 13 changed files with 304 additions and 255 deletions.
14 changes: 9 additions & 5 deletions emails/Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
build: build-html build-txt
build: clean build-mjml build-grunt

build-html:
clean:
rm -rf dist/
mkdir dist/

build-mjml:
npx mjml \
--config.beautify true \
--config.minify false \
--config.validationLevel=strict \
--config.keepComments=false \
./templates/*.mjml --output ../public/emails/
./templates/*.mjml --output ./dist/

build-txt:
build-grunt:
npx grunt

.PHONY: build build-html build-txt
.PHONY: clean build build-mjml build-grunt
1 change: 0 additions & 1 deletion emails/grunt/aliases.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
default:
- 'clean'
- 'assemble'
- 'replace'
- 'copy'
5 changes: 0 additions & 5 deletions emails/grunt/clean.js

This file was deleted.

6 changes: 6 additions & 0 deletions emails/grunt/copy.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,11 @@ module.exports = function () {
src: ['**.txt'],
dest: '../public/emails/',
},
html: {
expand: true,
cwd: 'dist',
src: ['**.html'],
dest: '../public/emails/',
},
};
};
59 changes: 44 additions & 15 deletions emails/grunt/replace.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,45 @@
module.exports = {
dist: {
overwrite: true,
src: ['dist/*.txt'],
replacements: [
{
from: '[[',
to: '{{',
},
{
from: ']]',
to: '}}',
},
],
},
module.exports = function () {
'use strict';

return {
txt,
comments,
};
};

const txt = {
overwrite: true,
src: ['dist/*.txt'],
replacements: [
{
from: '[[',
to: '{{',
},
{
from: ']]',
to: '}}',
},
],
};

/**
* Replace all instances of HTML comments with {{ __dangerouslyInjectHTML "<!-- my comment -->" }}.
*
* MJML will output <!--[if !mso]><!--> comments which are specific to MS Outlook.
*
* Go's template/html package will strip all HTML comments and we need them to be preserved
* to work with MS Outlook on the Desktop.
*/
const HTML_SAFE_FUNC = '__dangerouslyInjectHTML';
const commentBlock = /(<!--[\s\S]*?-->)/g;

const comments = {
overwrite: true,
src: ['dist/*.html'],
replacements: [
{
from: commentBlock,
to: `{{ ${HTML_SAFE_FUNC} \`$1\` }}`,
},
],
};
1 change: 0 additions & 1 deletion emails/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"grunt": "1.5.3",
"grunt-assemble": "0.6.3",
"grunt-cli": "^1.4.3",
"grunt-contrib-clean": "2.0.0",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-watch": "1.1.0",
"grunt-text-replace": "0.4.0",
Expand Down
16 changes: 14 additions & 2 deletions pkg/services/notifications/notifications.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ func ProvideService(bus bus.Bus, cfg *setting.Cfg, mailer Mailer, store TempUser

mailTemplates = template.New("name")
mailTemplates.Funcs(template.FuncMap{
"Subject": subjectTemplateFunc,
"HiddenSubject": hiddenSubjectTemplateFunc,
"Subject": subjectTemplateFunc,
"HiddenSubject": hiddenSubjectTemplateFunc,
"__dangerouslyInjectHTML": __dangerouslyInjectHTML,
})
mailTemplates.Funcs(sprig.FuncMap())

Expand Down Expand Up @@ -174,6 +175,17 @@ func subjectTemplateFunc(obj map[string]interface{}, data map[string]interface{}
return subj
}

// __dangerouslyInjectHTML allows marking areas of am email template as HTML safe, this will _not_ sanitize the string and will allow HTML snippets to be rendered verbatim.
// Use with absolute care as this _could_ allow for XSS attacks when used in an insecure context.
//
// It's safe to ignore gosec warning G203 when calling this function in an HTML template because we assume anyone who has write access
// to the email templates folder is an administrator.
//
// nolint:gosec
func __dangerouslyInjectHTML(s string) template.HTML {
return template.HTML(s)
}

func (ns *NotificationService) SendEmailCommandHandlerSync(ctx context.Context, cmd *SendEmailCommandSync) error {
message, err := ns.buildEmailMessage(&SendEmailCommand{
Data: cmd.Data,
Expand Down
36 changes: 18 additions & 18 deletions public/emails/invited_to_org.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
<title>
{{ Subject .Subject .TemplateData "{{ .InvitedBy }} has added you to the {{ .OrgName }} organization" }}
</title>
<!--[if !mso]><!-->
{{ __dangerouslyInjectHTML `<!--[if !mso]><!-->` }}
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--<![endif]-->
{{ __dangerouslyInjectHTML `<!--<![endif]-->` }}
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
Expand Down Expand Up @@ -44,7 +44,7 @@
}

</style>
<!--[if mso]>
{{ __dangerouslyInjectHTML `<!--[if mso]>
<noscript>
<xml>
<o:OfficeDocumentSettings>
Expand All @@ -53,19 +53,19 @@
</o:OfficeDocumentSettings>
</xml>
</noscript>
<![endif]-->
<!--[if lte mso 11]>
<![endif]-->` }}
{{ __dangerouslyInjectHTML `<!--[if lte mso 11]>
<style type="text/css">
.mj-outlook-group-fix { width:100% !important; }
</style>
<![endif]-->
<!--[if !mso]><!-->
<![endif]-->` }}
{{ __dangerouslyInjectHTML `<!--[if !mso]><!-->` }}
<link href="https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700" rel="stylesheet" type="text/css">
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700);

</style>
<!--<![endif]-->
{{ __dangerouslyInjectHTML `<!--<![endif]-->` }}
<style type="text/css">
@media only screen and (min-width:480px) {
.mj-column-per-100 {
Expand Down Expand Up @@ -100,13 +100,13 @@

<body style="word-spacing:normal;background-color:#111217;">
<div style="background-color:#111217;">
<!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->` }}
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->` }}
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="background-color:transparent;vertical-align:top;" width="100%">
<tbody>
Expand All @@ -126,19 +126,19 @@
</tbody>
</table>
</div>
<!--[if mso | IE]></td></tr></table><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]></td></tr></table><![endif]-->` }}
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" bgcolor="#22252b" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" bgcolor="#22252b" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->` }}
<div style="background:#22252b;background-color:#22252b;margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#22252b;background-color:#22252b;width:100%;">
<tbody>
<tr>
<td style="border:1px solid #2f3037;direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:598px;" ><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:598px;" ><![endif]-->` }}
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tbody>
Expand Down Expand Up @@ -186,19 +186,19 @@ <h2>You have been added to {{ .OrgName }}</h2>
</tbody>
</table>
</div>
<!--[if mso | IE]></td></tr></table><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]></td></tr></table><![endif]-->` }}
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->` }}
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->` }}
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="background-color:transparent;vertical-align:top;" width="100%">
<tbody>
Expand All @@ -210,13 +210,13 @@ <h2>You have been added to {{ .OrgName }}</h2>
</tbody>
</table>
</div>
<!--[if mso | IE]></td></tr></table><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]></td></tr></table><![endif]-->` }}
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]></td></tr></table><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]></td></tr></table><![endif]-->` }}
</div>
</body>

Expand Down
36 changes: 18 additions & 18 deletions public/emails/new_user_invite.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
<title>
{{ Subject .Subject .TemplateData "{{ .InvitedBy }} has invited you to join Grafana" }}
</title>
<!--[if !mso]><!-->
{{ __dangerouslyInjectHTML `<!--[if !mso]><!-->` }}
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--<![endif]-->
{{ __dangerouslyInjectHTML `<!--<![endif]-->` }}
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
Expand Down Expand Up @@ -44,7 +44,7 @@
}

</style>
<!--[if mso]>
{{ __dangerouslyInjectHTML `<!--[if mso]>
<noscript>
<xml>
<o:OfficeDocumentSettings>
Expand All @@ -53,19 +53,19 @@
</o:OfficeDocumentSettings>
</xml>
</noscript>
<![endif]-->
<!--[if lte mso 11]>
<![endif]-->` }}
{{ __dangerouslyInjectHTML `<!--[if lte mso 11]>
<style type="text/css">
.mj-outlook-group-fix { width:100% !important; }
</style>
<![endif]-->
<!--[if !mso]><!-->
<![endif]-->` }}
{{ __dangerouslyInjectHTML `<!--[if !mso]><!-->` }}
<link href="https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700" rel="stylesheet" type="text/css">
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700);

</style>
<!--<![endif]-->
{{ __dangerouslyInjectHTML `<!--<![endif]-->` }}
<style type="text/css">
@media only screen and (min-width:480px) {
.mj-column-per-100 {
Expand Down Expand Up @@ -100,13 +100,13 @@

<body style="word-spacing:normal;background-color:#111217;">
<div style="background-color:#111217;">
<!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->` }}
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->` }}
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="background-color:transparent;vertical-align:top;" width="100%">
<tbody>
Expand All @@ -126,19 +126,19 @@
</tbody>
</table>
</div>
<!--[if mso | IE]></td></tr></table><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]></td></tr></table><![endif]-->` }}
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" bgcolor="#22252b" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" bgcolor="#22252b" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->` }}
<div style="background:#22252b;background-color:#22252b;margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#22252b;background-color:#22252b;width:100%;">
<tbody>
<tr>
<td style="border:1px solid #2f3037;direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:598px;" ><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:598px;" ><![endif]-->` }}
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tbody>
Expand Down Expand Up @@ -180,19 +180,19 @@ <h2>You're invited to join {{ .OrgName }}</h2>
</tbody>
</table>
</div>
<!--[if mso | IE]></td></tr></table><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]></td></tr></table><![endif]-->` }}
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->` }}
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->` }}
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="background-color:transparent;vertical-align:top;" width="100%">
<tbody>
Expand All @@ -204,13 +204,13 @@ <h2>You're invited to join {{ .OrgName }}</h2>
</tbody>
</table>
</div>
<!--[if mso | IE]></td></tr></table><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]></td></tr></table><![endif]-->` }}
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]></td></tr></table><![endif]-->
{{ __dangerouslyInjectHTML `<!--[if mso | IE]></td></tr></table><![endif]-->` }}
</div>
</body>

Expand Down
Loading

0 comments on commit ed82f96

Please sign in to comment.