2025-03-07 14:11:03 +11:00
import json
import account
import requests
2025-03-07 14:14:45 +11:00
import os
2025-03-07 14:11:03 +11:00
# Plugin Data
info = {
" name " : " HNS Links " ,
2025-03-07 15:10:17 +11:00
" description " : " This is a plugin to quickly setup a HNS Links site<br>1. Connect varo instance with api key<br>2. Add domain to varo<br> 3. Add it to HNS Links<br>4. Wait a few minutes and readd it to HNS Links to ensure the generated TLSA is added<br>5. Wait for the DNS update to propogate (up to 7 hrs) " ,
2025-03-07 14:11:03 +11:00
" version " : " 1.0 " ,
" author " : " Nathan.Woodburn/ "
}
# Functions
functions = {
" login " : {
" name " : " Login to Varo Instance " ,
" type " : " default " ,
" description " : " You need to connect to a varo instance to setup the dns for domains " ,
" params " : {
" instance " : {
2025-03-07 14:14:45 +11:00
" name " : " Varo Instance (eg. domains.hns.au) " ,
2025-03-07 14:11:03 +11:00
" type " : " text "
} ,
" key " : {
" name " : " API Key " ,
" type " : " text "
}
} ,
" returns " : {
" status " :
{
" name " : " Status " ,
" type " : " text "
}
}
} ,
2025-03-07 14:14:45 +11:00
" addDomain " : {
" name " : " Add domain to varo " ,
2025-03-07 14:11:03 +11:00
" type " : " default " ,
2025-03-07 14:14:45 +11:00
" description " : " Add a domain to Varo " ,
2025-03-07 14:11:03 +11:00
" params " : {
" domain " : {
" name " : " Domain " ,
" type " : " text "
}
} ,
" returns " : {
2025-03-07 14:14:45 +11:00
" status " :
{
" name " : " Status of the function " ,
" type " : " text "
2025-03-07 14:11:03 +11:00
}
}
2025-03-07 14:14:45 +11:00
2025-03-07 14:19:22 +11:00
} ,
" hnslinks " : {
" name " : " Add domain to HNS Links with wallet address " ,
" type " : " default " ,
" description " : " Add a domain to HNS Links " ,
" params " : {
" domain " : {
" name " : " Domain " ,
" type " : " text "
}
} ,
" returns " : {
" status " :
{
" name " : " Status of the function " ,
" type " : " text "
}
}
2025-03-07 15:10:17 +11:00
} ,
" edit " : {
" name " : " Edit HNS Links " ,
" type " : " default " ,
" description " : " Login and Edit your HNS Links " ,
" params " : {
" domain " : {
" name " : " Domain " ,
" type " : " text "
}
} ,
" returns " : {
" url " :
{
" name " : " Login URL " ,
2025-03-07 15:13:58 +11:00
" type " : " list "
2025-03-07 15:10:17 +11:00
}
}
2025-03-07 14:11:03 +11:00
}
}
def login ( params , authentication ) :
instance = params [ " instance " ]
key = params [ " key " ]
# Test Connection
if instance == " " :
return { " status " : " Please enter a valid instance " }
instance = instance . replace ( " https:// " , " " )
instance = instance . replace ( " http:// " , " " )
if instance [ - 1 ] == " / " :
instance = instance [ : - 1 ]
try :
# Authorization: Bearer <API Key>
response = requests . post ( " https:// " + instance + " /api " , json = { " action " : " getInfo " } , headers = { " Authorization " : " Bearer " + key } )
if response . status_code != 200 :
return { " status " : " Error connecting to instance " }
except :
return { " status " : " Error connecting to instance " }
with open ( " user_data/hnslinks.json " , " w " ) as f :
json . dump ( { " instance " : instance , " key " : key } , f )
return { " status " : " Connected to " + instance }
2025-03-07 14:14:45 +11:00
def addDomain ( params , authentication ) :
# Add a domain to Varo
domain = params [ " domain " ]
if not os . path . exists ( " user_data/hnslinks.json " ) :
return { " status " : " Missing Varo API or instance " }
2025-03-07 14:51:24 +11:00
with open ( " user_data/hnslinks.json " , " r " ) as f :
2025-03-07 14:14:45 +11:00
auth = json . load ( f )
if not auth :
return { " status " : " Missing Varo API or instance " }
2025-03-07 14:55:04 +11:00
if ' key ' not in auth or ' instance ' not in auth :
2025-03-07 14:14:45 +11:00
return { " status " : " Missing Varo API or instance " }
2025-03-07 14:55:04 +11:00
api = auth [ " key " ]
2025-03-07 14:14:45 +11:00
instance = auth [ " instance " ]
headers = { " Authorization " : f " Bearer { api } " }
data = {
" action " : " getZones "
}
zones = requests . post ( f " https:// { instance } /api " , json = data , headers = headers )
if zones . status_code != 200 :
return { " status " : " Error connecting to Varo " }
if zones . json ( ) [ " success " ] != True :
return { " status " : " Error connecting to Varo " }
zones = zones . json ( ) [ " data " ]
for zone in zones :
if zone [ " name " ] == domain :
return { " status " : " Domain already exists " }
# Check domain is owned by user
wallet = authentication . split ( " : " ) [ 0 ]
owned = account . getDomains ( wallet )
# Only keep owned domains ["name"]
ownedNames = [ domain [ " name " ] for domain in owned ]
if domain not in ownedNames :
return { " status " : " Domain not owned by user " }
data = {
" action " : " createZone " ,
" domain " : domain
}
response = requests . post ( f " https:// { instance } /api " , json = data , headers = headers )
if response . status_code != 200 :
return { " status " : " Error connecting to Varo " }
if response . json ( ) [ " success " ] != True :
return { " status " : " Error connecting to Varo " }
zoneID = response . json ( ) [ " data " ] [ " zone " ]
data = {
" action " : " showZone " ,
" zone " : zoneID
}
response = requests . post ( f " https:// { instance } /api " , json = data , headers = headers )
if response . status_code != 200 :
return { " status " : " Error connecting to Varo " }
if response . json ( ) [ " success " ] != True :
return { " status " : " Error connecting to Varo " }
zone = response . json ( ) [ " data " ]
dns = [ ]
for ns in zone [ ' NS ' ] :
dns . append ( { ' type ' : ' NS ' , ' value ' : ns } )
ds = zone [ ' DS ' ]
ds = ds . split ( ' ' )
dns . append ( { ' type ' : ' DS ' , ' keyTag ' : int ( ds [ 0 ] ) , ' algorithm ' : int ( ds [ 1 ] ) , ' digestType ' : int ( ds [ 2 ] ) , ' digest ' : ds [ 3 ] } )
dns = json . dumps ( dns )
response = account . setDNS ( authentication , domain , dns )
2025-03-07 14:19:22 +11:00
return { " status " : " Success " }
def hnslinks ( params , authentication ) :
# Verify domain is owned by user
domain = params [ " domain " ]
wallet = authentication . split ( " : " ) [ 0 ]
owned = account . getDomains ( wallet )
# Only keep owned domains ["name"]
ownedNames = [ domain [ " name " ] for domain in owned ]
if domain not in ownedNames :
return { " status " : " Domain not owned by user " }
# Get wallet address
address = account . getAddress ( wallet )
if address == " " :
return { " status " : " Error getting wallet address " }
# Sign message hns-links
2025-03-07 14:20:40 +11:00
response = account . signMessage ( authentication , domain , " hns-links " )
2025-03-07 14:28:52 +11:00
if " error " in response and response [ " error " ] :
2025-03-07 14:28:18 +11:00
return { " status " : f " Error: { response [ ' error ' ] } " }
2025-03-07 14:47:10 +11:00
if ' result ' not in response :
return { " status " : " Error signing message " }
signature = response [ " result " ]
# Send request to hns-links
data = {
" domain " : domain ,
" signature " : signature ,
" data " : {
" title " : domain ,
" description " : " Connected via FireWallet " ,
" address " : [
{
" token " : " hns " ,
" address " : address
}
]
}
}
response = requests . post ( " https://links.hns.au/api/v1/site " , json = data )
if response . status_code != 200 :
return { " status " : " Error connecting to hns-links " }
response = response . json ( )
if " error " in response and response [ " error " ] :
return { " status " : f " Error: { response [ ' error ' ] } " }
ip = response [ " IP " ]
tlsa = response [ " TLSA " ]
# Get zones from varo
2025-03-07 14:57:39 +11:00
with open ( " user_data/hnslinks.json " , " r " ) as f :
2025-03-07 14:47:10 +11:00
auth = json . load ( f )
if not auth :
return { " status " : " Missing Varo API or instance " }
2025-03-07 14:57:39 +11:00
if ' key ' not in auth or ' instance ' not in auth :
2025-03-07 14:47:10 +11:00
return { " status " : " Missing Varo API or instance " }
2025-03-07 14:57:39 +11:00
api = auth [ " key " ]
2025-03-07 14:47:10 +11:00
instance = auth [ " instance " ]
response = requests . post ( f " https:// { instance } /api " , json = { " action " : " getZones " } , headers = { " Authorization " : f " Bearer { api } " } )
if response . status_code != 200 :
return { " status " : " Error connecting to Varo " }
if response . json ( ) [ " success " ] != True :
return { " status " : " Error connecting to Varo " }
zones = response . json ( ) [ " data " ]
for zone in zones :
if zone [ " name " ] == domain :
zoneID = zone [ " id " ]
break
if zoneID == " " :
return { " status " : " Error finding zone in Varo " }
response = requests . post ( f " https:// { instance } /api " , json = { " action " : " getRecords " , " zone " : zoneID } ,
headers = { " Authorization " : f " Bearer { api } " } )
if response . status_code != 200 :
return { " status " : " Error connecting to Varo " }
if response . json ( ) [ " success " ] != True :
return { " status " : " Error connecting to Varo " }
if ' data ' in response . json ( ) :
records = response . json ( ) [ " data " ]
else :
records = [ ]
for record in records :
if record [ " type " ] == " A " and record [ " name " ] == domain :
response = requests . post ( f " https:// { instance } /api " , json = { " action " : " deleteRecord " , " zone " : zoneID , " record " : record [ " uuid " ] } ,
headers = { " Authorization " : f " Bearer { api } " } )
if response . status_code != 200 :
return { " status " : " Error connecting to Varo " }
if response . json ( ) [ " success " ] != True :
return { " status " : " Error connecting to Varo " }
if record [ " type " ] == " TLSA " and record [ " name " ] == f " _443._tcp. { domain } " :
response = requests . post ( f " https:// { instance } /api " , json = { " action " : " deleteRecord " , " zone " : zoneID , " record " : record [ " uuid " ] } ,
headers = { " Authorization " : f " Bearer { api } " } )
if response . status_code != 200 :
return { " status " : " Error connecting to Varo " }
if response . json ( ) [ " success " ] != True :
return { " status " : " Error connecting to Varo " }
response = requests . post ( f " https:// { instance } /api " , json = { " action " : " addRecord " , " zone " : zoneID , " name " : " @ " , " type " : " A " , " content " : ip } ,
headers = { " Authorization " : f " Bearer { api } " } )
if response . status_code != 200 :
return { " status " : " Error connecting to Varo " }
if response . json ( ) [ " success " ] != True :
return { " status " : " Error connecting to Varo " }
if tlsa != " " :
response = requests . post ( f " https:// { instance } /api " , json = { " action " : " addRecord " , " zone " : zoneID , " name " : f " _443._tcp " , " type " : " TLSA " , " content " : tlsa } ,
headers = { " Authorization " : f " Bearer { api } " } )
if response . status_code != 200 :
return { " status " : " Error connecting to Varo " }
if response . json ( ) [ " success " ] != True :
return { " status " : " Error connecting to Varo " }
return { " status " : " YAY!!! All done! Just wait a few minutes for HNS Links to fully initialize the site. " }
2025-03-07 14:19:22 +11:00
2025-03-07 15:10:17 +11:00
def edit ( params , authentication ) :
# Verify domain is owned by user
domain = params [ " domain " ]
wallet = authentication . split ( " : " ) [ 0 ]
owned = account . getDomains ( wallet )
# Only keep owned domains ["name"]
ownedNames = [ domain [ " name " ] for domain in owned ]
if domain not in ownedNames :
return { " status " : " Domain not owned by user " }
# Get wallet address
address = account . getAddress ( wallet )
if address == " " :
return { " status " : " Error getting wallet address " }
# Sign message hns-links
response = account . signMessage ( authentication , domain , " hns-links " )
if " error " in response and response [ " error " ] :
return { " status " : f " Error: { response [ ' error ' ] } " }
if ' result ' not in response :
return { " status " : " Error signing message " }
signature = response [ " result " ]
2025-03-07 15:13:58 +11:00
return { " url " : [ f " <a href=https://links.hns.au/auth?username= { domain } &signature= { signature } target= ' _blank ' >Edit HNS Links</a> " ] }