Skip to content

Commit

Permalink
Merge pull request #3 from Geek-MD/develop
Browse files Browse the repository at this point in the history
Upgrade to v0.3.0
  • Loading branch information
Geek-MD authored Jul 9, 2023
2 parents 0523629 + 630e7fe commit 8eb7053
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 32 deletions.
35 changes: 27 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,42 @@ Now open ***config.json*** with the editor of your preference, and change *"time
nano config.json
```

Now, you have to create a cron job which will execute the script at a defined time and day. In the example, the script will run every 4 hours from monday to sunday.
Now, you have to create a service at ***systemd*** which will execute the script and restart it on failure.

```
crontab -e
0 */4 * * * python3 /home/emontes/python/apple-security-updates-notifier/asun.py
Ctrl O
Ctrl X
sudo nano /etc/systemd/system/apple-security-updates.service
```

Obviously you can change change the time interval at wich the script is executed, modifying the cron command. I recomend [https://crontab.guru](https://crontab.guru) to do that.
Paste the content of *apple-security-updates.service* file. Be sure to modify *ExecStart* with the path to the python script, and *Environment* with the route for python libraries.

Finally you have to reboot so changes take effect.
To get PYTHONPATH, first you need to know which version of python you have installed.

```
sudo reboot
python3 --version
```

In my case is *python 3.9.2*. With that info you can search for the path of your python libraries. Get into python interpreter and run the following commands.

```
python3
import sys
sys.path
```

You will obtain a series of paths. Focus on the one that has a structure similar to *'/home/<user>/.local/lib/python3.9/site-packages'*. Note that it makes mention to *python3.9* which is the same version that is running in your system. Paste the path replacing <path_to_your_python_packages>. Do not include quotation marks.

Save with Ctrl-O and exit with Ctrl X.

Now you have to reload *systemd* daemons, enable and start the service

```
sudo systemctl daemon-reload
sudo systemctl enable apple-security-updates.service
sudo systemctl start apple-security-updates.service
```

The service will take some time to start because of *ExecStartPre* section which will wait for 60 seconds. This is due to a recomendation found on several forums which intention is to ensure that the script executes only when the system is fully loaded.

## Note

This is a first workaround attempt for a persistent bot in the near future.
17 changes: 17 additions & 0 deletions apple-security-updates.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[Unit]
Description=Apple Security Updates Notifier
After=multi-user.target

[Service]
Type=simple
Environment=DISPLAY=:0
ExecStartPre=/bin/sleep 60
ExecStart=/usr/bin/python3 <absolute_path_to_file>/asu_notifier.py
Restart=on-failure
RestartSec=30s
KillMode=process
TimeoutSec=infinity
Environment="PYTHONPATH=$PYTHONPATH:<path_to_your_python_packages>"

[Install]
WantedBy=multi-user.target
63 changes: 45 additions & 18 deletions apple_security_updates.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
#!/usr/bin/env python
#!/usr/bin/env python3

# Apple Updates v0.2.0
# Apple Updates v0.3.0
# Python script that checks for Apple software updates, and notifies via Telegram Bot.
# This is a first workaround attempt for a persistent bot in the near future.

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

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

os.chdir('/home/emontes/python/apple-security-updates-notifier')

# set global variables
global apple_file, db_file, log_file, localtime, bot_token, chat_ids
Expand All @@ -40,6 +45,7 @@
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 = ?; """


def get_config():
global apple_file, db_file, log_file, localtime, bot_token, chat_ids
config = open('config.json', 'r')
Expand All @@ -52,6 +58,7 @@ def get_config():
bot_token = data['bot_token']
chat_ids = data['chat_ids']


def create_connection(file):
if not os.path.isfile(file):
logging.info(f'\'{file}\' database created.')
Expand All @@ -62,6 +69,7 @@ def create_connection(file):
logging.error(str(error))
return conn


def create_table(conn, sql_create_table, table_name):
with contextlib.suppress(Error):
try:
Expand All @@ -70,6 +78,7 @@ def create_table(conn, sql_create_table, table_name):
except Error as error:
logging.error(str(error))


def get_updates(conn, full_update):
cursor = conn.cursor()
response = requests.get(apple_file)
Expand All @@ -80,12 +89,16 @@ def get_updates(conn, full_update):
logging.info('No updates available.')
else:
update_databases(conn, content, file_hash, full_update)
conn.commit()
conn.close()


def update_databases(conn, content, file_hash, full_update):
log_date = datetime.now(tz=localtime)
update_main_database(conn, log_date, file_hash, full_update)
update_updates_database(conn, file_hash, content, full_update)


def update_main_database(conn, log_date, file_hash, full_update):
cursor = conn.cursor()
if full_update:
Expand All @@ -96,6 +109,7 @@ def update_main_database(conn, log_date, file_hash, full_update):
logging.info(log_message)
conn.commit()


def update_updates_database(conn, file_hash, content, full_update):
cursor = conn.cursor()
soup = BeautifulSoup(content, 'html.parser')
Expand All @@ -114,6 +128,7 @@ def update_updates_database(conn, file_hash, content, full_update):
conn.commit()
apprise_notification(conn, recent_updates, full_update)


def formatted_content(content):
content_list = []
for i, row in enumerate(content):
Expand All @@ -122,7 +137,8 @@ def formatted_content(content):
columns = row.find_all('td')
date_str = columns[2].get_text().strip().replace('\xa0', ' ')
update_date = check_date(date_str)
update_product = columns[0].get_text().strip().replace('Esta actualización no tiene ninguna entrada de CVE publicada.', '').replace('\xa0', ' ').replace('\n', '')
update_product = columns[0].get_text().strip().replace(
'Esta actualización no tiene ninguna entrada de CVE publicada.', '').replace('\xa0', ' ').replace('\n', '')
update_target = columns[1].get_text().replace('\xa0', ' ').replace('\n', '')
try:
update_link = columns[0].find('a')['href']
Expand All @@ -133,6 +149,7 @@ def formatted_content(content):
content_list.reverse()
return content_list


def check_date(date_str):
pattern = r'(\d{1,2}) de (\w+) de (\d{4})'
try:
Expand All @@ -147,6 +164,7 @@ def check_date(date_str):
except Exception:
return date_str


def apprise_notification(conn, updates, full_update):
apprise_object = Apprise()
apprise_message = build_message(conn, updates, full_update)
Expand All @@ -155,6 +173,7 @@ def apprise_notification(conn, updates, full_update):
apprise_object.add(apprise_syntax, tag='telegram')
apprise_object.notify(apprise_message, tag="telegram")


def build_message(conn, last_updates, full_update):
max_updates = 5
cursor = conn.cursor()
Expand Down Expand Up @@ -184,6 +203,7 @@ def build_message(conn, last_updates, full_update):
apprise_message += f' - {element[2]}\n'
return apprise_message


def main():
get_config()

Expand All @@ -194,16 +214,23 @@ def main():
# create a database connection
conn: Connection = create_connection(db_file)
cursor = conn.cursor()
full_update = cursor.execute(sql_check_empty_database).fetchone()[0] == 0
if full_update:
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')
create_table(conn, sql_create_updates_table, 'updates')

get_updates(conn, full_update)
# 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)

conn.commit()
conn.close()

if __name__ == '__main__':
main()
main()
12 changes: 6 additions & 6 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"apple_file": "https://support.apple.com/es-es/HT201222",
"db_file": "apple_security_updates.db",
"log_file": "apple_security_updates.log",
"timezone": "timezone",
"bot_token": "bot_token",
"timezone": "America/Santiago",
"bot_token": "5198410262:AAFfyI5u-HLBXqbzsm2bx7dEy1vuTqZoKD0",
"chat_ids": [
"chat_id_1",
"chat_id_2",
"chat_id_3"
"-1001261613616",
"-2202928",
"-923786492"
]
}
}

0 comments on commit 8eb7053

Please sign in to comment.