commit 83fae7f49f913ff18672097a9f7a4ad37833e2aa
Author: Jan Zerebecki <jan.foss@zerebecki.de>
Date:   Thu Jun 14 13:14:39 2018 +0200

    fix XSS vulnerabilities in dashboard links
    
    To be able to patch the tar distribution this is the minfied verion of
    1b61316353535c07ad7f9899a5bce548fe30b79e
    from https://github.com/grafana/grafana/pull/12265 .

diff --git a/public/app/features/dashlinks/module.js b/public/app/features/dashlinks/module.js
index 98322e887..fb5cda951 100644
--- a/public/app/features/dashlinks/module.js
+++ b/public/app/features/dashlinks/module.js
@@ -1,4 +1,4 @@
-/*! grafana - v4.5.1 - 2017-09-18
- * Copyright (c) 2017 Torkel Ödegaard; Licensed Apache-2.0 */
+/*! grafana - v4.5.2 - 2018-06-14
+ * Copyright (c) 2018 Torkel Ödegaard; Licensed Apache-2.0 */
 
-define(["angular","lodash"],function(a,b){"use strict";var c=a.module("grafana.directives"),d={"external link":"fa-external-link",dashboard:"fa-th-large",question:"fa-question",info:"fa-info",bolt:"fa-bolt",doc:"fa-file-text-o",cloud:"fa-cloud"};c.directive("dashLinksEditor",function(){return{restrict:"E",controller:"DashLinkEditorCtrl",templateUrl:"public/app/features/dashlinks/editor.html",link:function(){}}}),c.directive("dashLinksContainer",function(){return{scope:{links:"="},restrict:"E",controller:"DashLinksContainerCtrl",template:'<dash-link ng-repeat="link in generatedLinks" link="link"></dash-link>',link:function(){}}}),c.directive("dashLink",["$compile","linkSrv",function(a,b){return{restrict:"E",link:function(c,d){function e(){var a=b.getAnchorInfo(f);j.text(a.title),h.attr("href",a.href)}var f=c.link,g='<div class="gf-form"><a class="pointer gf-form-label" data-placement="bottom"'+(f.asDropdown?' ng-click="fillDropdown(link)" data-toggle="dropdown"':"")+"><i></i> <span></span></a>";f.asDropdown&&(g+='<ul class="dropdown-menu" role="menu"><li ng-repeat="dash in link.searchHits"><a href="{{dash.url}}">{{dash.title}}</a></li></ul>'),g+="</div>",d.html(g),a(d.contents())(c);var h=d.find("a"),i=d.find("i"),j=d.find("span");d.find("a").tooltip({title:c.link.tooltip,html:!0,container:"body"}),i.attr("class","fa fa-fw "+c.link.icon),h.attr("target",c.link.target),f.asDropdown&&c.$last&&d.find(".dropdown-menu").addClass("pull-right"),e(),c.$on("refresh",e)}}}]),c.controller("DashLinksContainerCtrl",["$scope","$rootScope","$q","backendSrv","dashboardSrv","linkSrv",function(a,c,e,f,g,h){function i(b){return"dashboards"===b.type?b.tags?b.asDropdown?e.when([{title:b.title,tags:b.tags,keepTime:b.keepTime,includeVars:b.includeVars,icon:"fa fa-bars",asDropdown:!0}]):a.searchDashboards(b,7):(console.log("Dashboard link missing tag"),e.when([])):"link"===b.type?e.when([{url:b.url,title:b.title,icon:d[b.icon],tooltip:b.tooltip,target:b.targetBlank?"_blank":"_self",keepTime:b.keepTime,includeVars:b.includeVars}]):e.when([])}function j(){var c=b.map(a.links,i);e.all(c).then(function(c){a.generatedLinks=b.flatten(c)})}var k=g.getCurrent().id;a.searchDashboards=function(a,c){return f.search({tag:a.tags,limit:c}).then(function(c){return b.reduce(c,function(b,c){return c.id!==k&&b.push({title:c.title,url:"dashboard/"+c.uri,icon:"fa fa-th-large",keepTime:a.keepTime,includeVars:a.includeVars}),b},[])})},a.fillDropdown=function(c){a.searchDashboards(c,100).then(function(a){b.each(a,function(a){a.url=h.getLinkUrl(a)}),c.searchHits=a})},j(),c.onAppEvent("dash-links-updated",j,a)}]),c.controller("DashLinkEditorCtrl",["$scope","$rootScope",function(a,c){a.iconMap=d,a.dashboard.links=a.dashboard.links||[],a.addLink=function(){a.dashboard.links.push({type:"dashboards",icon:"external link"}),a.dashboard.updateSubmenuVisibility(),a.updated()},a.moveLink=function(c,d){b.move(a.dashboard.links,c,c+d),a.updated()},a.updated=function(){c.appEvent("dash-links-updated")},a.deleteLink=function(b){a.dashboard.links.splice(b,1),a.dashboard.updateSubmenuVisibility(),a.updated()}}])});
\ No newline at end of file
+define(["angular","lodash"],function(a,b){"use strict";var c=a.module("grafana.directives"),d={"external link":"fa-external-link",dashboard:"fa-th-large",question:"fa-question",info:"fa-info",bolt:"fa-bolt",doc:"fa-file-text-o",cloud:"fa-cloud"};c.directive("dashLinksEditor",function(){return{restrict:"E",controller:"DashLinkEditorCtrl",templateUrl:"public/app/features/dashlinks/editor.html",link:function(){}}}),c.directive("dashLinksContainer",function(){return{scope:{links:"="},restrict:"E",controller:"DashLinksContainerCtrl",template:'<dash-link ng-repeat="link in generatedLinks" link="link"></dash-link>',link:function(){}}}),c.directive("dashLink",["$compile","$sanitize","linkSrv",function(a,b,c){return{restrict:"E",link:function(d,e){function f(){var a=c.getAnchorInfo(h);l.text(a.title),j.attr("href",a.href),g(),e.find("a").tooltip({title:b(d.link.tooltip),html:!0,container:"body"})}function g(){var a=b(j.parent().html());j.parent().html(a)}var h=d.link,i='<div class="gf-form"><a class="pointer gf-form-label" data-placement="bottom"'+(h.asDropdown?' ng-click="fillDropdown(link)" data-toggle="dropdown"':"")+"><i></i> <span></span></a>";h.asDropdown&&(i+='<ul class="dropdown-menu" role="menu"><li ng-repeat="dash in link.searchHits"><a href="{{dash.url}}">{{dash.title}}</a></li></ul>'),i+="</div>",e.html(i),a(e.contents())(d);var j=e.find("a"),k=e.find("i"),l=e.find("span");k.attr("class","fa fa-fw "+d.link.icon),j.attr("target",d.link.target),h.asDropdown&&d.$last&&e.find(".dropdown-menu").addClass("pull-right"),f(),d.$on("refresh",f)}}}]),c.controller("DashLinksContainerCtrl",["$scope","$rootScope","$q","backendSrv","dashboardSrv","linkSrv",function(a,c,e,f,g,h){function i(b){return"dashboards"===b.type?b.tags?b.asDropdown?e.when([{title:b.title,tags:b.tags,keepTime:b.keepTime,includeVars:b.includeVars,icon:"fa fa-bars",asDropdown:!0}]):a.searchDashboards(b,7):(console.log("Dashboard link missing tag"),e.when([])):"link"===b.type?e.when([{url:b.url,title:b.title,icon:d[b.icon],tooltip:b.tooltip,target:b.targetBlank?"_blank":"_self",keepTime:b.keepTime,includeVars:b.includeVars}]):e.when([])}function j(){var c=b.map(a.links,i);e.all(c).then(function(c){a.generatedLinks=b.flatten(c)})}var k=g.getCurrent().id;a.searchDashboards=function(a,c){return f.search({tag:a.tags,limit:c}).then(function(c){return b.reduce(c,function(b,c){return c.id!==k&&b.push({title:c.title,url:"dashboard/"+c.uri,icon:"fa fa-th-large",keepTime:a.keepTime,includeVars:a.includeVars}),b},[])})},a.fillDropdown=function(c){a.searchDashboards(c,100).then(function(a){b.each(a,function(a){a.url=h.getLinkUrl(a)}),c.searchHits=a})},j(),c.onAppEvent("dash-links-updated",j,a)}]),c.controller("DashLinkEditorCtrl",["$scope","$rootScope",function(a,c){a.iconMap=d,a.dashboard.links=a.dashboard.links||[],a.addLink=function(){a.dashboard.links.push({type:"dashboards",icon:"external link"}),a.dashboard.updateSubmenuVisibility(),a.updated()},a.moveLink=function(c,d){b.move(a.dashboard.links,c,c+d),a.updated()},a.updated=function(){c.appEvent("dash-links-updated")},a.deleteLink=function(b){a.dashboard.links.splice(b,1),a.dashboard.updateSubmenuVisibility(),a.updated()}}])});
\ No newline at end of file
diff --git a/public/app/features/panel/panel_ctrl.ts b/public/app/features/panel/panel_ctrl.ts
index b61f72297..705c30359 100644
--- a/public/app/features/panel/panel_ctrl.ts
+++ b/public/app/features/panel/panel_ctrl.ts
@@ -257,6 +257,7 @@ export class PanelCtrl {
     }
 
     var linkSrv = this.$injector.get('linkSrv');
