Newer
Older
DirtyScripts / htb2trilium.py
  1. '''
  2. ########################
  3. # SETUP
  4. ########################
  5. > pip3 install trilium-py
  6. > pip3 install pyhackthebox
  7.  
  8. - get trilium token in trilium options->ETAPI and "create new token"
  9. - get trilium_htb_folder click on note to become folder -> "note info". Note ID is there.
  10. - set the folder's owned attributes to:
  11. #label:user=promoted,single,text #label:root=promoted,single,text #label:respect=promoted,single,text #user=0 #root=0 #respect=0
  12.  
  13. - create a note named "HTBMachineTemplate" and set it's "owned attributes" to:
  14. #template #label:User=promoted,single,text #label:Root=promoted,single,text #label:Tags=promoted,single,text
  15.  
  16. - get this page's ID and put in "trilium_template_id"
  17. - to get "in progress" todo colour - add to taskmanager/implementation/CSS:
  18.  
  19. span.fancytree-node.inprogress .fancytree-title {
  20. color: orange !important;
  21. }
  22. '''
  23.  
  24. ########################
  25. # IGNORE THESE
  26. ########################
  27.  
  28. import requests
  29. from bs4 import BeautifulSoup
  30. from datetime import timezone
  31. from hackthebox import HTBClient
  32. from trilium_py.client import ETAPI
  33.  
  34. ########################
  35. # EDIT BELOW HERE
  36. ########################
  37.  
  38. htb_email = ''
  39. htb_pass = ''
  40. trilium_server_url = ''
  41. trilium_token = ''
  42. trilium_htb_folder = ''
  43. trilium_template_id = ''
  44.  
  45. ########################
  46. # LEAVE BELOW HERE
  47. ########################
  48.  
  49. def generate_newpage(machine):
  50. no = "<span style=\"color:hsl(0,75%,60%);\">No</span>"
  51. yes = "<span style=\"color:hsl(120,75%,60%);\">Yes</span>"
  52. user_colour = no
  53. if machine.user_owned:
  54. user_colour = yes
  55. root_colour = no
  56. if machine.root_owned:
  57. root_colour = yes
  58.  
  59. status = "Active"
  60. if machine.retired:
  61. status = "Retired"
  62.  
  63. html = """
  64. <figure class="image image-style-align-left image_resized" style="width:12.28%;">
  65. <img src="https://www.hackthebox.com{avatar}">
  66. </figure>
  67. <p>
  68. <strong>OS:</strong> {os}<br>
  69. <strong>Difficulty:</strong> {difficulty}<br>
  70. <strong>Rating:</strong> {rating} / 5<br>
  71. <strong>Points:</strong> {points}<br>
  72. <strong>User / Root: </strong> {user_colour} / {root_colour}<br>
  73. <strong>Released:</strong> {release_date}<br>
  74. <strong>State:</strong> {status}
  75. </p>
  76. <hr>
  77. <h2>Notes</h2>
  78. <p>&nbsp;</p>
  79. """.format(
  80. os=machine.os,
  81. difficulty=machine.difficulty,
  82. rating=machine.stars,
  83. points=machine.points,
  84. release_date=machine.release_date.strftime("%d %B %Y"),
  85. user_colour=user_colour,
  86. root_colour=root_colour,
  87. status = status,
  88. avatar = machine.avatar,
  89. )
  90.  
  91. return html
  92.  
  93. def get_timestamp(machine):
  94. dt = machine.release_date
  95. timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
  96. return timestamp
  97.  
  98. print("[+] connecting to HTB")
  99. client = HTBClient(email=htb_email, password=htb_pass)
  100. print("[+] connecting to trilium")
  101. ea = ETAPI(trilium_server_url, trilium_token)
  102.  
  103. print("[i] HTB User:",client.user.id, "-", client.user.name)
  104. print("[i] user owns:", client.user.user_owns, "| Root owns:", client.user.root_owns, "| Respect:", client.user.respects)
  105.  
  106. master_folder = ea.get_note(trilium_htb_folder)
  107. for attribute in master_folder['attributes']:
  108. if attribute['name'] == "user":
  109. if attribute['value'] != str(client.user.user_owns):
  110. print("[+] updating user owns (folder attribute)")
  111. ea.patch_attribute(attributeId=attribute['attributeId'], value=str(client.user.user_owns))
  112. if attribute['name'] == "root":
  113. if attribute['value'] != str(client.user.root_owns):
  114. print("[+] updating root owns (folder attribute)")
  115. ea.patch_attribute(attributeId=attribute['attributeId'], value=str(client.user.root_owns))
  116. if attribute['name'] == "respect":
  117. if attribute['value'] != str(client.user.respects):
  118. print("[+] updating respect (folder attribute)")
  119. ea.patch_attribute(attributeId=attribute['attributeId'], value=str(client.user.respects))
  120.  
  121. print("[+] gathering machines info")
  122.  
  123. machines = client.get_machines()
  124. machines += client.get_machines(None, True)
  125. machines.sort(key=get_timestamp)
  126. # starts with oldest, ends with newest...
  127.  
  128. machine_count = 0
  129. completed_count = 0
  130. for machine in machines:
  131. machine_count += 1
  132. print('processing: ',machine_count, "/", len(machines), "("+machine.name+") " , end='\r')
  133. res = ea.search_note(
  134. search="\""+machine.name+"\"",
  135. ancestorNoteId=trilium_htb_folder,
  136. ancestorDepth='eq1',
  137. limit=1,
  138. fastSearch=True,
  139. )
  140. if res['results'] and machine.name == res['results'][0]['title']:
  141. # page exists - lets check if the details have changed
  142.  
  143. current_html = ea.get_note_content(noteId=res['results'][0]['noteId'])
  144. current_soup = BeautifulSoup(current_html, 'html.parser')
  145. current_paragraph = current_soup.find_all('p')[0].text
  146.  
  147. new_html = generate_newpage(machine)
  148. new_soup = BeautifulSoup(new_html, 'html.parser')
  149. new_paragraph = new_soup.find_all('p')[0].text
  150.  
  151. # current page contains first paragraph of "blank" (useful for when it doesnt create or find the note properly.. shouldnt get here)
  152. if current_paragraph == "blank":
  153. ea.update_note_content(noteId=res['results'][0]['noteId'], content=new_html)
  154. ea.create_attribute(attributeId=None, isInheritable=False, noteId=res['results'][0]['noteId'], type="relation", name="template", value=trilium_template_id)
  155. if machine.user_owned and machine.root_owned:
  156. ea.create_attribute(attributeId=None, isInheritable=False, noteId=res['results'][0]['noteId'], type="label", name="cssClass", value="done")
  157. else:
  158. if machine.user_owned or machine.root_owned:
  159. ea.create_attribute(attributeId=None, isInheritable=False, noteId=res['results'][0]['noteId'], type="label", name="cssClass", value="inprogress")
  160. else:
  161. ea.create_attribute(attributeId=None, isInheritable=False, noteId=res['results'][0]['noteId'], type="label", name="cssClass", value="todo")
  162. # re-get the current content
  163. current_html = ea.get_note_content(noteId=res['results'][0]['noteId'])
  164. current_soup = BeautifulSoup(current_html, 'html.parser')
  165.  
  166. if current_paragraph != new_paragraph:
  167.  
  168. # details have updated!
  169. print("[+] updating page:",machine.name, "-> "+res['results'][0]['title']+" ")
  170. replacement = current_soup.find('p')
  171. replacement.replace_with( new_soup.find_all('p')[0] )
  172. ea.update_note_content(noteId=res['results'][0]['noteId'], content=current_soup)
  173.  
  174. # now to update the label
  175. for attribute in res['results'][0]['attributes']:
  176. if attribute['name'] == "cssClass":
  177. if machine.user_owned and machine.root_owned:
  178. ea.patch_attribute(attributeId=attribute['attributeId'], value="done")
  179. else:
  180. if machine.user_owned or machine.root_owned:
  181. ea.patch_attribute(attributeId=attribute['attributeId'], value="inprogress")
  182. else:
  183. ea.patch_attribute(attributeId=attribute['attributeId'], value="todo")
  184. else:
  185. # title does not exist - create the note
  186. html = generate_newpage(machine)
  187. new_note = ea.create_note(
  188. parentNoteId=trilium_htb_folder,
  189. type="text",
  190. title=machine.name,
  191. content=html,
  192. )
  193. print("[+] created note:", machine.name, " ")
  194.  
  195. ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="relation", name="template", value=trilium_template_id)
  196. if machine.user_owned and machine.root_owned:
  197. ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="label", name="cssClass", value="done")
  198. else:
  199. if machine.user_owned or machine.root_owned:
  200. ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="label", name="cssClass", value="inprogress")
  201. else:
  202. ea.create_attribute(attributeId=None, isInheritable=False, noteId=new_note['note']['noteId'], type="label", name="cssClass", value="todo")
  203.  
  204. if machine.user_owned and machine.root_owned:
  205. completed_count += 1
  206.  
  207. print("[+] updating folder name ")
  208. ea.patch_note(noteId=trilium_htb_folder,title="Machines - "+str(completed_count)+" / "+str(len(machines)))
  209.  
  210. print("[=] processed", machine_count)
  211.  
Buy Me A Coffee