PK!libaloha/__init__.pyPK!\C33libaloha/bin/__init__.pyimport sys import libaloha.network import libaloha.sms from .check_ip import App def check_ip(): return App().run() def send_sms(): if len(sys.argv) <= 1: print("Usage: {} ".format(sys.argv[0])) sys.exit(1) text = " ".join(sys.argv[1:]) libaloha.sms.send_to_me(text) def check_website_alive(): if len(sys.argv) != 2: print("Usage: {} ".format(sys.argv[0])) sys.exit(2) hostname = sys.argv[1] if not libaloha.network.is_valid_hostname(hostname): print("Le nom de domaine fourni ne semble pas valide") sys.exit(2) if libaloha.network.is_http_alive(hostname): print("Le serveur oueb est vivant :-)") sys.exit(0) else: print("Le serveur oueb ne répond pas :-(") sys.exit(1) PK!mS S libaloha/bin/check_ip.py#!/usr/bin/env python3 import os import sys import logging import textwrap import libaloha.sms import libaloha.network logging.basicConfig(level=logging.DEBUG) logging.getLogger('requests.packages.urllib3.connectionpool').setLevel(logging.INFO) logger = logging.getLogger() class App: def __init__(self): # Fichier de sauvegarde try: self.save_file = os.path.join(os.environ['HOME'], '.my-public-ip') except KeyError: logger.warning("La variable d'environnement 'HOME' n'est pas définie.") logger.warning("Enregistrement du fichier dans le répertoire courant.") self.save_file = '.my-public-ip' def get_last_known_ip(self): """Lire la dernière IP connue depuis le fichier de sauvegarde""" if not os.path.isfile(self.save_file): return None with open(self.save_file, 'r') as f: ip = f.read() return ip.strip() def save_current_ip(self, ip): """Enregistre l'IP courant dans le fichier de sauvegarde""" with open(self.save_file, 'w') as f: f.write(ip) def run(self): """Exécute le programme""" ip = libaloha.network.get_public_ip() if not ip: logger.error("Impossible de récupérer l'IP publique de la machine !") sys.exit(1) hostname = libaloha.network.get_hostname() if not hostname: logger.error("Impossible de récupérer le nom de la machine !") last_ip = self.get_last_known_ip() if ip == last_ip: logger.info("L'adresse IP n'a pas été modifiée !") return if not last_ip: logger.info("Aucune IP connue à ce jour") elif ip != last_ip: logger.info("L'IP a été modifiée !") message = textwrap.dedent("""\ L'adresse IP de la machine {} a été modifiée ! Ancienne adresse : {} Nouvelle adresse : {} Merci de faire le nécessaire. Biz !""".format(hostname, last_ip, ip)) libaloha.sms.send_to_me(message) self.save_current_ip(ip) if __name__ == '__main__': app = App() app.run() PK!ˣ**libaloha/cache/__init__.py class AbstractCache: def exists(self, path): raise NotImplementedError(self.__class__.__name__) def get(self, path): raise NotImplementedError(self.__class__.__name__) def set(self, path, article): raise NotImplementedError(self.__class__.__name__) def remove(self, path): raise NotImplementedError(self.__class__.__name__) from .exceptions import CacheException, CacheConnectionError from .redis import RedisCache __all__ = ['AbstractCache', 'CacheException', 'CacheConnectionError', 'RedisCache']PK!cclibaloha/cache/exceptions.py class CacheException(Exception): pass class CacheConnectionError(CacheException): pass PK!,9ԏ libaloha/cache/redis.pyfrom libaloha.cache import AbstractCache from libaloha.cache.exceptions import CacheConnectionError from redis import StrictRedis from redis.exceptions import ConnectionError from typing import Any import logging logger = logging.getLogger(__name__) class RedisCache(AbstractCache): def __init__(self, host: str = 'localhost', port: int = 6379, db: int = 0, prefix: str = None): """ Cache initialisation :param host: :param port: :param db: :param prefix: :return: """ self._cache = StrictRedis(host=host, port=port, db=db) self._prefix = prefix # We do a first request to check if server is up try: self._cache.exists('null') except ConnectionError: error_msg = "Connection to redis server {}:{} failed".format(host, port) raise CacheConnectionError(error_msg) def get_key(self, key: str) -> str: """ Return correct key with prefix :param key: :return: """ if key.startswith(self._prefix): return key return self._prefix + key def exists(self, key: str) -> bool: """ Return true if a key exists in the cache or false if it doesn't :param key: :return: """ key = self.get_key(key) if key in self._cache: return True logger.debug("Key not found: {}".format(key)) return False def get(self, key: str) -> Any: """ Return a value from the cache :param key: :return: """ key = self.get_key(key) if self.exists(key): result = self._cache.get(key).decode() logger.debug("Get {}".format(key)) return result def set(self, key: str, content: Any): """ Set a value in the cache :param key: :param content: :return: """ key = self.get_key(key) result = self._cache.set(key, content) logger.debug("Set {}".format(key)) return result def remove(self, key: str): """ Delete a value from the cache :param key: :return: """ key = self.get_key(key) if self.exists(key): result = self._cache.delete(key) logger.debug("Delete '{}".format(key)) return result PK!Ȫ:vvlibaloha/django/__init__.pyfrom django.http import HttpResponse from .views import AlohaView, AlohaProtectedView, AlohaMarkdownView def teapot(request): return HttpResponse("""

