Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
10b1cab
cron job for ETL is working, no duplicate jobs
Apr 10, 2026
911a3d0
email cron job working! need to handle some more edge cases though
Apr 10, 2026
d6e963e
There may be a better place to plac this, but hopefully will do for now
Apr 10, 2026
9efc3b8
removed some unused functions, added dependency installation for emai…
Apr 10, 2026
97c1a5a
Handled edege cases in my script, checked for and installed python de…
Apr 13, 2026
d3f6bfd
removed email_scheduler.py (working entirely from bash now) ;)
Apr 13, 2026
1c66d06
Merge branch 'develop' into cron_scheduling
Apr 13, 2026
5fb0402
Moved installation of python and dependencies to initial_setup.sh
Apr 13, 2026
22fe006
Fix script execution by adding .sh extension
JacobLanter Apr 13, 2026
3fda0bf
Fixed Error with Windows Formatting
JulianValleroy Apr 13, 2026
5b9869f
Added Cron deletion in initial setup script
JulianValleroy Apr 13, 2026
83139c5
Fixed email time formatting (base 10), restored config reader fix (cr…
JacobLanter Apr 14, 2026
3b5e53e
removed redundant check for 00 in the email send time field
Apr 14, 2026
507dd47
see last commit, actually removed it this time lol
Apr 14, 2026
2ea38ef
fix cron environment and config path in application.py
JacobLanter Apr 14, 2026
096046e
Created get ip script that is added to the initial script. I modified…
JacobLanter Apr 15, 2026
c8058e0
Fix typo in email HTML link text
JacobLanter Apr 15, 2026
cf15474
Merge branch 'develop' into cron_scheduling
Apr 15, 2026
5833d98
Ensures .env and config.ini exists before initial scripts continues. …
JacobLanter Apr 15, 2026
d90deab
Added -i to the cron jobs check in initial setup. This confirms delet…
JacobLanter Apr 15, 2026
efed9e3
Implemented functionality to automatically contact the correct smtp s…
Apr 16, 2026
2004ef3
Added else catch to avoid false error in domain_to_server
Apr 16, 2026
36fb11d
added subprocess run inside email_sender to run get_ip.sh so that lat…
JacobLanter Apr 16, 2026
90a2b80
Fixed Issue with Dialogue Box Memory
JulianValleroy Apr 16, 2026
dc2964a
Fixed Issue with multiple .env files
JulianValleroy Apr 16, 2026
8cda9b7
Added check for existing .env file
Apr 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ VERKADA_API_KEY=This should be your API Key==
ELASTIC_PASSWORD=At least six characters long
KIBANA_SYSTEM_PASSWORD=At least six characters long and you will need to set in Kibana refer to README
KIBANA_ENCRYPTION_KEY=Create Key using command "openssl rand -base64 32" in linux or wsl==
EMAIL_PASSWORD = Password for the email account you are sending the dashboard from
EMAIL_PASSWORD = Password for the email account you are sending the dashboard from
WINDOWS_IP=This is the IP for your device
18 changes: 9 additions & 9 deletions config.ini.example
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[Email]
EMAIL_TO=receiver_email@example.com
EMAIL_FROM=your_email@example.com
EMAIL_BODY_PREFIX=Click the link below to access the Kibana dashboard:
EMAIL_SUBJECT=Subject for the Email
EMAIL_SEND_TIME=09:00
email_to = email@example.com
email_from = email@example.com
email_body_prefix = Click the link below to access link:
email_subject = Subject Line goes here
email_send_time = 14:40

[Verkada]
# Default number of days to pull on first run or if index is empty
TIME_DELTA_INSTALLATION=365
time_delta_installation = 3

# This is how often you want to update elasticSearch (in 24-hour format)
# i.e. every 15 minutes -> ELASTIC_UPDATE_INTERVAL=00:15
ELASTIC_UPDATE_INTERVAL = 00:15
# This is how often you want to update elasticSearch
# i.e. every 15 minutes -> ELASTIC_UPDATE_INTERVAL=15m
elastic_update_interval = 15m
97 changes: 97 additions & 0 deletions scripts/cron_creation.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/usr/bin/env bash
# Run this from the root of the repo

# Exit on errors, prevent undefined variables, and fail if any command in a pipeline fails
set -euo pipefail

# Move into repo root
cd "$(dirname "$0")/.."

# for reading time fields
declare update_interval
declare cron_command
declare cron_expression

extract_field()
{
echo "$(grep -i "$1" config.ini | cut -d '=' -f2 | xargs)"
}

fail() {
echo
echo "ERROR: $1"
exit 1
}

parse_email_time_field()
{
local h_or_m=$(extract_field "EMAIL_SEND_TIME" | cut -d ':' -f$1)
if [[ "$h_or_m" =~ ^[0-9]{2}$ ]]; then
local stoi=10#$h_or_m

# handle cases where hour > 23 and minute > 59
if (( ("$1" == "1" && $stoi > 23) || ("$1" == "2" && $stoi > 59) )); then
echo "-1"

else
echo $((10#$h_or_m))
fi

else
echo "-1"
fi
}

write_cron_job()
{
cat <(fgrep -i -v "$cron_command" <(crontab -l)) <(echo "$cron_expression") | crontab -
}

echo "Creating cron job for ETL..."

update_interval=$(extract_field "ELASTIC_UPDATE_INTERVAL")

CRON_EXEC="$(which "docker")"
CRON_TARGET="$(realpath "compose.yaml")"

cron_command="${CRON_EXEC} compose -f ${CRON_TARGET} up -d"

case $update_interval in
*m)
minutes=${update_interval%m}
cron_expression="*/$minutes * * * * $cron_command"
;;
*h)
hours=${update_interval%h}
cron_expression="0 */$hours * * * $cron_command"
;;
*d)
days=${update_interval%d}
cron_expression="0 0 */$days * * $cron_command"
;;
*)
fail "Invalid ELASTIC_UPDATE_INTERVAL"
;;
esac

