certidude/certidude/api/cfg.py

112 lines
2.7 KiB
Python

import falcon
import logging
import ipaddress
import string
from random import choice
from certidude import config
from certidude.auth import login_required, authorize_admin
from certidude.decorators import serialize
from certidude.relational import RelationalMixin
from jinja2 import Environment, FileSystemLoader
logger = logging.getLogger("api")
env = Environment(loader=FileSystemLoader("/etc/certidude/scripts"), trim_blocks=True)
SQL_SELECT_INHERITED = """
select `key`, `value` from tag_inheritance where tag_id in (select
tag.id
from
device_tag
join
tag on device_tag.tag_id = tag.id
join
device on device_tag.device_id = device.id
where
device.cn = %s)
"""
SQL_SELECT_TAGS = """
select
tag.`key` as `key`,
tag.`value` as `value`
from
device_tag
join
tag on device_tag.tag_id = tag.id
join
device on device_tag.device_id = device.id
"""
SQL_SELECT_RULES = """
select
tag.cn as `cn`,
tag.key as `tag_key`,
tag.value as `tag_value`,
tag_properties.property_key as `property_key`,
tag_properties.property_value as `property_value`
from
tag_properties
join
tag
on
tag.key = tag_properties.tag_key and
tag.value = tag_properties.tag_value
"""
class ConfigResource(RelationalMixin):
@serialize
@login_required
@authorize_admin
def on_get(self, req, resp):
return self.iterfetch(SQL_SELECT_TAGS)
class ScriptResource(RelationalMixin):
def on_get(self, req, resp):
from certidude.api.whois import address_to_identity
node = address_to_identity(
self.connect(),
req.context.get("remote_addr")
)
if not node:
resp.body = "Could not map IP address: %s" % req.context.get("remote_addr")
resp.status = falcon.HTTP_404
return
address, acquired, identity = node
key, common_name = identity.split("=")
assert "=" not in common_name
conn = self.connect()
cursor = conn.cursor()
resp.set_header("Content-Type", "text/x-shellscript")
args = common_name,
ctx = dict()
for query in SQL_SELECT_INHERITED, SQL_SELECT_TAGS:
cursor.execute(query, args)
for key, value in cursor:
current = ctx
if "." in key:
path, key = key.rsplit(".", 1)
for component in path.split("."):
if component not in current:
current[component] = dict()
current = current[component]
current[key] = value
cursor.close()
conn.close()
resp.body = env.get_template("uci.sh").render(ctx)
# TODO: Assert time is within reasonable range