diff --git a/.gitignore b/.gitignore index 55f01d3..ac8e397 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ settings.ini *.pyc __pycache__/ +venv/ \ No newline at end of file diff --git a/classes/config.py b/classes/config.py index 91add0a..a4eaf83 100644 --- a/classes/config.py +++ b/classes/config.py @@ -1,7 +1,7 @@ from configparser import ConfigParser -from .local import Local -from .remote import Remote +from .directory import Directory +from .server import Server class Config: def __init__(self): @@ -14,19 +14,11 @@ class Config: return o @property - def locals(self): + def directories(self): for section in self._parser.sections: - if section.startswith("Local "): - yield Local.from_config(section) + if section.startswith("Directory "): + yield Directory.from_config(section) @property - def remotes(self): - for section in self._parser.sections: - if section.startswith("Remote "): - yield Remote.from_config(section) - - @property - def defaults(self): - if "DEFAULT" in self._parser.sections: - return self._parser["DEFAULT"] - return {} \ No newline at end of file + def server(self): + return Server(self._parser["Server"]) diff --git a/classes/directory.py b/classes/directory.py new file mode 100644 index 0000000..6c3df08 --- /dev/null +++ b/classes/directory.py @@ -0,0 +1,11 @@ +class Directory: + def __init__(self, name, source, destination, sourcebackup=None, destinationbackup=None): + self.name = name + self.source = source + self.destination = destination + self.sourcebackup = sourcebackup + self.destinationbackup = destinationbackup + + @classmethod + def from_config(cls, section): + return cls(section.name.split()[1], section["SourceDirectory"], section["DestinationDirectory"], section.get("SourceBackup"), section.get("DestinationBackup")) \ No newline at end of file diff --git a/classes/local.py b/classes/local.py deleted file mode 100644 index 5abdc39..0000000 --- a/classes/local.py +++ /dev/null @@ -1,4 +0,0 @@ -class Local: - @classmethod - def from_config(cls, section): - pass \ No newline at end of file diff --git a/classes/remote.py b/classes/remote.py deleted file mode 100644 index ab121d6..0000000 --- a/classes/remote.py +++ /dev/null @@ -1,4 +0,0 @@ -class Remote: - @classmethod - def from_config(cls, section): - pass \ No newline at end of file diff --git a/classes/server.py b/classes/server.py new file mode 100644 index 0000000..85020af --- /dev/null +++ b/classes/server.py @@ -0,0 +1,22 @@ +import paramiko + +class Server: + def __init__(self, host, username, password, inpath, outpath, ourkey, theirkey): + self.host = host + self.username = username + self.password = password + self.inpath = inpath + self.outpath = outpath + self.ourkey = ourkey + self.theirkey = theirkey + + @classmethod + def from_config(cls, section): + return cls(section["Host"], section["Username"], section["Password"], section["InPath"], section["OutPath"], section["OurKey"], section["TheirKey"]) + + def get_sftp_client(self): + ssh_client = paramiko.SSHClient() + ssh_client.load_system_host_keys() + ssh_client.connect(self.host, username=self.username, password=self.password) + sftp_client = ssh_client.open_sftp() + return sftp_client diff --git a/daemon.py b/daemon.py index e69de29..035b570 100644 --- a/daemon.py +++ b/daemon.py @@ -0,0 +1,68 @@ +from classes.config import Config + +from pathlib import Path +from io import BytesIO + +import time + +from gnupg import GPG + +if __name__ == "__main__": + config = Config.from_file(Path(__file__).parent / "settings.ini") + + for directory in config.directories: + source = Path(directory.source) + + for newfile in source.iterdir(): + if newfile.is_file() and (time.time() - newfile.stat().st_mtime > 60): + try: + raw = newfile.read_text() + encrypted: str = GPG().encrypt(raw, config.server.theirkey, sign=config.server.ourkey) + upfl = BytesIO(encrypted.encode()) + uppath = Path(config.server.inpath) / f"{directory.name}_{newfile.name}" + + with config.server.get_sftp_client() as sftp: + sftp.putfo(upfl, uppath) + + if directory.sourcebackup: + newfile.rename(Path(directory.sourcebackup) / newfile.name) + else: + newfile.unlink() + + except Exception as e: + print(f"Something went wrong uploading file {newfile.name} from {directory.name}: {e}") + + try: + with config.server.get_sftp_client() as sftp: + for response in sftp.listdir(config.server.outpath): + if (time.time() - sftp.stat(response).st_mtime < 60): + continue + + encrypted: bytes = sftp.open(response).read() + decrypted = GPG().decrypt(encrypted) + + dirname = Path(outpath).name.split("_")[0] + + founddir = None + + for directory in config.directories: + if directory.name == dirname: + founddir = directory + break + + if not founddir: + founddir = directory + + outfile = Path("_".join(Path(outpath).name.split("_")[1:])) + + assert not outfile.exists() + + outfile.write_text(decrypted) + + if founddir.destinationbackup: + (Path(founddir.destinationbackup) / outfile.name).write_text(decrypted) + + sftp.remove(response) + + except: + print(f"Something went wrong downloading files from the server.") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 03e8536..9fd01d4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -python-gnupg \ No newline at end of file +python-gnupg +paramiko \ No newline at end of file