Skip to content

Commit

Permalink
Merge pull request #7 from Geek-MD/develop
Browse files Browse the repository at this point in the history
Add files via upload
  • Loading branch information
Geek-MD authored Sep 20, 2023
2 parents e7dd436 + 30162de commit abde2f5
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 155 deletions.
46 changes: 15 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,33 @@

Python script that checks for Apple software updates, and notifies via Telegram Bot.

## Previous steps

This script relies on a previously created Telegram bot. If you don't have one follow [this steps](https://www.alphr.com/telegram-create-bot/) to create one. You need your bot token at hand in order to run this script.

Additionally, you have to install all dependencies listed in *requirements.txt* using
## Previous steps

Clone this repo with...

```
pip install -r requirements.txt
git clone https://github.com/Geek-MD/apple-security-updates-notifier.git
```

## Basic installation and configuration
Now execute the *start.sh* file with the following command. This will install all dependencies needed by the script
listed on *requirements.txt*.

Clone this repo with...

```
git clone https://github.com/Geek-MD/apple-security-updates-notifier.git
./start.sh
```

Once the script is finished, you will get help information on how to run the python script.

## Basic configuration

To run the script you must add *-b* or *--bot-token* option followed by the bot token itself. Bot token is mandatory, if you don't provide it, the script will exit with an error. Timezone or country arguments are optional. The default timezone is UTC.
The basic syntax to run the script is as the following examples.

```
python3 config.py -b <bot_token>
python3 config.py --bot-token <bot_token>
python3 asu-notifier.py -b <bot_token>
python3 asu-notifier.py --bot-token <bot_token>
```

You can check the script help by using *-h* or *--help* option.
Expand All @@ -44,7 +47,8 @@ python3 config.py --version

## Advanced configuration

There are two options, independent one from the other, to define the time zone of the bot. You can use timezone or country options. Remember that this is optional.
There are two options, independent one from the other, to define the bot timezone. You can use timezone or country
options. Remember that this is optional.
Additionally, you can define the chat ids where Telegram notifications will be sent.

