# Copyright (C) 2015, 2016 GoSecure Inc.
"""
Telnet Transport and Authentication for the Honeypot

@author: Olivier Bilodeau <obilodeau@gosecure.ca>
"""

from __future__ import annotations

import configparser
import importlib.resources
import time
from typing import TYPE_CHECKING

from twisted.internet import protocol
from twisted.python import log

from cowrie.core.config import CowrieConfig
from cowrie.telnet.transport import CowrieTelnetTransport
from cowrie.telnet.userauth import HoneyPotTelnetAuthProtocol
from cowrie.telnet_proxy.server_transport import FrontendTelnetTransport
from cowrie import data

if TYPE_CHECKING:
    from twisted.plugin import IPlugin
    from twisted.cred import portal as tp


class HoneyPotTelnetFactory(protocol.ServerFactory):
    """
    This factory creates HoneyPotTelnetAuthProtocol instances
    They listen directly to the TCP port
    """

    tac: IPlugin
    banner: bytes
    starttime: float

    def __init__(self, backend, pool_handler):
        self.portal: tp.Portal | None = None  # gets set by Twisted plugin
        self.backend: str = backend
        self.pool_handler = pool_handler
        super().__init__()

    # TODO logging clarity can be improved: see what SSH does
    def logDispatch(self, **args):
        """
        Special delivery to the loggers to avoid scope problems
        """
        args["sessionno"] = "T{}".format(str(args["sessionno"]))
        for output in self.tac.output_plugins:
            output.logDispatch(**args)

    def startFactory(self) -> None:
        """ """
        try:
            with open(
                "{}/etc/issue.net".format(
                    CowrieConfig.get("honeypot", "contents_path")
                ),
                mode="rb",
            ) as f:
                self.banner = f.read()
        except configparser.Error as e:
            log.msg(f"Loading default /etc/issue.net file: {e!r}")
            resources_path = importlib.resources.files(data)
            config_file_path = (
                resources_path.joinpath("honeyfs").joinpath("etc").joinpath("issue.net")
            )
            self.banner = config_file_path.read_text(encoding="utf-8").encode()
        except OSError as e:
            log.err(e, "ERROR: Failed to load /etc/issue.net")
            self.banner = b""

        # For use by the uptime command
        self.starttime = time.time()

        # hook protocol
        if self.backend == "proxy":
            self.protocol = lambda: FrontendTelnetTransport()
        else:
            self.protocol = lambda: CowrieTelnetTransport(
                HoneyPotTelnetAuthProtocol, self.portal
            )

        protocol.ServerFactory.startFactory(self)
        log.msg("Ready to accept Telnet connections")

    def stopFactory(self) -> None:
        """
        Stop output plugins
        """
        protocol.ServerFactory.stopFactory(self)
