From e27d8f9dcee63bad68f55939c50055ff95dafc02 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 5 Jan 2025 17:01:37 +0100 Subject: [PATCH] new changes --- scripts/darknet_exploration.py | 325 ++++++++++++------ scripts/tests/csvwork.py | 119 ++++++- scripts/tests/verified.csv | 21 +- templates/banner.png | Bin 0 -> 14119 bytes templates/blacklist.csv | 2 + templates/sensitive.csv | 5 + templates/unverified.csv | 2 + templates/verified.csv | 3 + templates/webring-participants.csv | 2 + .../unverified.csv | 14 +- .../verified.csv | 17 +- 11 files changed, 374 insertions(+), 136 deletions(-) create mode 100644 templates/banner.png create mode 100644 templates/blacklist.csv create mode 100644 templates/sensitive.csv create mode 100644 templates/unverified.csv create mode 100644 templates/verified.csv create mode 100644 templates/webring-participants.csv diff --git a/scripts/darknet_exploration.py b/scripts/darknet_exploration.py index b4c5e13..1a4c3e7 100644 --- a/scripts/darknet_exploration.py +++ b/scripts/darknet_exploration.py @@ -1,20 +1,31 @@ -import os, pwd +import os, pwd, re, pandas as pd def main(): rootpath='/srv/darknet-onion-webring/' urlpath=pwd.getpwuid(os.getuid()).pw_dir+"/.darknet_participant_url" - print(urlpath) - isitvalid="n" + #print(urlpath) - #check if ~/.darknet_participant_url exists, + + # check if ~/.darknet_participant_url exists, # if exists, instance= the content of ~/.darknet_participant_url (which is the url: such as uptime.nowherejez...onion) - + isitvalid="n" while isitvalid != "y": if os.path.isfile(urlpath): with open(urlpath) as f: - instance = f.read() - # TODO check if the instance URL domain is valid + instance = f.read().rstrip() + # check if the instance URL domain is valid + #print(urlpath,instance) + if IsOnionValid(instance): + print("[+] Instance Name: ",instance,IsOnionValid(instance)) + else: + print('[-] Invalid instance name in ~/.darknet_participant_url:', instance) + return False instancepath=rootpath+'www/participants/'+instance + verifiedcsvfile=instancepath+'/verified.csv' + vdf = pd.read_csv(verifiedcsvfile) + unverifiedcsvfile=instancepath+'/unverified.csv' + uvdf = pd.read_csv(unverifiedcsvfile) + #df = pd.read_csv(csvfile) print("[+] file exists, your Webring URL is ", instance) isitvalid = "y" else: @@ -23,112 +34,207 @@ def main(): instance = input("What is your Instance domain ? (ex: uptime.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion):") instancepath=rootpath+'www/participants/'+instance # TODO check if the instance URL domain is valid + if IsOnionValid(instance): + print("[+] Instance Name: ",instance,IsUrlValid(instance)) + else: + print('[-] Invalid instance name in ~/.darknet_participant_url:', instance) + return False + # ask the user if the instance URL is valid ? print() print(instance) - isitvalid=input("Is your this your instance domain ?") + isitvalid=input("Is this your this your instance domain ? (y/n)") # if yes, then write it into ~/.darknet_participant_url - if isitvalid != "y" : + if isitvalid == "y" : print("OK writing the instance url to ~/.darknet_participants_url") with open(urlpath, "w") as file: file.write(instance) - print("[+] file written, let's read it") - f = open(urlpath,"r") - print(f.read()) - print("[+] Initial Setup Completed!") - - print("[+] Welcome to the Darknet Onion Webring, where you are exploring the Darknet and helping others do the same.") - print(""" - 1) Add a new entry (into unverified.csv) - 2) Verify an entry (move an entry from unverified to verified.csv) - 3) Add a new webring participant (and download their files into their directory (without trusting them yet!)) - 4) Trust a webring participant (Potentially dangerous) - 5) Add/Remove words in the sensitive list (ex: drug) - 6) Add/Remove words in the blacklist (ex: porn) - """) - option = input("Select Option? (1-4)") - print(option) - match option: - case "1": - print("[+] Add a new Entry (into unverified.csv)") - # ask for the following: - unverifiedpath=instancepath+'/unverified.csv' - # the name of the website (required) + check if its valid - entry_name = input("What is the Website name ?") - # the url of the website (required) + check if its valid - entry_url = input("What is URL of the Website ? (ex: https://torproject.org or http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion") - # a quick description (optional) + check if its valid - entry_url = input("(Optional) Description of the website ? (max 256 characters) (press enter to skip)" - # sensitive ? (y/n) + check if its valid - entry_url = input("is it a sensitive website ? (ex: website related to drugs)" + print("[+] file written, let's read it") + f = open(urlpath,"r") + print(f.read()) + print("[+] Initial Setup Completed!") + while True: + print("[+] Welcome to the Darknet Onion Webring, where you are exploring the Darknet and helping others do the same.") + print(""" +Websites: + 1) Add a new Website entry (into unverified.csv) + 2) Trust a Website entry (move an entry from unverified to verified.csv) + 3) Untrust a Website entry (move an entry from unverified to verified.csv) + +Webring Participants: + 4) Add a new webring participant (and download their files into their directory (without trusting them yet!)) + 5) Trust a webring participant (Potentially dangerous) + 6) Untrust a webring participant + 7) Remove a webring participant + +Wordlists: + 8) Add/Remove words in the sensitive list (ex: drug) + 9) Add/Remove words in the blacklist (ex: porn) + 0) Exit + """) + option = input("Select Option? (0-6)") + print(option) + match option: + + +########## MANAGING WEBSITE ENTRIES ################# + case "1": + print("\n[+] Add a new Website entry (into unverified.csv)") + name='' + while(IsNameValid(name) is not True): + name = input("What is the Website name ? ") + category='' + while(IsCategoryValid(category) is not True): + category = input("What is the website Category ? ") + # the url of the website (required) + check if its valid + #entry_url = input("What is URL of the Website ? (ex: https://torproject.org or http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion)") + url='' + while(IsUrlValid(url) is not True): + url=input("What is the website URL ? ") + + # a quick description (optional) + check if its valid + #entry_desc = input("(Optional) Description of the website ? (max 256 characters) (press enter to skip)") + #desc="This is a new website that we add, it has this description" + desc='DEFAULT' + while(IsDescriptionValid(desc) is not True): + desc=input("Description for the website ? (Optional)") + # sensitive ? (y/n) + check if its valid + #entry_sensi = input("is it a sensitive website ? (ex: website related to drugs) (y/n)") + sensi = '' + while(IsStatusValid(sensi) is not True): + sensi=input("Is this website sensitive (ex: related to drugs) ? (y/n)") + + newrow=[instance,category,name,url,sensi,desc,'',''] + print("[+] NEWROW=",newrow) # (rest is automatic: status, score, instance is = '' because it is your own instance) # check if the entry doesn't already exist in verified.csv and in unverified.csv # if it doesnt exist, add it into unverified.csv + uvdf.loc[-1] = newrow # adding a row + uvdf.index = uvdf.index + 1 # shifting index + uvdf = uvdf.sort_index() # sorting by index + print("[+] New row added! now writing the csv file:") + uvdf.to_csv(unverifiedcsvfile, index=False) - case "2": - print("[+] Verify an entry (move an entry from unverified.csv to verified.csv)") - # search for a word - searchterm = input("What is the Website name ?") - # and display only the matching entries in an array format (display it in CLI). - # Each of the rows must have an index, - # prompt the user to ask for with row they want to move to verified.csv - searchterm = input("What is the index of the entry that you want to move to verified.csv ?") - # once selected, it must be able to print that row, and: - # append it into verified.csv - # remove it from unverified.csv - # print("[+] completed! You are now listing [name] (url) (sensitive)") - - case "3": - print("[+] Add a new webring participant (and download their files into their directory (without trusting them yet!))") - # ask for the url to the other webring participant - webring_participant_url = input("What is URL of the new webring participant? (ex: https://torproject.org or http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion") - # check if the (onion only) url is valid or not: at http://URL.onion/participants/URL.onion/{verified.csv,unverified.csv,sensitive.csv,blacklist.csv,webring-participants.csv} - - case "4": - print("[+] Trust a webring participant (Potentially dangerous)") - # list the existing webring participants from webring-participants.csv and - # ask the user to pick the index (0-9?) of the instance to trust - # if index is valid, then mark the instance as trusted in webring-participants.csv - searchterm = input("What is the index of the entry that you want to trust ?") - case "5": - print("[+] Add/Remove words in the sensitive list (ex: drug)") - print("do you want to 1) add words or 2) remove words ?") - option="0" - - done = False - while(done == False): - while option not any((1,2,"exit")): - option=input("do you want to 1) add words or 2) remove words ? (type exit to exit)") - # display the contents of sensitive.csv file - if option == 1: - word=input("which word do you want to add? (write 0 to exit") - if word == "0": - done = True - #True to get out of the while loop - else - print("checking if word is valid") - #check if word is valid in a while loop (dont check if - # if invalid! remove word at index + case "2": + print("[+] Trust a Website entry (move an entry from unverified to verified.csv)") + # search for a word + name='' + while(IsNameValid(name) is not True): + name = input("What is the Website name you want to verify ? (ex: Nowhere)") + filter_uvdf = uvdf[uvdf.Name.str.contains(name)] + # and display only the matching entries in unverified.csv in an array format (display it in CLI). + print(filter_uvdf[['Name','URL']]) + # check if there are no results, dont proceed if there are none! + if filter_uvdf.size == 0: + print("ERROR no results, skipping.") else: - index=input("which word do you want to remove? (index 0 to (max index) (write exit to exit)") - if index == "exit": - done = True - #True to get out of the while loop - else - print("checking if index is valid") - #check if index is valid or not - # if valid! remove word at index - # if invalid! just pass to ask for another word + # Each of the rows has an index, + index=-1 + while (index not in filter_uvdf.index): + # prompt the user to ask for with row they want to move to verified.csv + index = int(input("What is the index of the entry that you want to move to verified.csv ? (ex: 3) ")) + # once selected, it must be able to SAVE and print that row: + print(uvdf.iloc[index].values) + newrow=uvdf.iloc[index].values - case "6": - print("[+] Add/Remove words in the blacklist list (ex: porn)") - # copy option 5 - # print("do you want to 1) add words or 2) remove words ?") - # display the contents of blacklist.csv file + + # append it into verified.csv + vdf.loc[-1] = newrow # adding a row + vdf.index = vdf.index + 1 # shifting index + vdf = vdf.sort_index() # sorting by index + vdf.to_csv(verifiedcsvfile, index=False) + print("[+] New row added to verified.csv! now writing to the csv") + + + # remove it from unverified.csv + uvdf.drop(index, inplace= True) + uvdf.to_csv(unverifiedcsvfile, index=False) + print("[+] Link is now moved to verified.csv!") + + case "3": + # TODO + print("[+] Untrust a Website entry (move an entry from verified to unverified.csv)") + + +####### MANAGING WEBRING PARTICIPANTS ########### +# 4) Add a new webring participant (and download their files into their directory (without trusting them yet!)) +# 5) Trust a webring participant (Potentially dangerous) +# 6) Untrust a webring participant +# 7) Remove a webring participant +##################################################### + case "4": + print("[+] Add a new webring participant (and download their files into their directory (without trusting them yet!))") + # TODO ask for the url to the other webring participant + webring_participant_url = input("What is URL of the new webring participant? (ex: https://torproject.org or http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion") + # TODO check if the (onion only) url is valid or not: at http://URL.onion/participants/URL.onion/{verified.csv,unverified.csv,sensitive.csv,blacklist.csv,webring-participants.csv} + # TODO if OK then add it to the webring-participants.csv file - case _: - print("[-] ERROR, incorrect input") + case "5": + print("[+] Trust a webring participant (Potentially dangerous)") + # TODO list the existing webring participants from webring-participants.csv and + # TODO ask the user to pick the index (0-9?) of the instance to trust + # TODO if index is valid, then mark the instance as trusted in webring-participants.csv + searchterm = input("What is the index of the entry that you want to trust ?") + case "6": + # TODO + print("[+] Untrust a webring participant") + case "7": + # TODO + print("[+] Remove a webring participant") + + + + + + + +################### MANAGING WORDLISTS ################# +#Wordlists: +# 8) Add/Remove words in the sensitive list (ex: drug) +# 9) Add/Remove words in the blacklist (ex: porn) +# 0) Exit +######################################################### + + case "8": + print("[+] Add/Remove words in the sensitive list (ex: drug)") + print("do you want to 1) add words or 2) remove words ?") + option="0" + + done = False + while(done == False): + while option != "1" and option != "2" and option != "exit": + option=input("do you want to 1) add words or 2) remove words ? (type exit to exit)") + # TODO display the contents of sensitive.csv file + if option == 1: + word=input("which word do you want to add? (write 0 to exit") + if word == "0": + done = True + #True to get out of the while loop + else: + print("checking if word is valid") + # TODO check if word is valid in a while loop (dont check if + # TODO if invalid! remove word at index + else: + index=input("which word do you want to remove? (index 0 to (max index) (write exit to exit)") + if index == "exit": + done = True + #True to get out of the while loop + else: + print("checking if index is valid") + # TODO check if index is valid or not + # TODO if valid! remove word at index + # TODO if invalid! just pass to ask for another word + + case "9": + print("[+] Add/Remove words in the blacklist list (ex: porn)") + # TODO copy option 5 + # TODO print("do you want to 1) add words or 2) remove words ?") + # TODO display the contents of blacklist.csv file + + case _: + print("[-] Exiting") + return True #### PROTECTIONS AGAINST MALICIOUS CSV INPUTS #### @@ -168,7 +274,7 @@ def IsOnionValid(url: str)-> bool: print("Domain not valid") return False else: - print("URL doesn't start http") + #print("URL doesn't start http") if pattern.fullmatch(url) is not None: if len(url.split('.')) > 3: n_subdomians = len(url.split('.')) @@ -205,11 +311,11 @@ def IsUrlValid(url:str)->bool: return IsOnionValid(url) else: if not url.__contains__('.'): - print("No (DOT) in url") + print("No (DOT) in clearnet url") + return False + if pattern.fullmatch(url) is None: + print('Url contains invalid chars') return False - if pattern.fullmatch(url) is None: - print('Url contains invalid chars') - return False return True def IsStatusValid(status: str)-> bool: @@ -219,13 +325,14 @@ def IsStatusValid(status: str)-> bool: # check if the characters are only [vx] with maximum 1 chars max # if OK return True #if not : return False - pattern = ['v','x'] + pattern = ['y','n'] if len(status) != 1: print("Got more than one character or nothing.") return False elif (status not in pattern): - print("Got an invalid character") + print("Got an invalid character it must be either y or n") return False + return True def IsDescriptionValid(desc:str)->bool: @@ -238,8 +345,8 @@ def IsDescriptionValid(desc:str)->bool: #if not : return False pattern = re.compile("^[A-Za-z0-9-.,' ]+$") desc.strip() - if pattern.fullmatch(desc) is None: - print('Got an empty desc or invalid chars') + # empty description is fine as it's optional + if desc == "DEFAULT": return False elif len(desc) > 256: print("desc is greater than 256 chars") @@ -258,7 +365,7 @@ def IsCategoryValid(categories: list)-> bool: for category in categories: category.strip() if pattern.fullmatch(category) is None: - print('Got an empty list or invalid chars') + #print('Got an empty list or invalid chars') return False elif len(category) > 64: print('Category is too long') @@ -276,7 +383,7 @@ def IsNameValid(name: str)->bool: pattern = re.compile("^[A-Za-z0-9 ]+$") name = name.strip() if (pattern.fullmatch(name) is None): - print("Got an invalid character or nothing") + #print("Got an invalid character or nothing") return False elif len(name) > 64: print(f'Got a name lenght greater than 64. {len(name)}') diff --git a/scripts/tests/csvwork.py b/scripts/tests/csvwork.py index 145a405..b05f1ff 100644 --- a/scripts/tests/csvwork.py +++ b/scripts/tests/csvwork.py @@ -1,7 +1,7 @@ import csv, json, pandas as pd, glob def main(): - print("aaa") + #print("aaa") csvfile="verified.csv" df = pd.read_csv(csvfile) #for i in range (df.index.stop): @@ -12,26 +12,123 @@ def main(): # print(df.at[i][col]) #print(df) - print("[+] Display 2 columns:") +# print("[+] Display 2 columns:") #display 2 columns: - print(df[['Name', 'URL']]) +# print(df[['Name', 'URL']]) - print("[+] Display rows 0 to 5") +# print("[+] Display rows 0 to 5") #display rows from 0 to 5 - print(df[0:5]) +# print(df[0:5]) #display rows from 0 to 5 - print("[+] Display rows 3 to 5 and columns Name and URL") - print(df.loc[3:5,['Name','URL']]) +# print("[+] Display rows 3 to 5 and columns Name and URL") +# print(df.loc[3:5,['Name','URL']]) #print(df[0:1,['Name','URL']]) - print("[+] Display all rows for and columns name and URL") +# print("[+] Display all rows for and columns name and URL") #df.loc[startrow:endrow, startcolumn:endcolumn] - print(df.loc[0:df.index.stop,['Name','URL']]) +# print(df.loc[0:df.index.stop,['Name','URL']]) #display rows from 0 to the end of indexes - print("[+] Display all rows for all columns") - print(df[0:df.index.stop]) +# print("[+] Display all rows for all columns") +# print(df[0:df.index.stop]) + + + + + ############################################################################## + print('\n[+] list the entire csv file and get all row IDs') + print(df[['Name', 'URL']]) + index=-1 + while (index > df.tail(1).index.item() or index < 0): + #index=input("\n[+] What entry do you want to edit ? (enter the row index (ex: 4)") + index=4 + index=int(index) + print(df.iloc[index], "last index:", df.index.stop-1) + print("\n[+] Number of Rows:", len(df.index)-1) + + + + print('\n[+] Iterate over the rows by their IDs for the 2 Columns URL and Name') + print(df.iterrows()) + for i,j in df.iterrows(): + #print("[+] ROW=",i,"\n[+] CONTENT=\n",j) + #print("[+] ROW=",i) + #print("[+] ROW CONTENTS= \n",df.loc[i, ['URL','Name']]) + #print("[+] ROW CONTENTS= \n",df.loc[i, ['URL']]) + print("[+] ROW=",i,"ROW CONTENTS=", df.at[i, 'Name'], df.at[i, 'URL']) + #print(df[0][i]) + + + + print('\n[+] Iterate over the columns by their name:') + columns = list(df) + print(columns) + print('\n[+] Iterate over the columns of the first row:') + for i in columns: + print('\nCOLUMN=',i) + print('CONTENTS=',df[i][0]) + + + + #print('[+] list the csv file by filtering a keyword and get all row IDs') + #filterterm=input("[+] Filter the CSV file using a keyword (ex: DNM)") + filterterm="Psy" + filter_df = df[df.Name.str.contains(filterterm)] + #print(filtered_df) # print all columns + print(filter_df[['Name','URL']]) #print only 2 columns + #print("\n[+] Number of Rows:", len(filter_df.index)) + #for index in filter_df.index: + #print(index) + index=-1 + while (index not in filter_df.index): + #index=int(input("\n[+] Please select a valid row: ")) + index=int("1") + print("ROW=",index, 'CONTENT=', filter_df.at[index, 'Name'], filter_df.at[index, 'URL']) + + + + print("\n[+] Adding a new row:") + # ask for the following: + #unverifiedpath=instancepath+'/unverified.csv' + instance='uptime.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion' + unverifiedpath='verified.csv' + # the name of the website (required) + check if its valid + # if the website name is "exit" then get out of the while loop + #entry_name = input("What is the Website name ?") + name="NewWebsite" + category="TestCategory" + # the url of the website (required) + check if its valid + #entry_url = input("What is URL of the Website ? (ex: https://torproject.org or http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion)") + url="http://newwebsitewoidwajiawdhjoidwahjoadiwhj.onion" + # a quick description (optional) + check if its valid + #entry_desc = input("(Optional) Description of the website ? (max 256 characters) (press enter to skip)") + desc="This is a new website that we add, it has this description" + # sensitive ? (y/n) + check if its valid + #entry_sensi = input("is it a sensitive website ? (ex: website related to drugs) (y/n)") + sensi = "n" + newrow=[instance,category,name,url,sensi,desc,'',''] + print("[+] NEWROW=",newrow) + + #add a new row (get all the new data you need first): + + df.loc[-1] = newrow # adding a row + df.index = df.index + 1 # shifting index + df = df.sort_index() # sorting by index + print("[+] New row added! now writing the csv file:") + df.to_csv(csvfile, index=False) + + print(df) + + #write the dataframe into the csv file + #read and print the contents of the csv file + #re-add that row in the csv file + #remove that row from the dataframe + print() + + + # then select a row in it (by the ID) and display it + # list if __name__ == '__main__': main() diff --git a/scripts/tests/verified.csv b/scripts/tests/verified.csv index 25f8e3b..194eb98 100644 --- a/scripts/tests/verified.csv +++ b/scripts/tests/verified.csv @@ -1,12 +1,13 @@ Instance,Category,Name,URL,Sensitive,Description,Status,Score +uptime.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,TestCategory,NewWebsite,http://newwebsitewoidwajiawdhjoidwahjoadiwhj.onion,n,"This is a new website that we add, it has this description",, +uptime.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,TestCategory,NewWebsite,http://newwebsitewoidwajiawdhjoidwahjoadiwhj.onion,n,"This is a new website that we add, it has this description",, FIRSTherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,Psychonaut Wiki,http://vvedndyt433kopnhv6vejxnut54y5752vpxshjaqmj7ftwiu6quiv2ad.onion/,,"This is the wiki for psychonauts, it contains infos on substances and trip reports",✔️,100.0 -somewherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,"General guide on how to navigate the Darknet to buy drugs",✔️,100.0 -somewherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,"General guide on how to navigate the Darknet to buy drugs",✔️,100.0 -somewherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,"General guide on how to navigate the Darknet to buy drugs",✔️,100.0 -somewherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,"General guide on how to navigate the Darknet to buy drugs",✔️,100.0 -somewherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,"General guide on how to navigate the Darknet to buy drugs",✔️,100.0 -somewherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,"General guide on how to navigate the Darknet to buy drugs",✔️,100.0 -somewherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,"General guide on how to navigate the Darknet to buy drugs",✔️,100.0 -LASTherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,"General guide on how to navigate the Darknet to buy drugs",✔️,100.0 - - +somewherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,1DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,General guide on how to navigate the Darknet to buy drugs,✔️,100.0 +somewherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,2DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,General guide on how to navigate the Darknet to buy drugs,✔️,100.0 +somewherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,3DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,General guide on how to navigate the Darknet to buy drugs,✔️,100.0 +somewh3refoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,4DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,General guide on how to navigate the Darknet to buy drugs,✔️,100.0 +somewherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,5DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,General guide on how to navigate the Darknet to buy drugs,✔️,100.0 +somewherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,6DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,General guide on how to navigate the Darknet to buy drugs,✔️,100.0 +somewherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,7DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,General guide on how to navigate the Darknet to buy drugs,✔️,100.0 +nowherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,8DNM Bible,http://biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion/,✔️,General guide on how to navigate the Darknet to buy drugs,✔️,100.0 +LASTherefoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion,Infos and Links,Psychonaut Wiki,http://vvedndyt433kopnhv6vejxnut54y5752vpxshjaqmj7ftwiu6quiv2ad.onion/,,"This is the wiki for psychonauts, it contains infos on substances and trip reports",✔️,100.0 diff --git a/templates/banner.png b/templates/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..8e7af7380ab4bf22a26251b78949ea8efe89c0a6 GIT binary patch literal 14119 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 ZTzN}Ry>fC