Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor #60

Merged
merged 1 commit into from
Jul 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

96 changes: 96 additions & 0 deletions src/daemon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { join } from 'path'
import { createLibp2p } from 'libp2p'
import { createHelia } from 'helia'
import { createOrbitDB, Identities, KeyStore } from '@orbitdb/core'
import { LevelBlockstore } from 'blockstore-level'
import { LevelDatastore } from 'datastore-level'
import { pipe } from 'it-pipe'
import Orbiter from './lib/orbiter.js'
import { voyagerRPCProtocol } from './rpc/protocol.js'
import { handleCommand } from './rpc/index.js'
import { Access } from './lib/authorization.js'
import { config as libp2pConfig } from './utils/libp2p-config.js'
import { rpc as rpcId, appPath, rpcPath, app, orbiter as orbiterId, orbiterPath } from './utils/id.js'
import { saveConfig } from './utils/config-manager.js'
import { createFromPrivKey } from '@libp2p/peer-id-factory'
import { logger, enable } from '@libp2p/logger'

export default async ({ options }) => {
options = options || {}

const log = logger('orbitdb:voyager:daemon')

if (options.verbose > 0) {
enable('orbitdb:voyager:daemon' + (options.verbose > 1 ? '*' : ':error'))
}

options.defaultAccess = options.defaultAccess || Access.ALLOW

options.verbose = options.verbose || 0

const id = orbiterId

log('id:', id)

const appDirectory = appPath(options.directory)
const orbiterDirectory = orbiterPath(options.directory)

log('app:', app)
log('directory:', orbiterDirectory)

const path = join(orbiterDirectory, '/', 'keystore')

const blockstore = new LevelBlockstore(join(orbiterDirectory, '/', 'ipfs', '/', 'blocks'))
const datastore = new LevelDatastore(join(orbiterDirectory, '/', 'ipfs', '/', 'data'))

const keystore = await KeyStore({ path })
const identities = await Identities({ keystore })
await identities.createIdentity({ id })

const peerId = await createFromPrivKey(await keystore.getKey(id))
const libp2p = await createLibp2p(await libp2pConfig({ peerId }))

log('peerid:', libp2p.peerId.toString())
for (const addr of libp2p.getMultiaddrs().map(e => e.toString())) {
log('listening on', addr)
}

const ipfs = await createHelia({ libp2p, datastore, blockstore })

const orbitdb = await createOrbitDB({ ipfs, directory: orbiterDirectory, identities, id })

const orbiter = await Orbiter({ defaultAccess: options.defaultAccess, verbose: options.verbose, orbitdb })

// TODO: we might want to separate the key init to a separate 'init' CLI command
const initRPCKey = async ({ directory }) => {
const id = rpcId
const rpcDirectory = rpcPath(directory)
const path = join(rpcDirectory, 'keystore')
const keystore = await KeyStore({ path })
const identities = await Identities({ keystore })
const identity = await identities.createIdentity({ id })

await keystore.close()

return identity.publicKey
}

const authorizedRPCKey = await initRPCKey({ directory: options.directory })

const config = { orbiter: {}, rpc: {} }
config.orbiter.peerId = orbiter.orbitdb.ipfs.libp2p.peerId
config.orbiter.api = orbiter.orbitdb.ipfs.libp2p.getMultiaddrs().shift() // get 127.0.0.1 address
config.rpc.publicKeys = [authorizedRPCKey]
await saveConfig({ path: appDirectory, config })

const handleRPCMessages = async ({ stream }) => {
await pipe(stream, handleCommand({ config, orbitdb: orbiter.orbitdb, pins: orbiter.pins, dbs: orbiter.dbs, auth: orbiter.auth }), stream)
}

await orbiter.orbitdb.ipfs.libp2p.handle(voyagerRPCProtocol, handleRPCMessages)

process.on('SIGINT', async () => {
await orbiter.stop()
process.exit(0)
})
}
43 changes: 34 additions & 9 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@

import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'
import { daemon, authAdd, authDel, authList } from './lib/commands/index.js'
import daemon from './daemon.js'
import RPC from './rpc-client.js'
import { Responses } from './lib/messages/index.js'

