class ConfigFileTableToolbar(renderers.TemplateRenderer): """A navigation enhancing toolbar. Internal State: - aff4_path: The path we are viewing now in the table. """ post_parameters = ["aff4_path"] event_queue = "file_select" layout_template = renderers.Template(""" <ul id="toolbar_{{unique|escape}}" class="breadcrumb"> <li> <button id='{{unique|escape}}_upload' class="btn btn-default" title='Upload Binary' data-toggle="modal" data-target="#upload_dialog_{{unique|escape}}"> <img src='/static/images/upload.png' class='toolbar_icon'> </button> <button id='{{unique|escape}}_download' title='Download Binary' class="btn btn-default"> <img src='/static/images/download.png' class='toolbar_icon'> </button> </li> </ul> <div id="upload_dialog_{{unique|escape}}" class="modal" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true"> x </button> <h3>Upload File</h3> </div> <div class="modal-body" id="upload_dialog_body_{{unique|escape}}"></div> <div class="modal-footer"> <button class="btn btn-default" data-dismiss="modal" aria-hidden="true"> Close </button> </div> </div> </div> </div> """) def Layout(self, request, response): response = super(ConfigFileTableToolbar, self).Layout(request, response) return self.CallJavascript(response, "ConfigFileTableToolbar.Layout")
class RWeOwned(renderers.TemplateRenderer): """A magic 8 ball reply to the question - Are we Owned?""" layout_template = renderers.Template(""" <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true"> x </button> <h3>Are we owned?</h3> </div> <div class="modal-body"> <p class="text-info"> {{this.choice|escape}} </div> </div> </div> """) def Layout(self, request, response): """Render a magic 8 ball easter-egg.""" options = u"""It is certain You were eaten by a Grue! 中国 got you!! All your bases are belong to us! Maybe it was the Russians? It is decidedly so Without a doubt Yes - definitely You may rely on it As I see it, yes Most likely Outlook good Signs point to yes Yes Reply hazy, try again Ask again later Better not tell you now Cannot predict now Concentrate and ask again Don't count on it My reply is no My sources say no Outlook not so good Very doubtful""".splitlines() self.choice = options[random.randint(0, len(options) - 1)] return super(RWeOwned, self).Layout(request, response)
class DeleteArtifactsConfirmationDialog(renderers.ConfirmationDialogRenderer): """Dialog that asks for confirmation to delete uploaded artifacts. Note that this only deletes artifacts that have been uploaded via the ArtifactManager. Artifacts loaded from the artifacts directory are unaffected. """ content_template = renderers.Template(""" <p>Are you sure you want to <strong>delete all</strong> uploaded artifacts?</p> """) ajax_template = renderers.Template(""" <p class="text-info">Uploaded artifacts were deleted successfully.</p> """) def RenderAjax(self, request, response): aff4.FACTORY.Delete("aff4:/artifact_store", token=request.token) return self.RenderFromTemplate(self.ajax_template, response, unique=self.unique, this=self)
class EventMessageRenderer(semantic.RDFValueRenderer): """Render a special message to describe the event based on its type.""" # If the type is unknown we just say what it is. default_template = renderers.Template(""" Event of type {{this.type|escape}} """) event_template_dispatcher = { "file.mtime": renderers.Template( "<div><pre class='inline'>M--</pre> File modified.</div>"), "file.atime": renderers.Template( "<div><pre class='inline'>-A-</pre> File access.</div>"), "file.ctime": renderers.Template( "<div><pre class='inline'>--C</pre> File metadata changed.</div>"), } def Layout(self, request, response): self.type = self.proxy.type self.layout_template = self.event_template_dispatcher.get( self.type, self.default_template) return super(EventMessageRenderer, self).Layout(request, response)
class GlobalNotificationBar(renderers.TemplateRenderer): """Renders global notification bar on top of the admin UI.""" POLL_TIME = 5 * 60 * 1000 layout_template = renderers.Template(""" {% for notification in this.notifications %} <div class="alert alert-block alert-{{notification.type_name|lower|escape}}"> <button type="button" notification-hash="{{notification.hash|escape}}" class="close">×</button> <h4>{{notification.header|escape}}</h4> <p>{{notification.content|escape}}</h4> {% if notification.link %} <p><a href="{{notification.link|escape}}" target="_blank">More...</a></p> {% endif %} </div> {% endfor %} """) def Layout(self, request, response): try: user_record = aff4.FACTORY.Open( aff4.ROOT_URN.Add("users").Add(request.user), "GRRUser", token=request.token) self.notifications = user_record.GetPendingGlobalNotifications() except IOError: self.notifications = [] return super(GlobalNotificationBar, self).Layout(request, response) def RenderAjax(self, request, response): # If notification_hash is part of request, remove notification with a # given hash, otherwise just render list of notifications as usual. if "notification_hash" in request.REQ: hash_to_remove = int(request.REQ["notification_hash"]) user_record = aff4.FACTORY.Create( aff4.ROOT_URN.Add("users").Add(request.user), "GRRUser", mode="r", token=request.token) notifications = user_record.GetPendingGlobalNotifications() for notification in notifications: if notification.hash == hash_to_remove: flow.GRRFlow.StartFlow(flow_name="MarkGlobalNotificationAsShown", args=notification, token=request.token) break else: return self.Layout(request, response)
class AuditTable(statistics.Report, renderers.TableRenderer): """Parent class for audit event tabular reports.""" layout_template = renderers.Template(""" <div class="padded"> <h3>{{this.title|escape}}</h3> </div> """) + renderers.TableRenderer.layout_template time_offset = rdfvalue.Duration("7d") column_map = { "Timestamp": "timestamp", "Action": "action", "User": "******", "Client": "client", "Flow Name": "flow_name", "URN": "urn", "Description": "description" } # To be set by subclass TYPES = [] def __init__(self, **kwargs): super(AuditTable, self).__init__(**kwargs) for column_name in sorted(self.column_map): self.AddColumn(semantic.RDFValueColumn(column_name)) def BuildTable(self, start_row, end_row, request): try: now = rdfvalue.RDFDatetime().Now() start = now - self.time_offset fd = aff4.FACTORY.Open("aff4:/audit/log", aff4_type="RDFValueCollection", token=request.token) rows = [] for event in fd.GenerateItems( timestamp=(start.AsMicroSecondsFromEpoch(), now.AsMicroSecondsFromEpoch())): if event.action in self.TYPES: row_dict = {} for column_name, attribute in self.column_map.iteritems(): row_dict[column_name] = event.Get(attribute) rows.append(row_dict) for row in sorted(rows, key=lambda x: x["Timestamp"]): self.AddRow(row) except IOError: pass
class RequestRenderer(renderers.TemplateRenderer): """Display details of the request packet. Post Parameters: - task_id: The id of the request to display. - client_id: The client to show requests for. """ layout_template = renderers.Template(""" {%if this.msg %} <div id="{{unique|escape}}" class="{{this.css_class}}"> <h3>Request {{this.msg.task_id|escape}}</h3> <table id='{{ unique|escape }}' class="table table-condensed table-bordered"> <thead> <tr> <th class="ui-state-default">Task</th> </tr> </thead> <tbody> <tr> <td> <div class="default_view">{{ this.view|safe }}</div> </td> </tr> </tbody> </table> </div> {% endif %} """) def Layout(self, request, response): """Layout.""" if request.REQ.get("task_id") is None: return client_id = rdf_client.ClientURN(request.REQ.get("client_id")) task_id = "task:" + request.REQ.get("task_id") # Make a local QueueManager. manager = queue_manager.QueueManager(token=request.token) msgs = manager.Query(client_id, task_id=task_id) if msgs: self.msg = msgs[0] self.view = semantic.FindRendererForObject( self.msg).RawHTML(request) return super(RequestRenderer, self).Layout(request, response)
class SectionHeader(renderers.TemplateRenderer): """Renders a section header.""" layout_template = renderers.Template(""" <h3>{{this.header|escape}}</h3> """) def __init__(self, header=None, name=None, width=50, keep_sort=False, **kwargs): super(SectionHeader, self).__init__(**kwargs) self.header = header or name or ""
class RunHuntConfirmationDialog(renderers.ConfirmationDialogRenderer): """Dialog that asks confirmation to run a hunt and actually runs it.""" post_parameters = ["hunt_id"] inner_dialog_only = True header = "Run a hunt?" content_template = renderers.Template(""" <p>Are you sure you want to <strong>run</strong> this hunt?</p> """) ajax_template = renderers.Template(""" <p class="text-info">Hunt started successfully!</p> """) def Layout(self, request, response): self.check_access_subject = rdfvalue.RDFURN(request.REQ.get("hunt_id")) return super(RunHuntConfirmationDialog, self).Layout(request, response) def RenderAjax(self, request, response): flow.GRRFlow.StartFlow(flow_name="StartHuntFlow", token=request.token, hunt_urn=rdfvalue.RDFURN(request.REQ.get("hunt_id"))) return self.RenderFromTemplate(self.ajax_template, response, unique=self.unique)
class SearchHostView(renderers.Renderer): """Show a search screen for the host.""" title = "Search Client" context_help_url = "user_manual.html#searching-for-a-client" template = renderers.Template(""" <abbr title="Type label: to open a list of possible labels completions."> {% if this.context_help_url %} <a href="/help/{{this.context_help_url|escape}}" target="_blank" class="pull-right"> <i class="glyphicon glyphicon-question-sign input-append"></i> </a> {% endif %} <form id="search_host" class="navbar-form pull-right no-right-padding"> <div class="form-group"> <div class="input-group"> <input type="text" id="client_query" name="q" class="form-control search-query" placeholder="Search Box"/> <span class="input-group-btn"> <button type="submit" id="client_query_submit" class="btn btn-default search-query"> <span class="glyphicon glyphicon-search"></span> </button> </span> </div> </div> </form> </abbr> """) def Layout(self, request, response): """Display a search screen for the host.""" response = super(SearchHostView, self).Layout(request, response) response = self.RenderFromTemplate( self.template, response, title=self.title, id=self.id) labels_index = aff4.FACTORY.Create( aff4.VFSGRRClient.labels_index_urn, "AFF4LabelsIndex", mode="rw", token=request.token) used_labels = sorted(list( set([label.name for label in labels_index.ListUsedLabels()]))) return self.CallJavascript(response, "SearchHostView.Layout", labels=used_labels)
class GRREProcessObjectRenderer(GRRRekallViewerObjectRenderer): """Special rendering for _EPROCESS objects.""" renders_type = "_EPROCESS" layout = renderers.Template(""" <div id="{{unique|escape}}" class="modal fade" role="dialog" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" aria-hidden="true" data-dismiss="modal"> × </button> <h4 class="modal-title">Process {{this.Cybox.Name|escape}}</h4> </div> <div id="ClientInfoContent_{{unique|escape}}" class="modal-body"> <table class="table table-hover"> <tr><th>Key</th><th>Value</th></tr> {% for k, v in data %} <tr><td>{{k|escape}}</td><td>{{v|escape}}</td></tr> {% endfor %} </table> </div> </div> </div> </div> <a href=# data-toggle="modal" data-target="#{{unique|escape}}"> {{this.Cybox.Name|escape}} ({{this.Cybox.PID|escape}}) </a> """) def _Flatten(self, prefix, item): result = [] for k, v in item.items(): next_prefix = "%s.%s" % (prefix, k) if isinstance(v, dict): result.extend(self._Flatten(next_prefix, v)) else: result.append((next_prefix, v)) return result def RawHTML(self, item, **_): return self.layout.RawHTML(this=item, data=self._Flatten("", item))
class NotificationBar(renderers.TemplateRenderer): """Render a notification bar for the user.""" layout_template = renderers.Template(""" <div id="notification_dialog" class="modal wide-modal" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> <h3>Notifications for {{this.user|escape}}</h3> </div> <div class="modal-body" id="notification_dialog_body"> </div> <div class="modal-footer"> <button class="btn btn-default" data-dismiss="modal" aria-hidden="true"> Close </button> </div> </div> </div> </div> <div id="user_settings_dialog" class="modal" tabindex="-1" role="dialog" aria-hidden="true"> </div> <ul class="nav pull-left"> <li><p class="navbar-text">User: {{this.user|escape}}</p></li> </ul> <div id="notifications_and_settings" class="pull-right navbar-form"> <button id="notification_button" class="btn btn-info" data-toggle="modal" data-target="#notification_dialog" style="margin-right: 10px" /> <button id="user_settings_button" class="btn btn-default" data-toggle="modal" data-target="#user_settings_dialog"> <img src="static/images/modify.png" style="height: 17px; margin-top: -2px"> </button> </div> """) def Layout(self, request, response): """Show the number of notifications outstanding for the user.""" self.user = request.user response = super(NotificationBar, self).Layout(request, response) return self.CallJavascript(response, "Layout")
class TimelineMain(renderers.TemplateRenderer): """This is the main view to the timeline. Internal State (from hash value): - container: The container name for the timeline. - query: The query to filter. """ layout_template = renderers.Template(""" <div id='toolbar_{{id|escape}}' class="navbar navbar-default"></div> <div id='{{unique|escape}}' class="fill-parent no-margins toolbar-margin"></div> """) def Layout(self, request, response): response = super(TimelineMain, self).Layout(request, response) return self.CallJavascript(response, "TimelineMain.Layout")
class CollectionRenderer(StatEntryRenderer): """Nicely format a Collection.""" classname = "CollectionList" name = "Collection Listing" layout_template = renderers.Template(""" <table class='proto_table'> <thead> <tr><th>Mode</th><th>Name</th><th>Size</th><th>Modified</th></tr> </thead> <tbody> {% for row in this.result %} <tr> {% for value in row %} <td class="proto_value"> {{value|safe}} </td> {% endfor %} </tr> {% endfor %} </tbody> </table> """) def Layout(self, request, response): """Render collections as a table.""" self.result = [] fields = "st_mode pathspec st_size st_mtime".split() items = self.proxy.items for item in items: row = [] for name in fields: value = getattr(item, name) try: value = self.translator[name](self, request, value) # Regardless of what the error is, we need to escape the value. except StandardError: # pylint: disable=broad-except value = self.FormatFromTemplate(self.translator_error_template, value=value) row.append(value) self.result.append(row) return renderers.TemplateRenderer.Layout(self, request, response)
class ProtoBoolFormRenderer(TypeDescriptorFormRenderer): """Render a checkbox for boolean values.""" type_descriptor = type_info.ProtoBoolean layout_template = renderers.Template(""" <div class="form-group"> <div class="controls"> <label class="checkbox"> <input id='{{this.prefix}}' type=checkbox class="unset" {% if this.value %}checked {% endif %} onchange="grr.forms.checkboxOnChange(this)" value='{{ this.value|escape }}'/> <abbr title='{{this.descriptor.description|escape}}'> {{this.friendly_name}} </abbr> </label> </div> </div> """) def Layout(self, request, response): super(ProtoBoolFormRenderer, self).Layout(request, response) if self.default is not None: self.default = bool(self.default) if self.value is not None: self.value = bool(self.default) return self.CallJavascript( response, "Layout", default=self.default, value=self.value, prefix=self.prefix) def ParseArgs(self, request): value = request.REQ.get(self.prefix) if value is None: return if value.lower() in ["yes", "true"]: return True return False
class ArtifactRDFValueRenderer(semantic.RDFValueRenderer): """A special renderer for ArtifactRDFValues.""" classname = "Artifact" layout_template = renderers.Template( """ <div id={{unique|escape}}_artifact_description>""" + ArtifactListRenderer.artifact_template + """ </div> """) def Layout(self, request, response): self.artifact_str = self.proxy.ToPrettyJson() response = super(ArtifactRDFValueRenderer, self).Layout(request, response) return self.CallJavascript(response, "ArtifactRDFValueRenderer.Layout", artifact_str=self.artifact_str)
class StringListRenderer(renderers.TemplateRenderer): """Renders a list of strings as a proto table.""" layout_template = renderers.Template(""" <table class='proto_table'> <tbody> {% for string in this.strings %} <tr><td> {{string|escape}} </td></tr> {% endfor %} </tbody> </table> """) def __init__(self, strings, **kwargs): self.strings = strings super(StringListRenderer, self).__init__(**kwargs)
class CronReview(new_hunt.HuntInformation): """Shows generic hunt information plus its' cron scheduling settings.""" ajax_template = renderers.Template(""" <h3>Hunt Periodicity</h3> <div class="HuntPeriodicity"> <p>Hunt will run <strong>{{this.cron_arg.periodicity|escape}}</strong>.</p> </div> """) + new_hunt.HuntInformation.ajax_template def RenderAjax(self, request, response): """Renders review page of a hunt cron scheduling wizard.""" parser = CronHuntParser(request) self.cron_arg = parser.ParseCronParameters() return super(CronReview, self).RenderAjax(request, response)
class IPStatusIcon(semantic.RDFValueRenderer): """Renders the ip status (internal, external) icon.""" cls = "vertical_aligned" layout_template = renderers.Template(""" <img class="grr-icon-small {{this.cls|escape}}" src="/static/images/{{this.ip_icon|escape}}"/>""") icons = {utils.IPInfo.UNKNOWN: "ip_unknown.png", utils.IPInfo.INTERNAL: "ip_internal.png", utils.IPInfo.EXTERNAL: "ip_external.png", utils.IPInfo.VPN: "ip_unknown.png"} def Layout(self, request, response): self.ip_icon = self.icons.setdefault(int(self.proxy), "ip_unknown.png") return super(IPStatusIcon, self).Layout(request, response)
class CronJobManagementTabs(renderers.TabLayout): """Tab renderer for cron job management.""" names = ["Details", "Flows"] delegated_renderers = ["CronJobInformation", "CronJobView"] tab_hash = "cjt" empty_template = renderers.Template(""" <div class="padded">Please select a cron job to see the details.</div> """) def Layout(self, request, response): if not request.REQ.get("cron_job_urn"): return self.RenderFromTemplate(self.empty_template, response) else: self.state = dict(cron_job_urn=request.REQ.get("cron_job_urn")) return super(CronJobManagementTabs, self).Layout(request, response)
class AbstractLogRenderer(renderers.TemplateRenderer): """Render a page for view a Log file. Implements a very simple view. That will be extended with filtering capabilities. Implementations should implement the GetLog function. """ show_total_count = False layout_template = renderers.Template(""" <table class="proto_table"> {% if this.log|length > 0 %} {% if this.show_total_count %} <h5>{{this.log|length}} Entries</h5> {% endif %} {% endif %} {% for line in this.log %} <tr> {% for val in line %} <td class="proto_key">{{ val|safe }}</td> {% endfor %} </tr> {% empty %} <tr><td>No entries</tr></td> {% endfor %} <table> """) def GetLog(self, request): """Take a request and return a list of tuples for a log.""" _ = request return [] def Layout(self, request, response): """Fill in the form with the specific fields for the flow requested.""" self.log = [] for row in self.GetLog(request): rendered_row = [] for item in row: item_renderer = semantic.FindRendererForObject(item) rendered_row.append(item_renderer.RawHTML(request)) self.log.append(rendered_row) return super(AbstractLogRenderer, self).Layout(request, response)
class FlowFormCancelAction(renderers.TemplateRenderer): """Handle submission of a Cancel Flow button press. Post Parameters: - flow_id: The flow to cancel. """ layout_template = renderers.Template("") def Layout(self, request, response): # We can't terminate flow directly through flow.GRRFlow.TerminateFlow as # it requires writing to the datastore. We're not allowed to do it from # the GUI. Therefore we use dedicated TerminateFlow flow. flow.GRRFlow.StartFlow( flow_name="TerminateFlow", flow_urn=rdfvalue.RDFURN(request.REQ.get("flow_id")), reason="Cancelled in GUI", token=request.token) super(FlowFormCancelAction, self).Layout(request, response)
class Report(renderers.TemplateRenderer): """This is the base of all Statistic Reports.""" category = None layout_template = renderers.Template(""" <div class="padded"> {% if this.data %} <h3>{{this.title|escape}}</h3> <div> {{this.description|escape}} </div> <div id="hover_{{unique|escape}}">Hover to show exact numbers.</div> <div id="graph_{{unique|escape}}" class="grr_graph"></div> {% else %} <h3>No data Available</h3> {% endif %} </div> """)
class ProgressButtonRenderer(RDFValueRenderer): """Renders a button that shows a progress graph.""" # This specifies the name of the RDFValue object we will render. classname = "ProgressGraph" layout_template = renderers.Template(""" Open a graph showing the download progress in a new window: <button id="{{ unique|escape }}"> Generate </button> """) def Layout(self, request, response): self.flow_id = request.REQ.get("flow") response = super(ProgressButtonRenderer, self).Layout(request, response) return self.CallJavascript(response, "ProgressButtonRenderer.Layout", flow_id=self.flow_id)
class ShowFlowInformation(fileview.AFF4Stats): """Display information about the flow. Post Parameters: - flow: The flow id we will display. Internal State: - client_id, flow """ selection_publish_queue = "flow_table_select" historical_renderer = "HistoricalFlowView" # Embed the regular AFF4Stats inside a container to allow scrolling layout_template = renderers.Template(""" <div id="container_{{unique|escapejs}}"> {% if this.path %} """ + str(fileview.AFF4Stats.layout_template) + """ <br/> {% else %} Please select a flow to manage from the above table. {% endif %} </div> """) def Layout(self, request, response): """Introspect the Schema for flow objects.""" try: self.state["flow"] = session_id = request.REQ["flow"] self.fd = aff4.FACTORY.Open(session_id, token=request.token, age=aff4.ALL_TIMES) self.classes = self.RenderAFF4Attributes(self.fd, request) self.path = self.fd.urn except (KeyError, IOError): self.path = None # Skip our parent's Layout method and install parent's javascript code. response = super(fileview.AFF4Stats, self).Layout(request, response) return self.CallJavascript( response, "AFF4Stats.Layout", historical_renderer=self.historical_renderer, historical_renderer_state=self.state)
class CollectionExportView(renderers.TemplateRenderer): """Displays export command to be used to export collection.""" layout_template = renderers.Template(""" <p>To download all the files referenced in the collection, you can use this command:</p> <pre> {{ this.export_command_str|escape }} </pre> <p><em>NOTE: You can optionally add <tt>--dump_client_info</tt> flag to dump client info in YAML format.</em></p> """) @staticmethod def IsCollectionExportable(collection_urn_or_obj, token=None): if isinstance(collection_urn_or_obj, aff4.RDFValueCollection): collection = collection_urn_or_obj else: collection = aff4.FACTORY.Create( collection_urn_or_obj, "RDFValueCollection", mode="r", token=token) if not collection: return False try: export.CollectionItemToAff4Path(collection[0]) except export.ItemNotExportableError: return False return True def Layout(self, request, response, aff4_path=None): aff4_path = aff4_path or request.REQ.get("aff4_path") self.export_command_str = " ".join([ config_lib.CONFIG["AdminUI.export_command"], "--username", utils.ShellQuote(request.token.username), "--reason", utils.ShellQuote(request.token.reason), "collection_files", "--path", utils.ShellQuote(aff4_path), "--output", "."]) return super(CollectionExportView, self).Layout(request, response)
class ArtifactManagerToolbar(renderers.TemplateRenderer): """A navigation enhancing toolbar. Internal State: - aff4_path: The path we are viewing now in the table. """ post_parameters = ["aff4_path"] event_queue = "file_select" layout_template = renderers.Template(""" <ul id="toolbar_{{unique|escape}}" class="breadcrumb"> <li> <button id='{{unique|escape}}_upload' class="btn" title="Upload Artifacts as JSON or YAML" data-toggle="modal" data-target="#upload_dialog_{{unique|escape}}"> <img src='/static/images/upload.png' class='toolbar_icon'> </button> </li> </ul> <div id="upload_dialog_{{unique|escape}}" class="modal hide" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal-header"> <button id="upload_artifact_btn_{{unique|escape}}" type="button" class="close" data-dismiss="modal" aria-hidden="true"> x</button> <h3>Upload File</h3> </div> <div class="modal-body" id="upload_dialog_body_{{unique|escape}}"></div> <div class="modal-footer"> <button id="upload_artifact_close_btn_{{unique|escape}}" class="btn" data-dismiss="modal" aria-hidden="true">Close</button> </div> </div> <script> $("#upload_dialog_{{unique|escapejs}}").on("show", function () { grr.layout("ArtifactJsonUploadView", "upload_dialog_body_{{unique|escapejs}}"); }); </script> """)
class ClientCrashDetailsRenderer(semantic.RDFValueRenderer): """Renders details about a single client crash.""" layout_template = renderers.Template(""" <dl class="dl-horizontal"> <dt>Timestamp</dt><dd>{{this.proxy.timestamp}}</dd> <dt>Crash Type</dt><dd>{{this.proxy.crash_type}}</dd> {% if this.proxy.crash_message %} <dt>Crash Message</dt><dd>{{this.proxy.crash_message}}</dd> {% endif %} {% if this.proxy.backtrace %} <dt>Backtrace</dt><dd>{{this.proxy.backtrace}}</dd> {% endif %} {% if this.proxy.session_id %} <dt>Session Id</dt> <dd> <a href="/#{{this.hash|escape}}" onclick='grr.loadFromHash("{{this.hash|escapejs}}")'> {{this.proxy.session_id|escape}} </a> </dd> {% endif %} <dt>Client Information</dt> <dd>{{this.client_info|safe}}</dd> </dl> """) + renderers.TemplateRenderer.help_template context_help_url = "admin.html#_crashes" def Layout(self, request, response): if self.proxy.session_id: self.hash = urllib.urlencode( dict(c=self.proxy.client_id, flow=self.proxy.session_id, main="ManageFlows")) client_info_renderer = semantic.FindRendererForObject( self.proxy.client_info) self.client_info = client_info_renderer.RawHTML(request) super(ClientCrashDetailsRenderer, self).Layout(request, response)
class ValueRenderer(RDFValueRenderer): """A renderer which renders an RDFValue in machine readable format.""" layout_template = renderers.Template(""" <span type='{{this.rdfvalue_type|escape}}' rdfvalue='{{this.value|escape}}'> {{this.rendered_value|safe}} </span> """) def Layout(self, request, response): self.rdfvalue_type = self.proxy.__class__.__name__ try: self.value = self.proxy.SerializeToString() except AttributeError: self.value = utils.SmartStr(self.proxy) renderer = FindRendererForObject(self.proxy) self.rendered_value = renderer.RawHTML(request) return super(ValueRenderer, self).Layout(request, response)
class HuntContextView(renderers.TemplateRenderer): """Render the hunt context.""" layout_template = renderers.Template(""" {{this.args_str|safe}} """) def Layout(self, request, response): """Display hunt's context presented as dict.""" if not hasattr(self, "hunt_id"): self.hunt_id = request.REQ.get("hunt_id") self.hunt = aff4.FACTORY.Open(self.hunt_id, aff4_type=implementation.GRRHunt, token=request.token) self.args_str = renderers.DictRenderer( self.hunt.context).RawHTML(request) return super(HuntContextView, self).Layout(request, response)