#!/usr/bin/env python3
# Copyright 2026 SigmaSRC, Inc. All Rights Reserved.

"""Produce the Sigma agent home page (in HTML).

This is invoked by sigma/sched/webserver.py.

"""

import os
import sys
import time
import optparse

parser = optparse.OptionParser(usage=__doc__.strip())
parser.add_option("-s", "--started", dest="started", action="store_true",
                  default=False, help="add 'Compliance Checking Started' box")

import pwgather
from sigma.util import config, xmlparse, ostypes
from sigma.protocol import xmlproto

options = config.Options()

TOP = """<html>
  <head>
    <title>Security Policy Compliance Indicator</title>
    <style type="text/css" media="screen">
    body {
        margin: 0px;
        background: #FFFFFF;
        background-repeat: repeat-y;
        font-family: Arial, Helvetica, Sans-Serif;
        font-size: 10pt;
    }
    img {
        border: none;
    }
    #centerContent {
        position: absolute;
        top: 145px;
        left: 50px;
        bottom: 1px;
        padding-right: 150px;
    }
    #summaryBox {
        border: 1px solid #5C6264;
        background: #FFFFFF;
        width: 330px;
        height: 120px;
        padding: 2px;
        position: absolute;
        left: 10;
        top: 10;
        background-repeat: no-repeat;
    }
    #summaryBox #summarydata {
        font-family: Arial, Helvetica, Sans-Serif;
        font-size: 8pt;
    }
    #globalnavContainer {
        position: absolute;
        top: 70;
        left: 315;
        right: 0;
        height: 20px;
        padding-top: 0px;
        padding-bottom: 0px
        margin-top: 0px;
        white-space: nowrap;
        background: #5C6264;
        border-bottom: 4px solid #064A87;
    }
    #logo {
        position: absolute;
        top: 25;
        right: 5;
        float: right;
    }
    #summaryBox h1 {
        color: #5C6264;
        font-size: 16pt;
        font-weight: bold;
        font-family: Arial, Helvetica, Sans-Serif;
    }
    td {
        font-family: Arial, Helvetica, Sans-Serif;
    }
    th {
        font-weight: bold;
        text-align: left;
        font-size: 8pt;
    }
    .tableHeaderRow {
        background-color: #DDDDDD;
        color: #000000;
        font-weight: bold;
    }
    .tableHeaderRow th {
        border-bottom: 1px solid #000000;
        border-right: 1px solid #CCCCCC;
    }
    .datapanel, .resultspanel {
        margin-top: 0px;
        margin-bottom: 15px;
        margin-left: 3%%;
        margin-right: 3%%;
    }
    .header {
        background-color: #064A87;
        color: #FFFFFF;
        font-family: Arial, Helvetica, Sans-Serif;
        font-size: 10pt;
        font-weight: bold;
    }
    .datapanel .header, .resultspanel .content {
        border-bottom: none;
        border: 2px solid #064A87;
        border-bottom: none;
    }
    .datapanel .content, .resultspanel .content {
        border: 2px solid #064A87;
        background: #FFFFFF;
    }
    .datapanel table td {
        font-family: Arial, Helvetica, Sans-Serif;
        font-size: 8pt;
    }
    .header h3 {
        font-size: 10pt;
        font-weight: bold;
        font-family: Arial, Helvetica, Sans-Serif;
        display: inline;
        margin: 0px;
        color: #FFFFFF;
    }
    th {
        font-weight: bold;
        text-align: left;
        font-size: 8pt;
    }
    .blue {
        color: #064A87;
        font-weight: bold;
    }
    .red {
        color: #CC0000;
        font-weight: bold;
    }
    .datapanel table.content {
        border-top: none;
        border-top: 2px solid #064A87;
    }
    table .content {
        width: 100%%;
    }
    .tableRowA {
        background-color: #DFDFDF;
    }
    .tableRowB {
        background-color: #FFFFFF;
    }
    .datapanel .tableRowA td {
        border-right: 1px solid #FFFFFF;
    }
    .datapanel .tableRowB td {
        border-right: 1px solid #DFDFDF;
    }
    form {
        display: inline;
    }
    table {
        border: 0px;
        border-collapse: collapse;
        border-spacing: 0px;
        empty-cells: show;
        margin: 0px;
    }
    .datapanel table.content, .navpanel table {
       width: 100%%;
    }
    td {
        vertical-align: top;
    }
    .buttonBox {
        border-top: 1px solid #CCCCCC;
        text-align: right;
        margin-top: 5px;
        padding-right: 30px;
        padding-top: 5px;
    }
    button {
        margin-left: 5px;
        margin-right: 5px;
        margin-top: 2px;
        margin-bottom: 2px;
    }
    p {
        margin-left: 5px;
    }
    .datapanel .header {
        margin-bottom: 0px;
    }
    .datapanel table.content {
        margin-top: -2px;
        border-top: 2px solid #064A87;
        margin-left: 0px;
        width: 99.9%%;
    }
    .resultspanel table td {
        font-family: Arial, Helvetica, Sans-Serif;
        font-size: 10pt;
    }
    .resultspanel table.content {
        display: block;
    }
    resultspanel {
        margin-top: 5px;
        margin-bottom: 10px;
        margin-left: 3%%;
        margin-right: 3%%;
    }
    .resultspanel .header {
        border: 2px solid #39B54A;
        border-bottom: none;
        background: #007236;
    }
    .resultspanel .content {
        border: 2px solid #39B54A;
        color: #000000;
        background: #FFFFFF;
        border-top: 2px solid #007236;
    }
    .resultspanel .icon {
        background: #007236;
        width: 64px;
    }
    .resultspanel .data {
        padding-left: 5px;
    }
    </style>
  </head>
  <body>
    <div id="logo">
      <img src="sigma-logo.gif" width="139" height="42" alt="SigmaSRC" />
    </div>
    <div id="globalnavContainer"></div>
    <div id="summaryBox">
      <h1>Sigma Agent</h1>
      <div id="summarydata">
        <b>Version:</b> %s on %s
      </div>
    </div>
    <div id="centerContent">
"""

