split into daemon and cli interface

This commit is contained in:
2024-10-07 14:11:49 +02:00
parent 582c90c32a
commit fcdad8c2a3
5 changed files with 539 additions and 265 deletions

View File

@@ -1,31 +1,17 @@
package main
import (
"bufio"
"context"
"flag"
"fmt"
"os"
"time"
"os/signal"
"strings"
"syscall"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/libp2p/go-libp2p/core/peer"
ipfslite "github.com/hsanjuan/ipfs-lite"
badger "github.com/ipfs/go-ds-badger2"
logging "github.com/ipfs/go-log/v2"
"github.com/k4lipso/pentapass/storage"
"github.com/k4lipso/pentapass/crypto/age"
"github.com/k4lipso/pentapass/rpc"
"github.com/k4lipso/pentapass/crypto"
)
var (
topicNameFlag = flag.String("topicName", "akdjlask-23klaj2idalj2-ajl2kjd3i-2ldakjd2", "name of topic to join")
dbPath = flag.String("db", "./db", "db file path")
nameSpace = flag.String("namespace", "crdt", "namespace")
logger = logging.Logger("globaldb")
// topicName = "globaldb-example"
// netTopic = "globaldb-example-net"
@@ -35,262 +21,237 @@ var (
func main() {
flag.Parse()
ctx := context.Background()
data := *dbPath
key, err := age.LoadOrGenerateKeys(*dbPath + "/age.key")
client, err := rpc.Receive(*dbPath)
if err != nil {
panic(err)
}
fmt.Printf("AgeKey: %s\n", key.String())
fmt.Printf("AgePublicKey: %s\n", key.Recipient().String())
//cipher, err := age.Encrypt([]byte("Test Message"), []string{key.Recipient().String()})
//fmt.Printf("Encrypted: %s\n", cipher)
//decrypted, err := age.Decrypt(cipher, key)
//fmt.Printf("Decrypted: %s\n", decrypted)
h, dht, err := storage.SetupLibp2pHost(ctx, *dbPath)
pid := h.ID().String()
fmt.Println(h.ID().String())
if err != nil {
panic(err)
}
ps, err := pubsub.NewGossipSub(ctx, h)
if err != nil {
panic(err)
}
//topic, err := ps.Join(*topicNameFlag)
//if err != nil {
// panic(err)
//}
go storage.DiscoverPeers(ctx, h, dht)
store, err := badger.NewDatastore(data, &badger.DefaultOptions)
if err != nil {
logger.Fatal(err)
}
defer store.Close()
ipfs, err := ipfslite.New(ctx, store, nil, h, dht, nil)
if err != nil {
logger.Fatal(err)
}
Cfg, err := storage.NewConfig(*dbPath + "/config.json")
if err != nil {
logger.Fatal(err)
}
storageHandler := storage.StorageHandler{
Ctx: ctx ,
Store: store,
Host: h,
Ipfs: ipfs,
PubSub: ps,
Key: key,
Config: Cfg,
}
storageHandler.InitNamespaces()
for _, val := range storageHandler.Namespaces {
defer val.Close()
}
fmt.Printf(`
Peer ID: %s
Listen address: %s
Topic: %s
Data Folder: %s
Ready!
Commands:
> list -> list items in the store
> get <key> -> get value for a key
> put <key> <value> -> store value on a key
> exit -> quit
`,
pid, storage.Listen, *topicNameFlag, data,
)
if len(os.Args) > 1 && os.Args[1] == "daemon" {
fmt.Println("Running in daemon mode")
go func() {
for {
fmt.Printf("%s - %d connected peers\n", time.Now().Format(time.Stamp), len(storage.ConnectedPeers(h)))
time.Sleep(10 * time.Second)
}
}()
signalChan := make(chan os.Signal, 20)
signal.Notify(
signalChan,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGHUP,
)
<-signalChan
fmt.Printf("dialing: %s\n", err)
return
}
fmt.Printf("> ")
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
text := scanner.Text()
fields := strings.Fields(text)
if len(fields) == 0 {
fmt.Printf("> ")
continue
}
var names []string
namespace := "root"
err = client.Call("Query.GetAllNames", &namespace, &names)
cmd := fields[0]
switch cmd {
case "exit", "quit":
return
case "debug":
if len(fields) < 2 {
fmt.Println("debug <on/off/peers>")
}
st := fields[1]
switch st {
case "on":
logging.SetLogLevel("globaldb", "debug")
case "off":
logging.SetLogLevel("globaldb", "error")
case "peers":
for _, p := range storage.ConnectedPeers(h) {
addrs, err := peer.AddrInfoToP2pAddrs(p)
if err != nil {
logger.Warn(err)
continue
}
for _, a := range addrs {
fmt.Println(a)
}
}
}
case "list":
if len(fields) < 2 {
fmt.Printf("Available Namespaces:\n")
for k := range storageHandler.Namespaces {
fmt.Printf("%s\n", k)
}
continue
}
namespace := fields[1]
fmt.Printf("Listing content of %s", namespace)
val, ok := storageHandler.Namespaces[namespace]
if !ok {
fmt.Println("Namespace does not exist")
continue
}
val.List()
case "get":
if len(fields) < 3 {
fmt.Println("get <namespace> <key>")
fmt.Println("> ")
continue
}
namespace := fields[1]
val, ok := storageHandler.Namespaces[namespace]
if !ok {
fmt.Println("Namespace does not exist")
continue
}
k := fields[2]
v, err := val.Get(k)
if err != nil {
printErr(err)
continue
}
fmt.Printf("[%s] -> %s\n", k, string(v))
case "generate":
if len(fields) < 3 {
fmt.Println("generate <namespace> <Service>")
fmt.Println("> ")
continue
}
namespace := fields[1]
val, ok := storageHandler.Namespaces[namespace]
if !ok {
fmt.Println("Namespace does not exist")
continue
}
service := fields[2]
password := crypto.NewPassword()
password.Service = service
data, err := password.ToJson()
if err != nil {
printErr(err)
continue
}
encryptedPassword, err := age.Encrypt(data, val.GetRecipients())
if err != nil {
printErr(err)
continue
}
err = val.Put(password.Id.String(), string(encryptedPassword))
if err != nil {
printErr(err)
continue
}
case "put":
if len(fields) < 4 {
fmt.Println("put <namespace> <key> <value>")
fmt.Println("> ")
continue
}
namespace := fields[1]
val, ok := storageHandler.Namespaces[namespace]
if !ok {
fmt.Println("Namespace does not exist")
continue
}
k := fields[2]
v := strings.Join(fields[3:], " ")
err := val.Put(k, v)
if err != nil {
printErr(err)
continue
}
}
fmt.Printf("> ")
if err != nil {
fmt.Println(err)
}
fmt.Println(names)
var password *crypto.Password
np := rpc.NamespaceService{ Namespace: "root", Service: "Test" }
err = client.Call("Query.Generate", &np, &password)
if err != nil {
fmt.Println(err)
}
fmt.Println(*password)
var success bool
err = client.Call("Query.Delete", &np, &success)
if success == true {
fmt.Println("Deleted Test")
}
var password2 *crypto.Password
err = client.Call("Query.Get", &np, &password2)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(*password2)
// fmt.Printf(`
//Peer ID: %s
//Listen address: %s
//Topic: %s
//Data Folder: %s
//
//Ready!
//
//Commands:
//
//> list -> list items in the store
//> get <key> -> get value for a key
//> put <key> <value> -> store value on a key
//> exit -> quit
//
//
//`,
// pid, storage.Listen, *topicNameFlag, data,
// )
//
// if len(os.Args) > 1 && os.Args[1] == "daemon" {
// fmt.Println("Running in daemon mode")
// go func() {
// for {
// fmt.Printf("%s - %d connected peers\n", time.Now().Format(time.Stamp), len(storage.ConnectedPeers(h)))
// time.Sleep(10 * time.Second)
// }
// }()
// signalChan := make(chan os.Signal, 20)
// signal.Notify(
// signalChan,
// syscall.SIGINT,
// syscall.SIGTERM,
// syscall.SIGHUP,
// )
// <-signalChan
// return
// }
//
// fmt.Printf("> ")
// scanner := bufio.NewScanner(os.Stdin)
// for scanner.Scan() {
// text := scanner.Text()
// fields := strings.Fields(text)
// if len(fields) == 0 {
// fmt.Printf("> ")
// continue
// }
//
// cmd := fields[0]
//
// switch cmd {
// case "exit", "quit":
// return
// case "debug":
// if len(fields) < 2 {
// fmt.Println("debug <on/off/peers>")
// }
// st := fields[1]
// switch st {
// case "on":
// logging.SetLogLevel("globaldb", "debug")
// case "off":
// logging.SetLogLevel("globaldb", "error")
// case "peers":
// for _, p := range storage.ConnectedPeers(h) {
// addrs, err := peer.AddrInfoToP2pAddrs(p)
// if err != nil {
// logger.Warn(err)
// continue
// }
// for _, a := range addrs {
// fmt.Println(a)
// }
// }
// }
// case "list":
// if len(fields) < 2 {
// fmt.Printf("Available Namespaces:\n")
// for k := range storageHandler.Namespaces {
// fmt.Printf("%s\n", k)
// }
// continue
// }
//
// namespace := fields[1]
//
// fmt.Printf("Listing content of %s", namespace)
//
// val, ok := storageHandler.Namespaces[namespace]
//
// if !ok {
// fmt.Println("Namespace does not exist")
// continue
// }
//
// val.List()
// case "get":
// if len(fields) < 3 {
// fmt.Println("get <namespace> <key>")
// fmt.Println("> ")
// continue
// }
//
// namespace := fields[1]
//
// val, ok := storageHandler.Namespaces[namespace]
//
// if !ok {
// fmt.Println("Namespace does not exist")
// continue
// }
//
// k := fields[2]
// v, err := val.Get(k)
// if err != nil {
// printErr(err)
// continue
// }
//
// fmt.Printf("[%s] -> %s\n", k, string(v))
// case "generate":
// if len(fields) < 3 {
// fmt.Println("generate <namespace> <Service>")
// fmt.Println("> ")
// continue
// }
//
// namespace := fields[1]
//
// val, ok := storageHandler.Namespaces[namespace]
//
// if !ok {
// fmt.Println("Namespace does not exist")
// continue
// }
//
// service := fields[2]
// password := crypto.NewPassword()
// password.Service = service
//
// data, err := password.ToJson()
// if err != nil {
// printErr(err)
// continue
// }
//
// encryptedPassword, err := age.Encrypt(data, val.GetRecipients())
// if err != nil {
// printErr(err)
// continue
// }
//
// //err = val.Put(password.Id.String(), string(encryptedPassword))
// err = val.Put(password.Service, string(encryptedPassword))
// if err != nil {
// printErr(err)
// continue
// }
// case "put":
// if len(fields) < 4 {
// fmt.Println("put <namespace> <key> <value>")
// fmt.Println("> ")
// continue
// }
//
// namespace := fields[1]
//
// val, ok := storageHandler.Namespaces[namespace]
//
// if !ok {
// fmt.Println("Namespace does not exist")
// continue
// }
//
//
// k := fields[2]
// v := strings.Join(fields[3:], " ")
// err := val.Put(k, v)
// if err != nil {
// printErr(err)
// continue
// }
// }
// fmt.Printf("> ")
// }
}
func printErr(err error) {

103
cmd/ppassd/ppassd.go Normal file
View File

@@ -0,0 +1,103 @@
package main
import (
"context"
"flag"
"fmt"
pubsub "github.com/libp2p/go-libp2p-pubsub"
ipfslite "github.com/hsanjuan/ipfs-lite"
badger "github.com/ipfs/go-ds-badger2"
logging "github.com/ipfs/go-log/v2"
"github.com/k4lipso/pentapass/storage"
"github.com/k4lipso/pentapass/rpc"
"github.com/k4lipso/pentapass/crypto/age"
)
var (
topicNameFlag = flag.String("topicName", "akdjlask-23klaj2idalj2-ajl2kjd3i-2ldakjd2", "name of topic to join")
dbPath = flag.String("db", "./db", "db file path")
nameSpace = flag.String("namespace", "crdt", "namespace")
logger = logging.Logger("globaldb")
// topicName = "globaldb-example"
// netTopic = "globaldb-example-net"
// config = "globaldb-example"
)
func main() {
flag.Parse()
ctx := context.Background()
data := *dbPath
key, err := age.LoadOrGenerateKeys(*dbPath + "/age.key")
if err != nil {
panic(err)
}
fmt.Printf("AgeKey: %s\n", key.String())
fmt.Printf("AgePublicKey: %s\n", key.Recipient().String())
//cipher, err := age.Encrypt([]byte("Test Message"), []string{key.Recipient().String()})
//fmt.Printf("Encrypted: %s\n", cipher)
//decrypted, err := age.Decrypt(cipher, key)
//fmt.Printf("Decrypted: %s\n", decrypted)
h, dht, err := storage.SetupLibp2pHost(ctx, *dbPath)
fmt.Println(h.ID().String())
if err != nil {
panic(err)
}
ps, err := pubsub.NewGossipSub(ctx, h)
if err != nil {
panic(err)
}
//topic, err := ps.Join(*topicNameFlag)
//if err != nil {
// panic(err)
//}
go storage.DiscoverPeers(ctx, h, dht)
store, err := badger.NewDatastore(data, &badger.DefaultOptions)
if err != nil {
logger.Fatal(err)
}
defer store.Close()
ipfs, err := ipfslite.New(ctx, store, nil, h, dht, nil)
if err != nil {
logger.Fatal(err)
}
Cfg, err := storage.NewConfig(*dbPath + "/config.json")
if err != nil {
logger.Fatal(err)
}
storageHandler := storage.StorageHandler{
Ctx: ctx ,
Store: store,
Host: h,
Ipfs: ipfs,
PubSub: ps,
Key: key,
Config: Cfg,
}
storageHandler.InitNamespaces()
for _, val := range storageHandler.Namespaces {
defer val.Close()
}
rpc.StorageHandler = &storageHandler
rpc.Serve(*dbPath)
}

View File

@@ -1,11 +1,14 @@
package crypto
import (
"math/rand"
"encoding/json"
"github.com/google/uuid"
)
const DEFAULT_LENGTH int = 25
type Password struct {
Service string `json:"Service"`
Url string `json:"Url"`
@@ -21,7 +24,7 @@ func (p *Password) ToJson() ([]byte, error) {
func GetPasswordFromJson(b []byte) (Password, error) {
var result Password
err := json.Unmarshal(b, result)
err := json.Unmarshal(b, &result)
if err != nil {
return Password{}, err
@@ -30,9 +33,20 @@ func GetPasswordFromJson(b []byte) (Password, error) {
return result, nil
}
func NewPassword() *Password {
func NewPassword(length int) *Password {
return &Password{
Id: uuid.New(),
Password: GenerateRandomString(length),
}
}
func GenerateRandomString(length int) string {
charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, length)
for i := range b {
b[i] = charset[rand.Intn(len(charset))]
}
return string(b)
}

139
rpc/rpc.go Normal file
View File

@@ -0,0 +1,139 @@
package rpc
import (
"fmt"
"net"
"net/rpc"
"net/http"
"os"
"os/signal"
"syscall"
"github.com/k4lipso/pentapass/storage"
"github.com/k4lipso/pentapass/crypto"
"github.com/k4lipso/pentapass/crypto/age"
)
var StorageHandler *storage.StorageHandler
type Query int
type NamespaceService struct {
Namespace string
Service string
}
func (t *Query) Generate(np *NamespaceService, reply *crypto.Password) error {
val, ok := StorageHandler.Namespaces[np.Namespace]
if !ok {
return fmt.Errorf("Namespace does not exist")
}
password := crypto.NewPassword(crypto.DEFAULT_LENGTH)
password.Service = np.Service
data, err := password.ToJson()
if err != nil {
return err
}
encryptedPassword, err := age.Encrypt(data, val.GetRecipients())
if err != nil {
return err
}
err = val.Put(password.Service, string(encryptedPassword))
if err != nil {
return err
}
*reply = *password
return nil
}
func (t *Query) Get(np *NamespaceService, reply *crypto.Password) error {
namespace := np.Namespace
val, ok := StorageHandler.Namespaces[namespace]
if !ok {
return fmt.Errorf("Namespace does not exist")
}
v, err := val.GetPassword(np.Service)
if err != nil {
return err
}
*reply = v
return nil
}
//func (t *Query) Add(password *crypto.Password, reply *[]string) error {
// return nil
//}
func (t *Query) Delete(np *NamespaceService, success *bool) error {
namespace := np.Namespace
val, ok := StorageHandler.Namespaces[namespace]
if !ok {
return fmt.Errorf("Namespace does not exist")
}
err := val.Delete(np.Service)
if err != nil {
*success = false
return err
}
*success = true
return nil
}
func (t *Query) GetAllNames(namespace *string, reply *[]string) error {
fmt.Println("RPC Request: Query::LoadedTriggers")
fmt.Printf("Listing content of %s", *namespace)
val, ok := StorageHandler.Namespaces[*namespace]
if !ok {
return fmt.Errorf("Namesapce does not exist")
}
*reply = val.GetAllNames()
return nil
}
func Serve(path string) {
query := new(Query)
rpc.Register(query)
rpc.HandleHTTP()
l, err := net.Listen("unix", path + "/rpc_test.socket")
if err != nil {
fmt.Printf("Error while listening on unix socket: %s\n", err)
}
go http.Serve(l, nil)
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt, syscall.SIGTERM)
func(ln net.Listener, c chan os.Signal) {
sig := <-c
fmt.Printf("Caught signal %s: shutting down.\n", sig)
ln.Close()
os.Exit(0)
}(l, sigc)
}
func Receive(path string) (*rpc.Client, error) {
client, err := rpc.DialHTTP("unix", path + "/rpc_test.socket")
if err != nil {
fmt.Printf("Cant connect to RPC server: %s\n", err)
}
return client, err
}

View File

@@ -216,6 +216,42 @@ func (n *Namespace) Put(k string, v string) error {
return err
}
func (n *Namespace) Delete(k string) error {
key := ds.NewKey(k)
err := n.Datastore.Delete(n.ctx, key)
if err != nil {
printErr(err)
}
return err
}
func (n *Namespace) GetPassword(k string) (password.Password, error) {
v, err := n.Datastore.Get(n.ctx, ds.NewKey(k))
if err != nil {
printErr(err)
return password.Password{}, err
}
val, err := age.Decrypt(v, n.Key)
if err != nil {
printErr(err)
return password.Password{}, err
}
pw, err := password.GetPasswordFromJson(val)
if err != nil {
printErr(err)
return password.Password{}, err
}
return pw, nil
}
func (n *Namespace) Get(k string) (string, error) {
v, err := n.Datastore.Get(n.ctx, ds.NewKey(k))
if err != nil {
@@ -226,6 +262,27 @@ func (n *Namespace) Get(k string) (string, error) {
return string(v), nil
}
func (n *Namespace) GetAllNames() []string {
q := query.Query{}
results, err := n.Datastore.Query(n.ctx, q)
if err != nil {
printErr(err)
}
var result []string
for r := range results.Next() {
if r.Error != nil {
printErr(err)
continue
}
result = append(result, r.Key)
}
return result
}
func (n *Namespace) List() {
q := query.Query{}
results, err := n.Datastore.Query(n.ctx, q)