+    var sanitize = this.$injector.get('$sanitize');
     var templateSrv = this.$injector.get('templateSrv');
     var interpolatedMarkdown = templateSrv.replace(markdown, this.panel.scopedVars);
     var html = '<div class="markdown-html">';
@@ -272,7 +273,8 @@ export class PanelCtrl {
       html += '</ul>';
     }
 
-    return html + '</div>';
+    html += '</div>';
+    return sanitize(html);
   }
 
   openInspector() {
diff --git a/public/test/specs/helpers.js b/public/test/specs/helpers.js
index 4d7f9710f..97c05842b 100644
--- a/public/test/specs/helpers.js
+++ b/public/test/specs/helpers.js
@@ -1,4 +1,4 @@
-/*! grafana - v4.5.1 - 2017-09-18
- * Copyright (c) 2017 Torkel Ödegaard; Licensed Apache-2.0 */
+/*! grafana - v4.5.2 - 2018-06-14
+ * Copyright (c) 2018 Torkel Ödegaard; Licensed Apache-2.0 */
 
-define(["lodash","app/core/config","app/core/utils/datemath"],function(a,b,c){"use strict";function d(){var c=this;this.datasource={},this.$element={},this.annotationsSrv={},this.timeSrv=new g,this.templateSrv=new i,this.datasourceSrv={getMetricSources:function(){},get:function(){return{then:function(a){a(c.datasource)}}}},this.providePhase=function(b){return module(function(d){d.value("datasourceSrv",c.datasourceSrv),d.value("annotationsSrv",c.annotationsSrv),d.value("timeSrv",c.timeSrv),d.value("templateSrv",c.templateSrv),d.value("$element",c.$element),a.each(b,function(a,b){d.value(b,a)})})},this.createPanelController=function(a){return inject(function(d,e,f,g,h){c.scope=e.$new(),c.$location=g,c.$browser=h,c.$q=f,c.panel={type:"test"},c.dashboard={meta:{}},e.appEvent=sinon.spy(),e.onAppEvent=sinon.spy(),e.colors=[];for(var i=0;i<50;i++)e.colors.push("#"+i);b.panels.test={info:{}},c.ctrl=d(a,{$scope:c.scope},{panel:c.panel,dashboard:c.dashboard,row:{}})})},this.createControllerPhase=function(a){return inject(function(b,d,e,g,h){c.scope=d.$new(),c.$location=g,c.$browser=h,c.scope.contextSrv={},c.scope.panel={},c.scope.row={panels:[]},c.scope.dashboard={meta:{}},c.scope.dashboardMeta={},c.scope.dashboardViewState=new f,c.scope.appEvent=sinon.spy(),c.scope.onAppEvent=sinon.spy(),d.colors=[];for(var i=0;i<50;i++)d.colors.push("#"+i);c.$q=e,c.scope.skipDataOnInit=!0,c.scope.skipAutoInit=!0,c.controller=b(a,{$scope:c.scope})})}}function e(){var b=this;b.templateSrv=new i,b.timeSrv=new g,b.datasourceSrv={},b.backendSrv={},b.$routeParams={},this.providePhase=function(c){return module(function(d){a.each(c,function(a){d.value(a,b[a])})})},this.createService=function(a){return inject(function(c,d,e,f,g){b.$q=c,b.$rootScope=d,b.$httpBackend=e,b.$location=g,b.$rootScope.onAppEvent=function(){},b.$rootScope.appEvent=function(){},b.service=f.get(a)})}}function f(){this.registerPanel=function(){}}function g(){this.init=sinon.spy(),this.time={from:"now-1h",to:"now"},this.timeRange=function(a){return a===!1?this.time:{from:c.parse(this.time.from,!1),to:c.parse(this.time.to,!0)}},this.replace=function(a){return a},this.setTime=function(a){this.time=a}}function h(){this.hasRole=function(){return!0}}function i(){this.variables=[],this.templateSettings={interpolate:/\[\[([\s\S]+?)\]\]/g},this.data={},this.replace=function(b){return a.template(b,this.templateSettings)(this.data)},this.init=function(){},this.getAdhocFilters=function(){return[]},this.fillVariableValuesForUrl=function(){},this.updateTemplateData=function(){},this.variableExists=function(){return!1},this.variableInitialized=function(){},this.highlightVariablesAsHtml=function(a){return a},this.setGrafanaVariable=function(a,b){this.data[a]=b}}return{ControllerTestContext:d,TimeSrvStub:g,ContextSrvStub:h,ServiceTestContext:e}});
\ No newline at end of file
+define(["lodash","app/core/config","app/core/utils/datemath"],function(a,b,c){"use strict";function d(){var c=this;this.datasource={},this.$element={},this.$sanitize={},this.annotationsSrv={},this.timeSrv=new g,this.templateSrv=new i,this.datasourceSrv={getMetricSources:function(){},get:function(){return{then:function(a){a(c.datasource)}}}},this.providePhase=function(b){return module(function(d){d.value("datasourceSrv",c.datasourceSrv),d.value("annotationsSrv",c.annotationsSrv),d.value("timeSrv",c.timeSrv),d.value("templateSrv",c.templateSrv),d.value("$element",c.$element),d.value("$sanitize",c.$sanitize),a.each(b,function(a,b){d.value(b,a)})})},this.createPanelController=function(a){return inject(function(d,e,f,g,h){c.scope=e.$new(),c.$location=g,c.$browser=h,c.$q=f,c.panel={type:"test"},c.dashboard={meta:{}},e.appEvent=sinon.spy(),e.onAppEvent=sinon.spy(),e.colors=[];for(var i=0;i<50;i++)e.colors.push("#"+i);b.panels.test={info:{}},c.ctrl=d(a,{$scope:c.scope},{panel:c.panel,dashboard:c.dashboard,row:{}})})},this.createControllerPhase=function(a){return inject(function(b,d,e,g,h){c.scope=d.$new(),c.$location=g,c.$browser=h,c.scope.contextSrv={},c.scope.panel={},c.scope.row={panels:[]},c.scope.dashboard={meta:{}},c.scope.dashboardMeta={},c.scope.dashboardViewState=new f,c.scope.appEvent=sinon.spy(),c.scope.onAppEvent=sinon.spy(),d.colors=[];for(var i=0;i<50;i++)d.colors.push("#"+i);c.$q=e,c.scope.skipDataOnInit=!0,c.scope.skipAutoInit=!0,c.controller=b(a,{$scope:c.scope})})}}function e(){var b=this;b.templateSrv=new i,b.timeSrv=new g,b.datasourceSrv={},b.backendSrv={},b.$routeParams={},this.providePhase=function(c){return module(function(d){a.each(c,function(a){d.value(a,b[a])})})},this.createService=function(a){return inject(function(c,d,e,f,g){b.$q=c,b.$rootScope=d,b.$httpBackend=e,b.$location=g,b.$rootScope.onAppEvent=function(){},b.$rootScope.appEvent=function(){},b.service=f.get(a)})}}function f(){this.registerPanel=function(){}}function g(){this.init=sinon.spy(),this.time={from:"now-1h",to:"now"},this.timeRange=function(a){return a===!1?this.time:{from:c.parse(this.time.from,!1),to:c.parse(this.time.to,!0)}},this.replace=function(a){return a},this.setTime=function(a){this.time=a}}function h(){this.hasRole=function(){return!0}}function i(){this.variables=[],this.templateSettings={interpolate:/\[\[([\s\S]+?)\]\]/g},this.data={},this.replace=function(b){return a.template(b,this.templateSettings)(this.data)},this.init=function(){},this.getAdhocFilters=function(){return[]},this.fillVariableValuesForUrl=function(){},this.updateTemplateData=function(){},this.variableExists=function(){return!1},this.variableInitialized=function(){},this.highlightVariablesAsHtml=function(a){return a},this.setGrafanaVariable=function(a,b){this.data[a]=b}}return{ControllerTestContext:d,TimeSrvStub:g,ContextSrvStub:h,ServiceTestContext:e}});
\ No newline at end of file