write_cron_job
echo "ETL cron job created!"


echo "Creating cron job for email sender..."

CRON_EXEC="$(pwd)/.venv/bin/python"
CRON_TARGET=$(realpath "src/email_sender.py")

cron_command="${CRON_EXEC} ${CRON_TARGET}"
cron_expression="$(parse_email_time_field "2") $(parse_email_time_field "1") * * * ${cron_command}"

# check if cron_expression contains "-1", this means we reached an edge case
# so send time format is invalid
if [[ "$cron_expression" == *"-1"* ]]; then
fail "Invalid EMAIL_SEND_TIME, must be in 24-hour format"
fi
write_cron_job
echo "Email cron job created!"


22 changes: 22 additions & 0 deletions scripts/get_ip.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
# Run this from the root of the repo

set -euo pipefail

# Move into repo root
cd "$(dirname "$0")/.."

WINDOWS_IP=$(/mnt/c/Windows/System32/ipconfig.exe | sed -n '/Wireless LAN adapter.*:/,/IPv4 Address/s/.*IPv4 Address[^:]*: //p' | head -n 1 | tr -d '\r' | xargs)

if [ -z "$WINDOWS_IP" ]; then
WINDOWS_IP=$(/mnt/c/Windows/System32/ipconfig.exe | sed -n '/Ethernet adapter.*:/,/IPv4 Address/s/.*IPv4 Address[^:]*: //p' | head -n 1 | tr -d '\r' | xargs)
fi

if [ -z "$WINDOWS_IP" ]; then
echo "ERROR: Could not determine Windows IP"
exit 1
fi

grep -q "^WINDOWS_IP=" .env && \
sed -i "s|^WINDOWS_IP=.*|WINDOWS_IP=$WINDOWS_IP|" .env || \
echo "WINDOWS_IP=$WINDOWS_IP" >> .env
39 changes: 39 additions & 0 deletions scripts/initial_setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,52 @@ set -euo pipefail
# Move into repo root
cd "$(dirname "$0")/.."

if crontab -l >/dev/null 2>&1; then
echo "Cron jobs exist"
echo "Deleting Cron jobs"
crontab -i -r
else
echo "No cron jobs"
fi