418 I'm a teapot

The HTCPCP Server is a teapot. The responding entity MAY be short and stout.

""", status=418) __all__ = ['AlohaView', 'AlohaProtectedView', 'AlohaMarkdownView']PK!ɻ  libaloha/django/views.pyfrom libaloha.markdown import MarkdownFileReader from django.conf import settings from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator from django.views.generic import TemplateView import os import logging logger = logging.getLogger(__name__) class AlohaView(TemplateView): title = '' def get_context_data(self, **kwargs): """ Récupère le contexte et ajoute une clé {{ view_title }} :param kwargs: :return: """ context = super().get_context_data(**kwargs) context['view_title'] = self.title return context def redirect_to_error(self, message=None): self.template_name = 'error-page.html' return self.render_to_response({'message': message}) def dispatch(self, request, *args, **kwargs): try: return super().dispatch(request, *args, **kwargs) except Exception as e: logger.error("AlohaView.dispatch: {} {}".format(e.__class__.__name__, str(e))) message = None if settings.DEBUG: message = str(e) return self.redirect_to_error(message) @method_decorator(login_required, name='dispatch') class AlohaProtectedView(AlohaView): pass class AlohaMarkdownView(AlohaView): markdown_file = None template_name = 'markdown-view.html' def get_markdown_file(self, filename): if not filename.endswith('.md'): filename += '.md' filename = os.path.join(settings.STATIC_MARKDOWN_FOLDER, filename) if not os.path.isfile(filename): raise FileNotFoundError(filename) md = MarkdownFileReader(filename).get() return md def get(self, request, *args, **kwargs): logger.debug("Get markdown view: {}".format(self.markdown_file)) if not self.markdown_file: raise AttributeError("MarkdownView.markdown_file doit être défini") self.markdown_file = os.path.join(settings.STATIC_MARKDOWN_FOLDER, self.markdown_file) md = self.get_markdown_file(self.markdown_file) context = super().get_context_data() context['view_title'] = md.get_metadata('title', self.title) context['content'] = md.html return self.render_to_response(context)PK!R> > libaloha/markdown/__init__.pyimport os import logging import markdown logger = logging.getLogger(__name__) markdown.logger.setLevel(logging.INFO) class MarkdownFile: """ Representation of a Markdown file parsed by the MarkdownFileReader class """ EXTENSION = '.md' def __init__(self, path: str, html=None, metadata=None): """ Initialise un fichier Markdown :param path: Chemin absolu du fichier :param html: Contenu au format HTML du fichier :param metadata: Métadonnées du fichier """ self.path = path self.html = html or "" self.metadata = metadata or {} def get_metadata(self, key: str, default=None, is_list=False): """ Retourne une valeur de métadonnées :param key: :param default: :param is_list: :return: """ if not key in self.metadata: return default if not is_list: return self.metadata[key][0] else: return self.metadata[key] class MarkdownFileReader: """ Markdown reader Classe permettant de lire un fichier Markdown passé en entrée Métadonnées acceptées : title: contient le titre du document, on utilise le titre par défaut sinon """ extensions = [ 'markdown.extensions.meta', 'markdown.extensions.nl2br', 'markdown.extensions.tables', ] def __init__(self, path): if not path.endswith(MarkdownFile.EXTENSION): path += MarkdownFile.EXTENSION if not os.path.isfile(path): logger.error("MarkdownFileReader: le fichier n'existe pas: {}".format(path)) raise FileNotFoundError(path) self.path = path self._file = None self._parser = markdown.Markdown(extensions=self.extensions) def get(self): """ Retourne le fichier Markdown lu :return: """ if self._file: return self._file logger.debug("Lecture du fichier Markdown: {}".format(self.path)) # Lecture du fichier et stockage du contenu with open(self.path, encoding='utf-8') as f: text = f.read() html = self._parser.convert(text) metadata = self._get_metadata() self._file = MarkdownFile(self.path, html, metadata) return self._file def _get_metadata(self): """ Récupère les métadonnées du fichier parsé :return: """ try: return self._parser.Meta except AttributeError: return {} PK!/ libaloha/network.py#!/usr/bin/env python3 import logging import os import re import requests import requests.exceptions import socket import subprocess logger = logging.getLogger(__name__) def get_hostname(): """Récupère le nom d'hôte de la machine""" return socket.getfqdn() def get_public_ip(): """Récupère l'adresse IP publique de la machine grâce au service ipify.org""" url = 'https://api.ipify.org' try: ip = requests.get(url, timeout=5).text except requests.exceptions.ConnectionError as e: logger.warning("get_public_ip: Erreur à la récupération de l'adresse IP publique") logger.warning(e) return return ip.strip() def resolve_hostname(hostname): """Retourne l'adresse IP associée au nom de domaine donné en paramètre.""" if not is_valid_hostname(hostname): logger.warning("resolve_hostname: Nom d'hôte incorrect : {}" .format(hostname)) return False try: ip_addr = socket.gethostbyname(hostname) logger.debug("resolve_hostname: Résolution de {} en {}" .format(hostname, ip_addr)) return ip_addr except socket.gaierror: logger.warning("resolve_hostname: Résolution d'un hôte impossible : {}" .format(hostname)) return False def is_valid_hostname(hostname): """Retourne True si le nom de l'hôte passé en paramètre est correct""" if len(hostname) > 255: return False hostname = hostname.rstrip(".") allowed = re.compile("(?!-)[A-Z\d\-\_]{1,63}(? Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You just DO WHAT THE FUCK YOU WANT TO. PK!HlŃTTlibaloha-0.0.1.dist-info/WHEEL A н#J@Z|Jmqvh&#hڭw!Ѭ"J˫( } %PK!HOyֲ<f!libaloha-0.0.1.dist-info/METADATASn@}WK! QQTTbxuv;kR%?xg9sDBfRp]:c1_XF:^,I}] ["  ["h 1u  Ih`"Lq)[QȘT-@&"xC{Lj(4N~~f"| !n?<'7|ʸBNsP)wso3K$3E!|XTi ;! 3\`kN'/3"{JKK1ʨRdcO{7'3ޝx_ceɥ1U?l rql)<2mBG!ׯspm*8hu-z=8+}gSp~GnxYdP.;Ǽ)Cm*ǒ Pf{iӸ<7wi?ܣ3֙6Hǘ!-盲`c'>Lզkb!NAe_B.31;mm kУ<Ѐ:Ny~5 NDfe2Bzj/+uR}*K]PK!H2]Dlibaloha-0.0.1.dist-info/RECORD}ɶJy E ZQ 4Od\E: ~ZoH d̑o˥! 2ԵFqXtoŧH4&fXVsb1.g1XV-@5{aOiv3Q"EdW)q]˦xc4 o[= kq6mWe_ p9@~;vRN8FOM!jiqIT}g.x)"m>l?u[0bdt]graVװF8YzAznQ# \ eAaI ,Kcȵ E3uJTk4JѸVAob;~na'n\*9Nsj0*9eQ=~pB~pXU'&L?3Z/BX/i Ï/^„rl[o VWPߧs=. ,Mxd3JU^@՚vߘyL&{gCsh'bڵX &1l-m97iQշ;o~n02$E+d9V $!ݲ2# 2/FY݆N7gzM!:n]<9c{e1u~봧 Bu10]$:"w]4#@oUbj ~37 ij;Dq;w[`eSϦaPK!libaloha/__init__.pyPK!\C332libaloha/bin/__init__.pyPK!mS S 큛libaloha/bin/check_ip.pyPK!ˣ**$ libaloha/cache/__init__.pyPK!cclibaloha/cache/exceptions.pyPK!,9ԏ #libaloha/cache/redis.pyPK!Ȫ:vvlibaloha/django/__init__.pyPK!ɻ  libaloha/django/views.pyPK!R> > $libaloha/markdown/__init__.pyPK!/ _/libaloha/network.pyPK!RE-<libaloha/settings.pyPK!1(h{$$=libaloha/sms.pyPK!HKMT)UDlibaloha-0.0.1.dist-info/entry_points.txtPK!V Dlibaloha-0.0.1.dist-info/LICENSEPK!HlŃTTGlibaloha-0.0.1.dist-info/WHEELPK!HOyֲ<f!Glibaloha-0.0.1.dist-info/METADATAPK!H2]DJlibaloha-0.0.1.dist-info/RECORDPKsM