Compare commits

...

7 commits

Author SHA1 Message Date
+++ 9fe94d7e6e umstellung auf requests
modul mastodon gegen requests getauscht, import exceptions eingefuegt,
InitException wieder entfernt
2022-07-14 21:47:16 +02:00
+++ 0eba169038 kleine aenderung im logging 2022-07-13 22:10:07 +02:00
+++ 666a997a90 erste version eines toots 2022-07-13 19:10:17 +02:00
+++ c7fc0b9eff angefangen toot in thread auszulagern 2022-07-12 21:57:20 +02:00
+++ 930ab7eef3 funktion send_toot() hinzu 2022-07-10 19:38:29 +02:00
+++ edece83dd1 kleinere umstrukturierung
auswertung der konfig fuer mastodon, default_config erweitert,
set_values() in get_status_and_timestamp() umbenannt,
statusstring und timestamp werden in main() aufgerufen und an andere funktionen uebergeben
2022-07-10 18:17:33 +02:00
+++ c4d02a73c9 konfiguration fuer mastodon hinzu 2022-07-10 17:54:37 +02:00
2 changed files with 125 additions and 26 deletions

View file

@ -23,3 +23,9 @@ cert = ./certs/statusclient-pub.pem
[api] [api]
api = ./api api = ./api
template = ./api_template template = ./api_template
[mastodon]
send = true
host = localhost
token = aaaaa-bbbbb-ccccc-ddddd-eeeee

View file