STARTED = """
      <div class="resultspanel">
        <div class="header">
          <h3>Compliance Checking Started</h3>
        </div>
        <table class="content">
          <tbody>
            <tr>
              <td class="icon">
                  <img src="checkbox-green-shadow.gif" alt="[!]"
                       height="64" width="64">
              </td>
              <td class="data">
                <p>The Sigma Agent is recomputing your computer's
                   compliance. This may take a few minutes.</p>
                <p><a href="/">Click here</a> to remove this message.</p>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
"""

NEXT = """
      <div class="datapanel">
        <div class="header">
          <h3>Security Policy Compliance Indicator</h3>
        </div>
        <div class="content">
          <!-- begin user changeable -->
"""

DEFAULT_CUSTOM = """
          <p>Violations of security policy for this computer are
          listed below.</p>

          <p>If the security agent's tray icon is <span
          class="blue">blue</span>, no restrictions currently are
          being placed on the network access rights of this
          machine.</p>

          <p>If the icon is <span class="red">red</span>, you must
          correct any unresolved conditions indicated by the rules
          listed below before access restrictions will be removed. For
          more information, contact your Network Administrator.</p>

          <p><i>Note: Linux or macOS computer users will not see a tray
          icon on their desktop.</i></p>
"""

CENTER = """
          <!-- end user changeable -->
        </div>
      </div>
      <div class="datapanel">
        <div class="header">
          <h3>Help!</h3>
        </div>
        <div class="content">
          <p>If the security agent's icon is <span
          class="red">red</span> and you have corrected the problems
          shown below, click the <b>Try Again</b> button to restore
          full network access.</p>
          <p>There may be some minor delay while the network is
          updated; if problems persist, please contact your
          administrator.</p>
          <div class="buttonBox">
            <form method="post" action="/doitnow">
              <button type="submit">Try Again</button>
            </form>
          </div>
        </div>
      </div>
      <div class="datapanel">
        <div class="header">
          <h3>Policy Violations (max. items: 100 most recent)</h3>
        </div>
        <table class="content">
          <tr class="tableHeaderRow">
            <th>Description</th>
            <th>Message</th>
            <th>Timestamp</th>
          </tr>
"""

BOTTOM = """
        </table>
      </div>
      <br />
    </div>
  </body>
</html>
"""

def main(args=None):
    opts, args = parser.parse_args(args)
    print(TOP % (getversion() or "unknown", ostypes.guess_ostype()))
    if opts.started:
        print(STARTED)
    print(NEXT)
    custom = options.agent_ui_message or DEFAULT_CUSTOM
    print(custom)
    print(CENTER)
    sys.stdout.flush()
    pwgather.main([])
    packetlog = pwgather.readpacketlog()
    cls = "tableRowB"
    nextclass = {"tableRowB": "tableRowA", "tableRowA": "tableRowB"}
    if not packetlog:
        print('<tr class="%s"><td><i>(No violations found)</i></td></tr>' % cls)
    packetlog.reverse()
    for datef, timef, ruleid, message in packetlog:
        args = cls, getrulename(ruleid), message, formattime(datef, timef)
        print('<tr class="%s"><td>%s</td><td>%s</td><td>%s</td></tr>' % args)
        cls = nextclass[cls]
    print(BOTTOM)
    return 0

def formattime(datef, timef):
    t = time.strptime(datef, "%Y-%m-%d")
    return timef + time.strftime(" %b %d, %Y", t)

def getversion():
    fn = os.path.join(options.agentactive, "version.txt")
    try:
        f = open(fn)
    except IOError:
        return ""
    try:
        return f.readline().strip()
    finally:
        f.close()

def getrulename(ruleid):
    policydir = options.datapath("policy")
    try:
        filenames = os.listdir(policydir)
    except os.error:
        filenames = []
    for filename in filenames:
        filename = os.path.join(policydir, filename)
        try:
            directive = xmlproto.load_directive(filename)
        except xmlparse.ParseError:
            continue
        for rule in directive.rules:
            if str(rule.id) == ruleid:
                name = rule.name or "%s.%s" % (rule.module, rule.procedure)
                params = []
                for param in rule.parameters:
                    params.append("%s=%s" % (param.name, param.value))
                if params:
                    name = "%s; %s" % (name, ", ".join(params))
                return name
    # Fallback if we didn't get anything
    return "Unknown - Policy recalled; no longer applies to this computer"

if __name__ == "__main__":
    sys.exit(main())
