Grafana-web visual read-only/kiosk mode for integration in enteprise app -


have requirement in project integrate grafana-web in enteprise app.

some of points are:

  • don't show grafana menu (dashboards read via api , integrated in app menu)
  • hide playground buttons users (even if grafana offers readonly mode, prevents saving not playing around settings/data)
  • for users allow edit mode (add rows, dashboard settings, dashboard save ...)
  • disable sharing users
  • all these visual quirks in frontend, security level low (evil user can still bypass hidden buttons , that's ok)
  • create/delete dashboards done via api triggered buttons in enteprise app

as grafana has nothing this, thinking load iframe , xss hide buttons (both ui's loaded same domain).

i understand , accept torkel , grafana team decision not have readonly mode in frontend "evil" user can query backend around it, security point of view right.

but see edge cases/projects require if visual quirk.

warning: sure got it, visual styling of grafana-web , not offer security, "evil" user can still have access everything.

so here's how implemented it:

  • all users have edit priviledges in grafana (the buttons hidden frontend only)
  • load grafana-web iframe
  • the iframe either has mask on (one can move iframe our of view or make if transparent)
  • on iframe domcontentloaded handler, register mutationobserver on iframe document catch , hide buttons added dom, using amazing mutation summary library rafael weinstein.
  • hide buttons @ stage rendered, in case observer registred late (it's race condition against angular rendering)
  • remove mask (move iframe visible area, make opac ...)

here's customizer code triggered domcontentloaded:

// don't forget load mutation-summary.js lib  function iframeload (iframe) {     // disable if want users have access playground buttons like:     // add rows, edit panels, dashboard settings ...     readonlymode = true;      // iframe "window"     var iframe_window = iframe.contentwindow;      // iframe "document" under mutationobserver dom changes     var iframe_document = iframe.contentdocument;      var queries = [{         // main menu of grafana         element: '.navbar-brand-btn'      },{          // dashboard selection right of main menu         element: '.navbar-page-btn'      },{          // share button appearing inside .dashnav-action-icons, don't want allow         // anybody, it's exposes real url, bypassing code         element: 'li[ng-show="::dashboardmeta.canshare"]'      },{          // dashboard delete button, under dashboard setting button         element: 'a[ng-click="deletedashboard();"]'      }];       if ( readonlymode ) {         queries.push({              // 3 vertical dots button open row menu/edit             element: '.dash-row-menu-grip'          });         queries.push({             // bottom "+ add row" button             element: '.add-row-panel-hint'         });         queries.push({             // share button right of dashboard menu             element: '.dashnav-action-icons'          });         queries.push({             // "panel" menu triggered clicking panel name             element: '.panel-menu'          });     }       var observer;     observer = new mutationsummary({         callback: function (changes) {             changes.foreach(function (change) {                 change.added.foreach(function (el) {                     iframe_window.angular.element(el).addclass('ng-hide');                 });             });              // disconnect here free resources, on new dashboards             // buttons re-rendered angular, keep block behaviour             //observer.disconnect();         },         queries: queries,         rootnode: iframe_document     });       // hide elements if generated before registred observer     // race condition afterall "angular rendering" vs "registering observer"     queries.foreach( function (el) {         if ( iframe_window && iframe_window.angular ) {             iframe_window.angular.element(el.element).addclass('ng-hide');         }     });      // remove mask or move iframe view if needed     // [your code here]   } 

this method tested against grafana version 4.0.0-1476697633pre1 (and 1 running in play.grafana.org)

will try update code in github page, once upgrade grafana.

full example can found on github page using play.grafana.org in iframe, , play.grafana not in domain play around disable same-origin policy in chrome starting with:

google-chrome --disable-web-security --user-data-dir 

Comments

Popular posts from this blog

asynchronous - C# WinSCP .NET assembly: How to upload multiple files asynchronously -

aws api gateway - SerializationException in posting new Records via Dynamodb Proxy Service in API -

asp.net - Problems sending emails from forum -