echo
echo "Running dependencies check..."
sudo apt update
sudo apt install -y unzip openssl
sudo apt install python3-venv
sudo apt install python3-tk
echo "Dependencies check complete..."

echo
echo "Setting up Python virtual environment and installing dependencies..."
if [ ! -d ".venv" ]; then
python3 -m venv .venv
fi
source .venv/bin/activate
pip install python-dotenv

echo
echo "Getting Windows IP"
./scripts/get_ip.sh
echo "Windows IP added to .env"

echo
echo "Ensuring config.ini exists..."
cp -n config.ini.example config.ini

echo
echo "Ensuring .env exists..."
cp -n .env.example .env

echo
echo "Launching setup dialogue box..."
python3 ./src/dialogueBox.py
echo "Setup dialogue box entry complete..."

echo
echo "building images from compose.yaml..."
docker compose build --no-cache

echo
echo "running elastic_setup.sh..."
./scripts/elastic_setup.sh
Expand All @@ -30,5 +65,9 @@ echo
echo "Starting normal secure stack..."
docker compose up -d

echo
echo "running cron_creation.sh..."
./scripts/cron_creation.sh

echo
echo "Setup complete."
5 changes: 4 additions & 1 deletion src/Application.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@
import os

from Verkada import VerkadaContext
from ConfigReader import config
import configparser
from datetime import datetime, date, timedelta

ELASTIC_PASSWORD = os.environ.get("ELASTIC_PASSWORD")
if not ELASTIC_PASSWORD:
print("ERROR: ELASTIC_PASSWORD has not been set, exiting...")
exit(1)

config = configparser.ConfigParser()
config.read("/config.ini")

def init():
args = CLI.setup_cli()

Expand Down
3 changes: 2 additions & 1 deletion src/ConfigReader.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import configparser
import Utils

config = configparser.ConfigParser()
config.read("/config.ini")
config.read(Utils.get_project_root() / "config.ini")
12 changes: 7 additions & 5 deletions src/dialogueBox.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ def Save_Button():
newTo = inpTo.get()
newFrom = inpFrom.get()
newSubject = inpSubject.get()
newMessage = inpMessage.get("1.0", "end-1c")
newMessage = inpMessage.get("1.0", "end").strip()
newSendTime = inpSendTime.get()
newFreq = freqVar.get()
newFreqUnit = timeUnit.get()
newEmailPass = inpEmailPass.get()
newVerkAPI = inpApiKey.get("1.0", "end-1c")
newVerkAPI = inpApiKey.get("1.0", "end").strip()
newElastPass = inpElastPass.get()
newKibPass =inpKibPass.get()
newKibEnc = inpKibEnc.get("1.0", "end-1c")
newKibEnc = inpKibEnc.get("1.0", "end").strip()

#Updates config values
co["Email"]["EMAIL_TO"] = newTo
Expand All @@ -40,6 +40,8 @@ def Save_Button():
dotenv.set_key(dotenv_file, "ELASTIC_PASSWORD", newElastPass)
dotenv.set_key(dotenv_file,"KIBANA_SYSTEM_PASSWORD", newKibPass)
dotenv.set_key(dotenv_file,"KIBANA_ENCRYPTION_KEY", newKibEnc)

dotenv.load_dotenv(dotenv_file, override=True)

#Writes new config values to file
with open(os.path.join(BASE_DIR, '..', 'config.ini'), "w") as f:
Expand All @@ -59,8 +61,8 @@ def generate_kibana_key():

co = configparser.ConfigParser()
co.read(os.path.join(BASE_DIR, '..', 'config.ini'))
dotenv.load_dotenv()
dotenv_file = ".env"
dotenv_file = os.path.join(BASE_DIR, '..', '.env')
dotenv.load_dotenv(dotenv_file)

root = tk.Tk(screenName=None, baseName='VerityBot', className='VerityBot', useTk=1)
frame = tk.Frame(root)
Expand Down
40 changes: 0 additions & 40 deletions src/email_scheduler.py

This file was deleted.

Loading
Loading