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
template = ./api_template
[mastodon]
send = true
host = localhost
token = aaaaa-bbbbb-ccccc-ddddd-eeeee

View file

@ -2,20 +2,25 @@
# file: apistatusd.py
# date: 26.07.2019
# email: berhsi@web.de
# mail: berhsi@web.de
# Status server, listening for door status updates. The IPv4 address and port
# to listen on are configurable, by default localhost:10001 is used. The
# connection is secured by TLS and client side authentication.
import json
import logging
import os
import socket
import ssl
import sys
from time import time, sleep
import configparser
try:
import json
import logging
import os
import socket
import ssl
import sys
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):
@ -32,7 +37,6 @@ def certs_readable(config):
return False
return True
def print_config(config):
'''
Logs the config with level debug.
@ -41,7 +45,10 @@ def print_config(config):
for section in config.sections():
logging.debug('Section {}'.format(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):
'''
@ -101,25 +108,22 @@ def receive_buffer_is_valid(raw_data):
logging.debug('Argument is not valid: {}'.format(raw_data))
return False
def change_status(raw_data, api):
def change_status(status, timestamp, filename):
'''
Write the new status together with a timestamp into the Space API JSON.
param 1: byte object
param 2: string
return: boolean
'''
logging.debug('Change status API')
# todo: use walrus operator := when migrating to python >= 3.8
data = read_api(api)
data = read_api(filename)
if data is False:
return False
status, timestamp = set_values(raw_data)
if os.access(api, os.W_OK):
if os.access(filename, os.W_OK):
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')
data["state"]["open"] = status
data["state"]["lastchange"] = timestamp
@ -133,10 +137,9 @@ def change_status(raw_data, api):
else:
logging.error('API file is not writable. Wrong permissions?')
return False
logging.info('Status successfull changed to {}'.format(status))
logging.info('API file successfull changed to {}'.format(status))
return True
def read_api(api):
'''
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
'''
logging.debug('Open API file: {}'.format(api))
# return early if the API JSON cannot be read
if not os.access(api, os.R_OK):
logging.error('Failed to read API file')
@ -163,13 +165,12 @@ def read_api(api):
return False
return api_json_data
def set_values(raw_data):
def get_status_and_time(raw_data):
'''
Create a timestamp, changes the value of the given byte into a string
and returns both.
param 1: byte object
return: tuple
return: tuple (boolean, integer)
'''
status = True if raw_data.decode('utf-8', 'strict') == '1' else False
timestamp = int(str(time()).split('.')[0])
@ -178,6 +179,83 @@ def set_values(raw_data):
str(timestamp), str(status)))
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():
'''
@ -188,7 +266,6 @@ def main():
OP_DONT_ISERT_EMPTY_FRAGMENTS: prevention agains CBC 4 attack
(cve-2011-3389)
'''
answer = '3'.encode(encoding='utf-8', errors='strict')
loglevel = logging.WARNING
formatstring = '%(asctime)s: %(levelname)s: %(message)s'
@ -211,6 +288,11 @@ def main():
'api': {
'api': './api',
'template': './api_template'
},
'mastodon': {
'send': 'false',
'host': 'localhost',
'token': 'aaaaa-bbbbb-ccccc-ddddd-eeeee'
}
}
configfile = './apistatusd.conf'
@ -293,8 +375,19 @@ def main():
raw_data = conn.recv(1)
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
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:
logging.debug('Send {} back'.format(raw_data))
conn.send(answer)