@ -2,20 +2,25 @@
# file: apistatusd.py # file: apistatusd.py
# date: 26.07.2019 # date: 26.07.2019
# email: berhsi@web.de # mail: berhsi@web.de
# Status server, listening for door status updates. The IPv4 address and port # Status server, listening for door status updates. The IPv4 address and port
# to listen on are configurable, by default localhost:10001 is used. The # to listen on are configurable, by default localhost:10001 is used. The
# connection is secured by TLS and client side authentication. # connection is secured by TLS and client side authentication.
import json try:
import logging import json
import os import logging
import socket import os
import ssl import socket
import sys import ssl
from time import time, sleep import sys
import configparser import requests
import threading
from time import time, localtime, strftime, sleep
import configparser
except ImportException as e:
print('Import error: {}'.format(e))
def certs_readable(config): def certs_readable(config):
@ -32,7 +37,6 @@ def certs_readable(config):
return False return False
return True return True
def print_config(config): def print_config(config):
''' '''
Logs the config with level debug. Logs the config with level debug.
@ -41,7 +45,10 @@ def print_config(config):
for section in config.sections(): for section in config.sections():
logging.debug('Section {}'.format(section)) logging.debug('Section {}'.format(section))
for i in config[section]: for i in config[section]:
logging.debug(' {}: {}'.format(i, config[section][i])) if i == 'token':
logging.debug(' {}: {}'.format(i, 'aaaaa-bbbbb-ccccc-ddddd-eeeee'))
else:
logging.debug(' {}: {}'.format(i, config[section][i]))
def print_ciphers(cipherlist): def print_ciphers(cipherlist):
''' '''
@ -101,25 +108,22 @@ def receive_buffer_is_valid(raw_data):
logging.debug('Argument is not valid: {}'.format(raw_data)) logging.debug('Argument is not valid: {}'.format(raw_data))
return False return False
def change_status(status, timestamp, filename):
def change_status(raw_data, api):
''' '''
Write the new status together with a timestamp into the Space API JSON. Write the new status together with a timestamp into the Space API JSON.
param 1: byte object param 1: byte object
param 2: string param 2: string
return: boolean return: boolean
''' '''
logging.debug('Change status API') logging.debug('Change status API')
# todo: use walrus operator := when migrating to python >= 3.8 # todo: use walrus operator := when migrating to python >= 3.8
data = read_api(api) data = read_api(filename)
if data is False: if data is False:
return False return False
status, timestamp = set_values(raw_data) if os.access(filename, os.W_OK):
if os.access(api, os.W_OK):
logging.debug('API file is writable') logging.debug('API file is writable')
with open(api, 'w') as api_file: with open(filename, 'w') as api_file:
logging.debug('API file open successfull') logging.debug('API file open successfull')
data["state"]["open"] = status data["state"]["open"] = status
data["state"]["lastchange"] = timestamp data["state"]["lastchange"] = timestamp
@ -133,10 +137,9 @@ def change_status(raw_data, api):
else: else:
logging.error('API file is not writable. Wrong permissions?') logging.error('API file is not writable. Wrong permissions?')
return False return False
logging.info('Status successfull changed to {}'.format(status)) logging.info('API file successfull changed to {}'.format(status))
return True return True
def read_api(api): def read_api(api):
''' '''
Reads the Space API JSON into a dict. Returns the dict on success and Reads the Space API JSON into a dict. Returns the dict on success and
@ -146,7 +149,6 @@ def read_api(api):
return: dict or boolean return: dict or boolean
''' '''
logging.debug('Open API file: {}'.format(api)) logging.debug('Open API file: {}'.format(api))
# return early if the API JSON cannot be read # return early if the API JSON cannot be read
if not os.access(api, os.R_OK): if not os.access(api, os.R_OK):
logging.error('Failed to read API file') logging.error('Failed to read API file')
@ -163,13 +165,12 @@ def read_api(api):
return False return False
return api_json_data return api_json_data
def get_status_and_time(raw_data):
def set_values(raw_data):
''' '''
Create a timestamp, changes the value of the given byte into a string Create a timestamp, changes the value of the given byte into a string
and returns both. and returns both.
param 1: byte object param 1: byte object
return: tuple return: tuple (boolean, integer)
''' '''
status = True if raw_data.decode('utf-8', 'strict') == '1' else False status = True if raw_data.decode('utf-8', 'strict') == '1' else False
timestamp = int(str(time()).split('.')[0]) timestamp = int(str(time()).split('.')[0])
@ -178,6 +179,83 @@ def set_values(raw_data):
str(timestamp), str(status))) str(timestamp), str(status)))
return (status, timestamp) return (status, timestamp)
def join_path(host, api):
'''
Becomes two parts (host and api) of the mastodon url and concanate them
param1: string
param2: string
return: string
'''
url = ''
try:
if host[-1] == '/' and api[0] == '/':
url = ''.join((host, api[1:]))
elif host[-1] != '/' and api[0] != '/':
url = '/'.join((host, api))
else:
url = ''.join((host, api))
except TypeError as e:
logging.error('Can´t join path: {}'.format(e))
return url
class Toot(threading.Thread):
'''
The thread to toot the status to mastodon.
'''
def __init__(self, status, timestamp, config):
'''
param1: boolean
param2: integer
param3: dictionary
'''
threading.Thread.__init__(self)
self.status = status
self.config = config
self.timestamp = timestamp
self.api = '/api/v1/statuses'
self.auth = {'Authorization': ''}
self.data = {'status': ''}
self.url = ''
def run(self):
'''
return: boolean
'''
timeformat = '%d.%m.%Y %H:%M Uhr'
# check if status is valid
if self.status not in (True, False):
logging.error('Invalid status to toot')
return False
# convert seconds into timestring
try:
timestring = strftime(timeformat, localtime(self.timestamp))
except Exception as e:
logging.error('Can not convert timestamp into timestring')
return False
# set status message
if self.status == True:
self.data['status'] = 'Krautspace is open since: {}'.format(timestring)
elif self.status == False:
self.data['status'] = 'Krautspace is closed since: {}'.format(timestring)
logging.debug('Message: {}'.format(self.data['status']))
# build mastodon api url
self.url = join_path(self.config['mastodon']['host'], self.api)
# build authentcation header
self.auth['Authorization'] = 'Bearer {}'.format(
self.config['mastodon']['token'])
# and finaly send request to mastodon
try:
logging.debug('Try to toot status')
response = requests.post(self.url, data = self.data,
headers = self.auth)
if response.status_code == 200:
logging.info('Toot successful send')
return True
else:
logging.error('Failed to toot. Response: {}'.format(response.status_code))
except Exception as e:
logging.error('Exception occurred: {}'.format(e))
return False
def main(): def main():
''' '''
@ -188,7 +266,6 @@ def main():
OP_DONT_ISERT_EMPTY_FRAGMENTS: prevention agains CBC 4 attack OP_DONT_ISERT_EMPTY_FRAGMENTS: prevention agains CBC 4 attack
(cve-2011-3389) (cve-2011-3389)
''' '''
answer = '3'.encode(encoding='utf-8', errors='strict') answer = '3'.encode(encoding='utf-8', errors='strict')
loglevel = logging.WARNING loglevel = logging.WARNING
formatstring = '%(asctime)s: %(levelname)s: %(message)s' formatstring = '%(asctime)s: %(levelname)s: %(message)s'
@ -211,6 +288,11 @@ def main():
'api': { 'api': {
'api': './api', 'api': './api',
'template': './api_template' 'template': './api_template'
},
'mastodon': {
'send': 'false',
'host': 'localhost',
'token': 'aaaaa-bbbbb-ccccc-ddddd-eeeee'
} }
} }
configfile = './apistatusd.conf' configfile = './apistatusd.conf'
@ -293,8 +375,19 @@ def main():
raw_data = conn.recv(1) raw_data = conn.recv(1)
if receive_buffer_is_valid(raw_data) is True: if receive_buffer_is_valid(raw_data) is True:
if change_status(raw_data, config['api']['api']) is True: status, timestamp = get_status_and_time(raw_data)
if change_status(status, timestamp, config['api']['api']) is True:
answer = raw_data answer = raw_data
if config['mastodon']['send'].lower() == 'true':
logging.debug('Toot is set to true')
try:
toot_thread = Toot(status, timestamp, config)
toot_thread.run()
except InitException as e:
logging.error('InitException: {}'.format(e))
except Exception as ex:
logging.debug('Exception: {}'.format(ex))
else: logging.debug('Toot is set to false')
if conn: if conn:
logging.debug('Send {} back'.format(raw_data)) logging.debug('Send {} back'.format(raw_data))
conn.send(answer) conn.send(answer)