### Timezone or country configuration
Expand Down Expand Up @@ -77,26 +81,6 @@ python3 config.py -b <bot_token> -i <chat_id_1>
python3 config.py --bot-token <bot_token> --chat-ids <chat_id_1> <chat_id_2>
```

## Functionality

This piece of software comprehends 2 *.py* files, 1 *.json* file and 1 *.sh* file. Python files are *config.py* which runs just once at start, and *apple_security_updates.py* which is the persistent script. The JSON file is *asu-notifier.json* which contains some basic information for *config.py*. Finally, the bash file is *asu-notifier.sh* which contains shell commands in order to run the persistent Python script as a systemd service.

Once the script is run, it will automatically recreate 2 files using the information you gave it, a *asu-notifier.service* file used to start a *systemd* service, and a *config.json* file with the configuration needed by the persistent script.

Finally, the script will execute the bash file in order to enable and start the systemd service. This will take some time to start because of *ExecStartPre* section which will wait for 60 seconds. This is due to a recommendation found on several forums which intention is to ensure that the script executes only when the system is fully loaded.

When you see the system prompt, if you haven't received an error message, the script will be running in background, and you'll receive a Telegram Notification with the latest Apple Security Updates.

## Troubleshooting

Eventually, the systemd service may need to be restarted due to a system restart or by any other reason. You can do it manually using the following shell commands.

```
sudo systemctl daemon-reload
sudo systemctl enable asu-notifier.service
sudo systemctl start asu-notifier.service
```

## Note

This is a first workaround attempt for a permanent bot in the near future, instead of a self-hosted bot.
66 changes: 21 additions & 45 deletions asu-bot.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,49 @@
#!/usr/bin/env python3

# Apple Security Updates Notifier v0.4.1
# Python script that checks for Apple software updates, and notifies via Telegram Bot.
# This is a first workaround attempt for a permanent bot in the near future.
# Apple Security Updates Notifier v0.4.2
# File: asu-bot.py
# Description: Secondary component of ASU Notifier, which will run hourly and notify via Telegram of any new security
# update.

import contextlib
import datetime
import hashlib
import json
import logging
import os
import os.path
import re
import sqlite3
import time
from datetime import datetime
from sqlite3 import Error, Connection
from typing import TypeVar

import pytz
import requests
import schedule
from apprise import Apprise
from bs4 import BeautifulSoup

working_dir = os.getcwd()
os.chdir(working_dir)

# set global variables
global apple_url, db_file, log_file, localtime, bot_token, chat_ids

# SQL queries
sql_check_empty_database: str = """ SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='main' """
sql_create_main_table: str = """ CREATE TABLE IF NOT EXISTS main ( main_id integer PRIMARY KEY AUTOINCREMENT, log_date text NOT
NULL, file_hash text NOT NULL, log_message text NOT NULL ); """
sql_create_updates_table: str = """ CREATE TABLE IF NOT EXISTS updates ( update_id integer PRIMARY KEY AUTOINCREMENT, update_date
text NOT NULL, update_product text NOT NULL, update_target text NOT NULL, update_link text, file_hash text NOT NULL ); """
sql_main_table_hash_check: str = """ SELECT COUNT(*) FROM main WHERE file_hash = ? """
sql_main_table: str = """ INSERT INTO main (log_date, file_hash, log_message) VALUES (?, ?, ?); """
sql_updates_table: str = """ INSERT INTO updates (update_date, update_product, update_target, update_link, file_hash)
VALUES (?, ?, ?, ?, ?); """
sql_get_updates: str = """ SELECT update_date, update_product, update_target, update_link FROM updates ORDER BY update_id ASC; """
sql_get_updates: str = """SELECT update_date, update_product, update_target, update_link FROM updates ORDER BY
update_id ASC;"""
sql_get_updates_count: str = """ SELECT count(update_date) FROM updates WHERE update_date = ?; """
sql_get_last_updates: str = """ SELECT update_date, update_product, update_target, update_link FROM updates WHERE update_date = ?; """
sql_get_last_updates: str = """SELECT update_date, update_product, update_target, update_link FROM updates WHERE
update_date = ?;"""
sql_get_last_update_date: str = """ SELECT update_date FROM updates ORDER BY update_id DESC LIMIT 1; """
sql_get_update_dates: str = """ SELECT DISTINCT update_date FROM updates; """
sql_get_date_update: str = """ SELECT update_date, update_product, update_target, update_link FROM updates WHERE update_date = ?; """
sql_get_date_update: str = """SELECT update_date, update_product, update_target, update_link FROM updates WHERE
update_date = ?;"""


def get_config():
def get_config(local_path):
global apple_url, db_file, log_file, localtime, bot_token, chat_ids
config = open('config.json', 'r')
config = open(f'{local_path}/config.json', 'r')
data = json.loads(config.read())
apple_url = data['apple_url']
db_file = data['db_file']
Expand All @@ -68,14 +63,6 @@ def create_connection(file):
logging.error(str(error))
return conn

def create_table(conn, sql_create_table, table_name, file):
with contextlib.suppress(Error):
try:
conn.cursor().execute(sql_create_table)
logging.info(f'\'{file}\' - \'{table_name}\' table created.')
except Error as error:
logging.error(str(error))

def get_updates(conn, full_update):
cursor = conn.cursor()
response = requests.get(apple_url)
Expand Down Expand Up @@ -121,6 +108,7 @@ def update_updates_database(conn, file_hash, content, full_update):
cursor.execute(sql_updates_table, (element[0], element[1], element[2], element[3], file_hash))
logging.info(log_message)
conn.commit()
recent_updates.reverse()
apprise_notification(conn, recent_updates, full_update)

def formatted_content(content):
Expand Down Expand Up @@ -162,7 +150,7 @@ def apprise_notification(conn, updates, full_update):
apprise_syntax = f'tgram://{bot_token}/'
for chat_id in chat_ids:
apprise_syntax += f'{chat_id}/'
apprise_syntax *= '?format=markdown'
apprise_syntax += '?format=markdown'
apprise_object.add(apprise_syntax, tag='telegram')
apprise_object.notify(apprise_message, tag="telegram")

Expand All @@ -173,7 +161,7 @@ def build_message(conn, last_updates, full_update):
last_updates = []
update_dates = cursor.execute(sql_get_update_dates).fetchall()
for element in reversed(update_dates):
if max_updates >= 0:
if max_updates > 0:
query = cursor.execute(sql_get_date_update, element).fetchall()
query_count = cursor.execute(sql_get_updates_count, element).fetchone()[0]
last_updates += query
Expand All @@ -196,31 +184,19 @@ def build_message(conn, last_updates, full_update):
return apprise_message

def main():
get_config()
local_file = __file__
local_path = os.path.dirname(local_file)
get_config(local_path)

# logging
log_format = '%(asctime)s -- %(message)s'
logging.basicConfig(filename=log_file, encoding='utf-8', format=log_format, level=logging.INFO)

# create a database connection
conn: Connection = create_connection(db_file)
cursor = conn.cursor()
empty_database = cursor.execute(sql_check_empty_database).fetchone()[0] == 0
if empty_database:
# create database tables and populate them
create_table(conn, sql_create_main_table, 'main', db_file)
create_table(conn, sql_create_updates_table, 'updates', db_file)

# run first database update
get_updates(conn, full_update=True)

# Schedule the function to run every hour
schedule.every().hour.do(get_updates, conn=conn, full_update=False)

# Run the scheduler continuously
while True:
schedule.run_pending()
time.sleep(1)

if __name__ == '__main__':
main()
main()
2 changes: 1 addition & 1 deletion asu-notifier.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"prog_name_short": "asu-notifier",
"prog_name_long": "Apple Security Updates Notifier",
"version": "v0.4.1",
"version": "v0.4.2",
"apple_url": "https://support.apple.com/es-es/HT201222"
}
Loading

0 comments on commit abde2f5

Please sign in to comment.