An interactive command-line interface (CLI) tool to help you install, use, and administer an AO instance.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

108 lines
4.9 KiB

// Each AO API server can connect peer-to-peer over Tor. Tor addresses are unique and data is end-to-end encrypted.
import { headerStyle } from './styles.js'
import { aoEnv, setAoEnv } from '../ao-lib/settings.js'
import { isLoggedIn } from './session.js'
import { isInstalled } from '../features/tor.js'
import { postEvent, getAoBootstrapList, bootstrap } from '../ao-lib/api.js'
import { roger, promptMenu } from './welcome.js'
// Prints a menu to connect your AO to other AOs and manage connections
export async function connectMenu() {
const PUBLIC_BOOTSTRAP_ENABLED = aoEnv('PUBLIC_BOOTSTRAP_ENABLED')
let publicBootstrapMenuItem = { title: 'Enable p2p bootstrap', value: 'enable_bootstrap' }
if(PUBLIC_BOOTSTRAP_ENABLED) {
publicBootstrapMenuItem = { title: 'Disable p2p bootstrap', value: 'disable_bootstrap' }
}
const connectChoices = [
{ title: 'Connect to AO', value: 'connect', short: 'p2p connect'},
{ title: 'View connections', value: 'connections' },
{ title: 'Bootstrap now', value: 'bootstrap' },
publicBootstrapMenuItem,
{ title: 'Back to AO Menu', value: false }
]
const answer = await promptMenu(connectChoices, 'AO P2P')
switch(answer.connect_menu) {
case 'connect':
await connectInteractive()
break
case 'connections':
const onionList = await getAoBootstrapList()
console.log('The AO server has connections to:')
console.log(onionList.join('\n'))
break
case 'bootstrap':
const bootstrappedOnionList = await bootstrap()
if(!bootstrappedOnionList || bootstrappedOnionList.length < 1) {
console.log('Failed to fetch AO bootstrap server list.')
} else {
console.log('All known .onion addresses in neighborhood:')
console.log(bootstrappedOnionList.join('\n'))
}
break
case 'enable_bootstrap':
console.log('In order to join AO public chatrooms, AO uses the hyperswarm protocol. Joining hyperswarm may expose your IP address to other users. (For high-security installations, don\'t use public bootstrap: you can still add tor addresses to your address book manually and join those chatrooms by name.)')
setAoEnv('PUBLIC_BOOTSTRAP_ENABLED', true)
//message: Type \'public\' and press Enter to enable:')
break
case 'disable_bootstrap':
setAoEnv('PUBLIC_BOOTSTRAP_ENABLED', false)
console.log(roger(), 'Disabled public bootstrapping.')
break
default:
return false
}
return true
}
// Tells the AO server you are connected to connect to the AO server at the given .onion with the given connection secret string
// Any client logged in to the AO can tell it to connect to another AO. This could be a security issue if there is a bad actor server.
async function connectInteractive() {
const loggedIn = isLoggedIn()
console.log('The AO server you are logged in to can connect peer-to-peer via tor to another AO server to join chatrooms, send cards, and sync file attachments. Tor is Tor Onion Routing, a secure, end-to-end encrypted way of routing anonymized internet traffic.')
if(!isInstalled()) {
console.log('It looks like your tor server isn\'t instaled and running. Go to Configure->Tor to set it up.')
return false
}
const memberId = aoEnv('AO_CLI_SESSION_MEMBERID')
if(!memberId) {
console.log('Not logged in.')
return false
}
console.log('To connect to another AO, you need it\'s Tor address, which ends in .onion, and its server secret. This information can be found on that AO\'s website. For convenience, it is combined in a single connection string separate by a colon. Please enter the entire string.')
const validateOnion = (onion) => {
const parts = onion.split('.')
if(parts.length != 2 || parts[0].length != 56 || parts[1] !== 'onion') {
console.log('\nInvalid onion address, an onion address is 56 chararcters followed by \'.onion\'. Press ESC to go back.')
return false
}
return true
}
const validateConnectionString = (connectionString) => {
const parts = connectionString.split(':')
if(parts.length != 2) {
console.log('Your connection string has too many or two few parts. It should have two part separated by a colon. Press ESC to go back.')
return false
}
if(!validateOnion(parts[0])) {
return false
}
if(parts[1].length != 64) {
console.log('The connection secret (second half of connection string) must be exactly 64 characters. Press ESC to go back.')
return false
}
return true
}
const answer = await askQuestionText('Enter connection string of other AO:') //todo: validate: validateConnectionString
const [onion, secret] = answer.connection_string.split(':')
console.log('onion is', onion, 'and secret is', secret)
console.log('Attempting connect...')
const result = await postEvent({
type: 'ao-outbound-connected',
address: onion,
secret: secret
})
console.log('result is', result.body)
return true
}