diff --git a/htb2trilium.py b/htb2trilium.py new file mode 100644 index 0000000..ac579ca --- /dev/null +++ b/htb2trilium.py @@ -0,0 +1,214 @@ +''' +######################## +# SETUP +######################## + > pip3 install trilium-py + > pip3 install pyhackthebox + + - get trilium token in trilium options->ETAPI and "create new token" + - get trilium_htb_folder click on note to become folder -> "note info". Note ID is there. + - set the folder's owned attributes to: + #label:user=promoted,single,text #label:root=promoted,single,text #label:respect=promoted,single,text #user=0 #root=0 #respect=0 + + - create a note named "HTBMachineTemplate" and set it's "owned attributes" to: + #template #label:User=promoted,single,text #label:Root=promoted,single,text #label:Tags=promoted,single,text + + - get this page's ID and put in "trilium_template_id" + - to get "in progress" todo colour - add to taskmanager/implementation/CSS: + + span.fancytree-node.inprogress .fancytree-title { + color: orange !important; + } +''' + +######################## +# IGNORE THESE +######################## + +import requests +from bs4 import BeautifulSoup +from datetime import timezone +from hackthebox import HTBClient +from trilium_py.client import ETAPI + +######################## +# EDIT BELOW HERE +######################## + +htb_email = '' +htb_pass = '' +trilium_server_url = '' +trilium_token = '' +trilium_htb_folder = '' +trilium_template_id = '' + +######################## +# LEAVE BELOW HERE +######################## + +def generate_newpage(machine): + no = "No" + yes = "Yes" + user_colour = no + if machine.user_owned: + user_colour = yes + root_colour = no + if machine.root_owned: + root_colour = yes + + status = "Active" + if machine.retired: + status = "Retired" + + html = """ +
+ +
+

+ OS: {os}
+ Difficulty: {difficulty}
+ Rating: {rating} / 5
+ Points: {points}
+ User / Root: {user_colour} / {root_colour}
+ Released: {release_date}
+ State: {status} +

+
+

Notes

+

 

+ """.format( + os=machine.os, + difficulty=machine.difficulty, + rating=machine.stars, + points=machine.points, + release_date=machine.release_date.strftime("%d %B %Y"), + user_colour=user_colour, + root_colour=root_colour, + status = status, + avatar = machine.avatar, + ) + + return html + +def get_timestamp(machine): + dt = machine.release_date + timestamp = dt.replace(tzinfo=timezone.utc).timestamp() + return timestamp + +print("[+] connecting to HTB") +client = HTBClient(email=htb_email, password=htb_pass) +print("[+] connecting to trilium") +ea = ETAPI(trilium_server_url, trilium_token) + +print("[i] HTB User:",client.user.id, "-", client.user.name) +print("[i] user owns:", client.user.user_owns, "| Root owns:", client.user.root_owns, "| Respect:", client.user.respects) + +master_folder = ea.get_note(trilium_htb_folder) +for attribute in master_folder['attributes']: + if attribute['name'] == "user": + if attribute['value'] != str(client.user.user_owns): + print("[+] updating user owns (folder attribute)") + ea.patch_attribute(attributeId=attribute['attributeId'], value=str(client.user.user_owns)) + if attribute['name'] == "root": + if attribute['value'] != str(client.user.root_owns): + print("[+] updating root owns (folder attribute)") + ea.patch_attribute(attributeId=attribute['attributeId'], value=str(client.user.root_owns)) + if attribute['name'] == "respect": + if attribute['value'] != str(client.user.respects): + print("[+] updating respect (folder attribute)") + ea.patch_attribute(attributeId=attribute['attributeId'], value=str(client.user.respects)) + +print("[+] gathering machines info") + +machines = client.get_machines() +machines += client.get_machines(None, True) +machines.sort(key=get_timestamp) +# starts with oldest, ends with newest... + +machine_count = 0 +completed_count = 0 +for machine in machines: + machine_count += 1 + print('processing: ',machine_count, "/", len(machines), "("+machine.name+") " , end='\r') + + res = ea.search_note( + search="\""+machine.name+"\"", + ancestorNoteId=trilium_htb_folder, + ancestorDepth='eq1', + limit=1, + fastSearch=True, + ) + + if res['results'] and machine.name == res['results'][0]['title']: + # page exists - lets check if the details have changed + + current_html = ea.get_note_content(noteId=res['results'][0]['noteId']) + current_soup = BeautifulSoup(current_html, 'html.parser') + current_paragraph = current_soup.find_all('p')[0].text + + new_html = generate_newpage(machine) + new_soup = BeautifulSoup(new_html, 'html.parser') + new_paragraph = new_soup.find_all('p')[0].text + + # current page contains first paragraph of "blank" (useful for when it doesnt create or find the note properly.. shouldnt get here) + if current_paragraph == "blank": + ea.update_note_content(noteId=res['results'][0]['noteId'], content=new_html) + ea.create_attribute(attributeId=None, isInheritable=False, noteId=res['results'][0]['noteId'], type="relation", name="template", value=trilium_template_id) + if machine.user_owned and machine.root_owned: + ea.create_attribute(attributeId=None, isInheritable=False, noteId=res['results'][0]['noteId'], type="label", name="cssClass", value="done") + else: + if machine.user_owned or machine.root_owned: + ea.create_attribute(attributeId=None, isInheritable=False, noteId=res['results'][0]['noteId'], type="label", name="cssClass", value="inprogress") + else: + ea.create_attribute(attributeId=None, isInheritable=False, noteId=res['results'][0]['noteId'], type="label", name="cssClass", value="todo") + # re-get the current content + current_html = ea.get_note_content(noteId=res['results'][0]['noteId']) + current_soup = BeautifulSoup(current_html, 'html.parser') + + if current_paragraph != new_paragraph: + + # details have updated! + print("[+] updating page:",machine.name, "-> "+res['results'][0]['title']+" ") + replacement = current_soup.find('p') + replacement.replace_with( new_soup.find_all('p')[0] ) + ea.update_note_content(noteId=res['results'][0]['noteId'], content=current_soup) + + # now to update the label + for attribute in res['results'][0]['attributes']: + if attribute['name'] == "cssClass": + if machine.user_owned and machine.root_owned: + ea.patch_attribute(attributeId=attribute['attributeId'], value="done") + else: + if machine.user_owned or machine.root_owned: + ea.patch_attribute(attributeId=attribute['attributeId'], value="inprogress") + else: + ea.patch_attribute(attributeId=attribute['attributeId'], value="todo") + + else: + # title does not exist - create the note + html = generate_newpage(machine) + new_note = ea.create_note( + parentNoteId=trilium_htb_folder, + type="text", + title=machine.name, + content=html, + ) + print("[+] created note:", machine.name, " ") + + ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="relation", name="template", value=trilium_template_id) + if machine.user_owned and machine.root_owned: + ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="label", name="cssClass", value="done") + else: + if machine.user_owned or machine.root_owned: + ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="label", name="cssClass", value="inprogress") + else: + ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="label", name="cssClass", value="todo") + + if machine.user_owned and machine.root_owned: + completed_count += 1 + +print("[+] updating folder name ") +ea.patch_note(noteId=trilium_htb_folder,title="Machines - "+str(completed_count)+" / "+str(len(machines))) + +print("[=] processed", machine_count) +