yargs(hideBin(process.argv))
.scriptName('voyager')
.command(
'daemon',
'Launch Voyager',
() => {},
argv => {
daemon(argv)
async (argv) => {
await daemon({ options: argv })
})
.command('auth', 'Add/remove authorized addresses', yargs => {
yargs
Expand All @@ -25,8 +27,15 @@ yargs(hideBin(process.argv))
})
},
async argv => {
await authAdd(argv)
process.exit(0)
const { authAdd } = await RPC(argv)
const res = await authAdd(argv)
if (res.type === Responses.OK) {
console.log('ok')
process.exit(0)
} else {
console.error(res)
process.exit(1)
}
})
.command(
'del <id>',
Expand All @@ -38,16 +47,32 @@ yargs(hideBin(process.argv))
})
},
async argv => {
await authDel(argv)
process.exit(0)
const { authDel } = await RPC(argv)
const res = await authDel(argv)
if (res.type === Responses.OK) {
console.log('ok')
process.exit(0)
} else {
console.error(res)
process.exit(1)
}
})
.command(
'list',
'List authorized addresses',
() => {},
async argv => {
await authList(argv)
process.exit(0)
const { authList } = await RPC(argv)
const res = await authList()
if (res.type === Responses.OK) {
for (const id of res.message) {
console.log(id)
}
process.exit(0)
} else {
console.error(res)
process.exit(1)
}
})
.demandCommand(1, 'Error: use add or remove')
})
Expand Down
26 changes: 12 additions & 14 deletions src/lib/authorization.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,19 @@ export const Access = Object.freeze({
DENY: 2
})

export default ({ orbitdb, defaultAccess }) => {
export default async ({ orbitdb, defaultAccess }) => {
defaultAccess = defaultAccess || Access.DENY

useDatabaseType(Set)

const access = await orbitdb.open('access', { type: 'set' })

const add = async (id) => {
const access = await orbitdb.open('access', { type: 'set' })
await access.add(id)
await access.close()
}

const del = async (id) => {
const access = await orbitdb.open('access', { type: 'set' })
await access.del(id)
await access.close()
}

const hasAccess = async (id) => {
Expand All @@ -30,31 +28,31 @@ export default ({ orbitdb, defaultAccess }) => {

// @TODO is there a database which stores unique values + can get by value?
// @TODO add has(value) function to SetDB
for await (const a of access.iterator()) {
if (a.value === id) {
for await (const { value } of access.iterator()) {
if (value === id) {
found = true
break
}
}

await access.close()

return defaultAccess === Access.DENY ? found : !found
}

const all = async () => {
const access = await orbitdb.open('access', { type: 'set' })
const all = await access.all()
await access.close()

const all = (await access.all()).map(e => e.value)
return all
}

const close = async () => {
await access.close()
}

return {
defaultAccess,
add,
del,
hasAccess,
all
all,
close
}
}
6 changes: 0 additions & 6 deletions src/lib/commands/auth-add.js

This file was deleted.

6 changes: 0 additions & 6 deletions src/lib/commands/auth-del.js

This file was deleted.

8 changes: 0 additions & 8 deletions src/lib/commands/auth-list.js

This file was deleted.

54 changes: 0 additions & 54 deletions src/lib/commands/controller.js

This file was deleted.

22 changes: 0 additions & 22 deletions src/lib/commands/daemon.js

This file was deleted.

11 changes: 0 additions & 11 deletions src/lib/commands/index.js

This file was deleted.

8 changes: 4 additions & 4 deletions src/lib/handlers/index.js → src/lib/handle-request.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import handlePinRequest from './pin.js'
import handleUnpinRequest from './unpin.js'
import { createResponseMessage, parseMessage, Requests, Responses } from '../messages/index.js'
import handlePinRequest from './handlers/pin.js'
import handleUnpinRequest from './handlers/unpin.js'
import { createResponseMessage, parseMessage, Requests, Responses } from './messages/index.js'

export const handleRequest = (orbiter) => source => {
return (async function * () {
Expand All @@ -16,7 +16,7 @@ export const handleRequest = (orbiter) => source => {
}

// verify that the params have come from the user who owns the pubkey.
if (!await orbiter.orbitdb.identity.verify(signature, pubkey, addresses)) {
if (!await orbiter.orbitdb.identity.verify(signature, pubkey, JSON.stringify(addresses))) {
throw Object.assign(new Error('invalid signature'), { type: Responses.E_INVALID_SIGNATURE })
}

Expand Down
Loading
Loading