Newer
Older
htb2trilium / htb2trilium_sherlocks.py
0xRoM 22 days ago 7 KB initial commit
import os
import json
import requests
from collections import defaultdict
from bs4 import BeautifulSoup
from datetime import datetime, timezone
from htb_client import HTBClient
from trilium_py.client import ETAPI

# Get the absolute path of the script's directory
script_dir = os.path.dirname(os.path.abspath(__file__))

# Construct the full path to the config.json file
config_path = os.path.join(script_dir, 'config.json')

# Load configuration from the JSON file
with open(config_path, 'r') as f:
    config = json.load(f)

# Accessing config values
htb_code = config['htb_code']
trilium_server_url = config['trilium_server_url']
trilium_token = config['trilium_token']
trilium_sherlocks_folder = config['trilium_sherlocks_folder']
trilium_sherlocks_template_id = config['trilium_sherlocks_template_id']

def get_timestamp(machine):
    # Parse the release date string into a datetime object
    release_str = machine['release_date']
    dt = datetime.strptime(release_str, "%Y-%m-%dT%H:%M:%S.%fZ")
    
    # Set the timezone to UTC
    dt = dt.replace(tzinfo=timezone.utc)
    
    # Get the timestamp
    timestamp = dt.timestamp()
    return timestamp

print("[+] connecting to HTB")
client = HTBClient(password=htb_code)
print("[+] connecting to trilium")
ea = ETAPI(trilium_server_url, trilium_token)
print("[i] version: ", ea.app_info()['appVersion'])

print("[i] HTB User:", client.user['id'], "-", client.user['name'])


print("[+] gathering sherlocks info")
categories = defaultdict(list)
sherlocks = client.get_all_sherlocks()
sherlocks.sort(key=get_timestamp)
total_completed = 0  # Variable to track total completed sherlocks

print(f"[i] Retrieved {len(sherlocks)} sherlocks")

# Group sherlocks by their categories
for sherlock in sherlocks:
    categories[sherlock['category_name']].append(sherlock)
    if sherlock['progress'] == 100:
        total_completed += 1  # Increment total completed if challenge is owned

# Print out the grouped sherlocks with the number of completed and total sherlocks in each category
for category, grouped_sherlocks in categories.items():
    total = len(grouped_sherlocks)
    completed = sum(1 for sherlock in grouped_sherlocks if sherlock['progress'] == 100)  # Count completed challenges
    
    res = ea.search_note(
        search=f"note.title %= '{category}*'",
        ancestorNoteId=trilium_sherlocks_folder,
        ancestorDepth='eq1',
        limit=1,
        fastSearch=True,
    )
    
    catId = ""
    if res['results'] and res['results'][0]['title'].lower() == category.lower()+" - "+str(completed)+" / "+str(total):
		# page exists - lets check if the details have changed
        ea.patch_note(noteId=res['results'][0]['noteId'], title=category+" - "+str(completed)+" / "+str(total))
        catId = res['results'][0]['noteId']
        print(f"[i] updated category: {category} - ({completed}/{total})")
    else:
        new_note = ea.create_note(
            parentNoteId=trilium_sherlocks_folder,
            type="text",
            title=category+" - "+str(completed)+" / "+str(total),
            content=" ",
        )
        catId = new_note['note']['noteId']
        print(f"[+] created category: {catId} {category} - ({completed}/{total})")
    
    for sherlock in grouped_sherlocks:
        #print(f" - ID: {challenge['id']}, Name: {challenge['name']}, Difficulty: {challenge['difficulty']}")
        res2 = ea.search_note(
            search=f"{sherlock['name']}",
            ancestorNoteId=catId,
            ancestorDepth='eq1',
            limit=1,
            fastSearch=True,
        )
        # already exists update the values
        if res2['results'] and res2['results'][0]['title'].lower() == sherlock['name'].lower():
            print(f"[i] found ID: {sherlock['id']}, Name: {sherlock['name']}, Difficulty: {sherlock['difficulty']}")
    
            for attribute in res2['results'][0]['attributes']:
                if attribute['name'] == "Difficulty":
                    ea.patch_attribute(attributeId=attribute['attributeId'], value=sherlock['difficulty'])
        
                if attribute['name'] == "Released":
                    release_str = sherlock['release_date']
                    release_date = datetime.strptime(release_str, "%Y-%m-%dT%H:%M:%S.%fZ")
                    formatted_release_date = release_date.strftime("%d %B %Y")
                    ea.patch_attribute(attributeId=attribute['attributeId'], value=formatted_release_date)
        
                if attribute['name'] == "Solved":
                    ea.patch_attribute(attributeId=attribute['attributeId'], value=str(sherlock['progress']))
        
                if attribute['name'] == "cssClass":
                    # Determine the cssClass value based on the progress
                    if sherlock['progress'] == 0:
                        ea.patch_attribute(attributeId=attribute['attributeId'], value="todo")
                    elif sherlock['progress'] == 100:
                        ea.patch_attribute(attributeId=attribute['attributeId'], value="done")
                    elif 0 < sherlock['progress'] < 100:
                        ea.patch_attribute(attributeId=attribute['attributeId'], value="inprogress")


        else: # doesnt already exist, create page
            release_str = sherlock['release_date']
            release_date = datetime.strptime(release_str, "%Y-%m-%dT%H:%M:%S.%fZ")
            formatted_release_date = release_date.strftime("%d %B %Y")
            new_note = ea.create_note(
                parentNoteId=catId,
                type="text",
                title=sherlock['name'],
                content=" ",
            )
            ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="relation", name="template", value=trilium_sherlocks_template_id)
            ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="label", name="Difficulty", value=sherlock['difficulty'])
            ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="label", name="Released", value=formatted_release_date)
            ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="label", name="Solved", value=str(sherlock['progress']))
            if sherlock['progress'] == 0:
                ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="label", name="cssClass", value="todo")
            elif sherlock['progress'] == 100:
                ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="label", name="cssClass", value="done")
            elif 0 < sherlock['progress'] < 100:
                ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="label", name="cssClass", value="inprogress")

            print(f"[+] created ID: {sherlock['id']}, Name: {sherlock['name']}, Difficulty: {sherlock['difficulty']}")

print("[+] updating folder name                                          ")
ea.patch_note(noteId=trilium_sherlocks_folder,title="Sherlocks - "+str(total_completed)+" / "+str(len(sherlocks)))