Compare commits
28 Commits
582c90c32a
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
de0589761e
|
|||
|
6880401ac8
|
|||
| 4ee522c26c | |||
| b19eb8f422 | |||
| 817a14704b | |||
| a3f2a5ee6d | |||
| 069fdf8215 | |||
| e6d05290fc | |||
| ca6a51bf36 | |||
| aea7050a72 | |||
| c2f301a6b1 | |||
| 950e4fb30e | |||
| 7cb3636328 | |||
| f2e25cb402 | |||
| 528faedfb4 | |||
| 0419af16b0 | |||
| 873f653b86 | |||
| 74a3fc3900 | |||
| 73459571d5 | |||
| 18b2a65885 | |||
| 9968d69fdd | |||
| 7f667c0cf7 | |||
| 0bb7ce12bd | |||
| 9fce13c6db | |||
| 06c4c6492e | |||
| af1319f1e5 | |||
| 2fefbe5e6c | |||
| fcdad8c2a3 |
@@ -1,299 +1,300 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"context"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"time"
|
RPC "net/rpc"
|
||||||
"os/signal"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
"github.com/spf13/cobra"
|
||||||
"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/internal/rpc"
|
||||||
"github.com/k4lipso/pentapass/crypto/age"
|
"github.com/k4lipso/pentapass/internal/crypto"
|
||||||
"github.com/k4lipso/pentapass/crypto"
|
. "github.com/k4lipso/pentapass/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
topicNameFlag = flag.String("topicName", "akdjlask-23klaj2idalj2-ajl2kjd3i-2ldakjd2", "name of topic to join")
|
dbPath string
|
||||||
dbPath = flag.String("db", "./db", "db file path")
|
debug bool
|
||||||
nameSpace = flag.String("namespace", "crdt", "namespace")
|
rpcClient *RPC.Client
|
||||||
logger = logging.Logger("globaldb")
|
|
||||||
// topicName = "globaldb-example"
|
|
||||||
// netTopic = "globaldb-example-net"
|
|
||||||
// config = "globaldb-example"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func main() {
|
func parseSingleArgWithOptionalVault(args []string) (vault string, arg string){
|
||||||
flag.Parse()
|
if len(args) == 1 {
|
||||||
ctx := context.Background()
|
vault = "root"
|
||||||
data := *dbPath
|
arg = args[0]
|
||||||
|
} else {
|
||||||
key, err := age.LoadOrGenerateKeys(*dbPath + "/age.key")
|
vault = args[0]
|
||||||
|
arg = args[1]
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("AgeKey: %s\n", key.String())
|
return vault, arg
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
`,
|
// Create the root command
|
||||||
pid, storage.Listen, *topicNameFlag, data,
|
var rootCmd = &cobra.Command{
|
||||||
)
|
Use: "ppass",
|
||||||
|
Short: "Interact with the Password Store",
|
||||||
|
}
|
||||||
|
|
||||||
if len(os.Args) > 1 && os.Args[1] == "daemon" {
|
// Create the 'list' subcommand
|
||||||
fmt.Println("Running in daemon mode")
|
var listCmd = &cobra.Command{
|
||||||
go func() {
|
Use: "list [vault]",
|
||||||
for {
|
Short: "List all passwords",
|
||||||
fmt.Printf("%s - %d connected peers\n", time.Now().Format(time.Stamp), len(storage.ConnectedPeers(h)))
|
Args: cobra.RangeArgs(0, 1),
|
||||||
time.Sleep(10 * time.Second)
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
}
|
vault := "root"
|
||||||
}()
|
|
||||||
signalChan := make(chan os.Signal, 20)
|
|
||||||
signal.Notify(
|
|
||||||
signalChan,
|
|
||||||
syscall.SIGINT,
|
|
||||||
syscall.SIGTERM,
|
|
||||||
syscall.SIGHUP,
|
|
||||||
)
|
|
||||||
<-signalChan
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("> ")
|
if len(args) == 1 {
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
vault = args[0]
|
||||||
for scanner.Scan() {
|
|
||||||
text := scanner.Text()
|
|
||||||
fields := strings.Fields(text)
|
|
||||||
if len(fields) == 0 {
|
|
||||||
fmt.Printf("> ")
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := fields[0]
|
var names []string
|
||||||
|
err := rpcClient.Call("Query.GetAllNames", &vault, &names)
|
||||||
|
|
||||||
switch cmd {
|
if err != nil {
|
||||||
case "exit", "quit":
|
Logger.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
Logger.Info(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var generateCmd = &cobra.Command{
|
||||||
|
Use: "generate",
|
||||||
|
Short: "Generate a Password",
|
||||||
|
Args: cobra.RangeArgs(1, 2),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
vault, serviceName := parseSingleArgWithOptionalVault(args)
|
||||||
|
|
||||||
|
var password *crypto.Password
|
||||||
|
np := rpc.VaultService{ Vault: vault, Service: serviceName }
|
||||||
|
err := rpcClient.Call("Query.Generate", &np, &password)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Info(password.Password)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var showCmd = &cobra.Command{
|
||||||
|
Use: "show",
|
||||||
|
Short: "show a Password",
|
||||||
|
Args: cobra.RangeArgs(1, 2),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
vault, serviceName := parseSingleArgWithOptionalVault(args)
|
||||||
|
|
||||||
|
var password *crypto.Password
|
||||||
|
np := rpc.VaultService{ Vault: vault, Service: serviceName }
|
||||||
|
err := rpcClient.Call("Query.Get", &np, &password)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Error(err)
|
||||||
return
|
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("> ")
|
|
||||||
|
Logger.Info(password.Password)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var vaultCmd = &cobra.Command{
|
||||||
|
Use: "vault",
|
||||||
|
Short: "Add, delete or list vaults",
|
||||||
|
}
|
||||||
|
|
||||||
|
var addVaultCmd = &cobra.Command{
|
||||||
|
Use: "add",
|
||||||
|
Short: "add a vault",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
vault := args[0]
|
||||||
|
|
||||||
|
var placeholder int
|
||||||
|
err := rpcClient.Call("Query.AddVault", &vault, &placeholder)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Infof("Vault %s was added\n", vault)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var deleteVaultCmd = &cobra.Command{
|
||||||
|
Use: "delete",
|
||||||
|
Short: "delete a vault",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
vault := args[0]
|
||||||
|
|
||||||
|
var placeholder int
|
||||||
|
err := rpcClient.Call("Query.DeleteVault", &vault, &placeholder)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Infof("Vault %s was deleted\n", vault)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var listVaultsCmd = &cobra.Command{
|
||||||
|
Use: "list",
|
||||||
|
Short: "list all vaults",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
var reply []string
|
||||||
|
err := rpcClient.Call("Query.ListVaults", 0, &reply)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Info("Vaults:")
|
||||||
|
for _, ns := range reply {
|
||||||
|
Logger.Info(ns)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var peerCmd = &cobra.Command{
|
||||||
|
Use: "peer",
|
||||||
|
Short: "Add or remove peers. Get your own peering information",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var infoCmd = &cobra.Command{
|
||||||
|
Use: "info",
|
||||||
|
Short: "print your own peerstring",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
var result *string
|
||||||
|
err := rpcClient.Call("Query.GetPeerString", 0, &result)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Info(*result)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var addPeerCmd = &cobra.Command{
|
||||||
|
Use: "add",
|
||||||
|
Short: "add a peer",
|
||||||
|
Args: cobra.RangeArgs(1, 2),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
vault, peerString := parseSingleArgWithOptionalVault(args)
|
||||||
|
|
||||||
|
var success *bool
|
||||||
|
np := rpc.VaultPeer{ Vault: vault, Peer: peerString }
|
||||||
|
err := rpcClient.Call("Query.AddPeer", &np, &success)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if *success {
|
||||||
|
Logger.Infof("Added peer: %s", peerString)
|
||||||
|
} else {
|
||||||
|
Logger.Infof("Could not add peer: %s", peerString)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var removePeerCmd = &cobra.Command{
|
||||||
|
Use: "remove",
|
||||||
|
Short: "remove a peer",
|
||||||
|
Args: cobra.RangeArgs(1, 2),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
vault, peerString := parseSingleArgWithOptionalVault(args)
|
||||||
|
|
||||||
|
var success *bool
|
||||||
|
np := rpc.VaultPeer{ Vault: vault, Peer: peerString }
|
||||||
|
err := rpcClient.Call("Query.DeletePeer", &np, &success)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if *success {
|
||||||
|
Logger.Infof("Removed peer: %s", peerString)
|
||||||
|
} else {
|
||||||
|
Logger.Infof("Could not find peer: %s", peerString)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var deleteCmd = &cobra.Command{
|
||||||
|
Use: "delete",
|
||||||
|
Short: "delete a Password",
|
||||||
|
Args: cobra.RangeArgs(1, 2),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
vault, serviceName := parseSingleArgWithOptionalVault(args)
|
||||||
|
|
||||||
|
var success *bool
|
||||||
|
np := rpc.VaultService{ Vault: vault, Service: serviceName }
|
||||||
|
err := rpcClient.Call("Query.Delete", &np, &success)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if *success {
|
||||||
|
Logger.Infof("Deleted password: %s", serviceName)
|
||||||
|
} else {
|
||||||
|
Logger.Infof("Could not find password: %s", serviceName)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.PersistentFlags().StringVar(&dbPath, "db", "", "db path")
|
||||||
|
rootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "enable debug mode")
|
||||||
|
rootCmd.MarkPersistentFlagRequired("db")
|
||||||
|
|
||||||
|
peerCmd.AddCommand(addPeerCmd)
|
||||||
|
peerCmd.AddCommand(removePeerCmd)
|
||||||
|
peerCmd.AddCommand(infoCmd)
|
||||||
|
|
||||||
|
vaultCmd.AddCommand(addVaultCmd)
|
||||||
|
vaultCmd.AddCommand(deleteVaultCmd)
|
||||||
|
vaultCmd.AddCommand(listVaultsCmd)
|
||||||
|
|
||||||
|
rootCmd.AddCommand(listCmd)
|
||||||
|
rootCmd.AddCommand(generateCmd)
|
||||||
|
rootCmd.AddCommand(showCmd)
|
||||||
|
rootCmd.AddCommand(deleteCmd)
|
||||||
|
rootCmd.AddCommand(peerCmd)
|
||||||
|
rootCmd.AddCommand(vaultCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cobra.OnInitialize(func() {
|
||||||
|
var tmpClient *RPC.Client
|
||||||
|
tmpClient, err := rpc.Receive(dbPath)
|
||||||
|
rpcClient = tmpClient
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Fatalf("dialing: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
InitLogger(debug)
|
||||||
|
})
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
Logger.Error(err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func printErr(err error) {
|
|
||||||
fmt.Println("error:", err)
|
|
||||||
fmt.Println("> ")
|
|
||||||
}
|
|
||||||
|
|||||||
99
cmd/ppassd/ppassd.go
Normal file
99
cmd/ppassd/ppassd.go
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
|
||||||
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
|
ipfslite "github.com/hsanjuan/ipfs-lite"
|
||||||
|
badger "github.com/ipfs/go-ds-badger2"
|
||||||
|
|
||||||
|
"github.com/k4lipso/pentapass/internal/storage"
|
||||||
|
"github.com/k4lipso/pentapass/internal/rpc"
|
||||||
|
"github.com/k4lipso/pentapass/internal/crypto/age"
|
||||||
|
. "github.com/k4lipso/pentapass/internal/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
dbPath = flag.String("db", "./db", "db file path")
|
||||||
|
debug = flag.Bool("debug", false, "log debug information")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
InitLogger(*debug)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
data := *dbPath
|
||||||
|
|
||||||
|
Logger.Info("Initializing passd")
|
||||||
|
Logger.Info("Looking for Keys...")
|
||||||
|
key, err := age.LoadOrGenerateKeys(*dbPath + "/age.key")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Infof("Found Key: %s", key.Recipient().String())
|
||||||
|
Logger.Info("Setting up DHT...")
|
||||||
|
|
||||||
|
h, dht, err := storage.SetupLibp2pHost(ctx, *dbPath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Infof("Own ID: %s", h.ID().String())
|
||||||
|
|
||||||
|
ps, err := pubsub.NewGossipSub(ctx, h)
|
||||||
|
if err != nil {
|
||||||
|
Logger.Panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Info("Initializing datastore...")
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
storageHandler := storage.StorageHandler{
|
||||||
|
Ctx: ctx ,
|
||||||
|
Store: store,
|
||||||
|
Host: h,
|
||||||
|
Ipfs: ipfs,
|
||||||
|
PubSub: ps,
|
||||||
|
Key: key,
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Info("Starting peer discovery...")
|
||||||
|
go storageHandler.RunBackground(ctx, h, dht)
|
||||||
|
|
||||||
|
configPath := *dbPath + "/config.json"
|
||||||
|
Logger.Infof("Loading config from: %s", configPath)
|
||||||
|
Cfg, err := storageHandler.NewConfig(configPath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
storageHandler.Config = Cfg
|
||||||
|
storageHandler.ConfigPath = configPath
|
||||||
|
|
||||||
|
Logger.Infof("Setting up Vaults...")
|
||||||
|
storageHandler.InitVaults()
|
||||||
|
|
||||||
|
for _, val := range storageHandler.Vaults {
|
||||||
|
defer val.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Infof("Initialization complete!")
|
||||||
|
Logger.Infof("Serving RPC for ppass cli")
|
||||||
|
rpc.StorageHandler = &storageHandler
|
||||||
|
rpc.Serve(*dbPath)
|
||||||
|
}
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
package rsa
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/pem"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
var (
|
|
||||||
privateKeyName = "rsa_private_key.pem"
|
|
||||||
publicKeyName = "rsa_public_key.pem"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GenerateKeys(path string) (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
|
||||||
// Generate a new RSA key pair
|
|
||||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the private key to a file
|
|
||||||
privateKeyPath := path + privateKeyName
|
|
||||||
privateKeyFile, err := os.Create(privateKeyPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
defer privateKeyFile.Close()
|
|
||||||
|
|
||||||
privateKeyPEM := pem.EncodeToMemory(&pem.Block{
|
|
||||||
Type: "RSA PRIVATE KEY",
|
|
||||||
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
|
|
||||||
})
|
|
||||||
_, err = privateKeyFile.Write(privateKeyPEM)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
fmt.Printf("Private key saved to %s\n", privateKeyPath)
|
|
||||||
|
|
||||||
// Extract and save the public key
|
|
||||||
publicKeyPath := path + publicKeyName
|
|
||||||
publicKeyFile, err := os.Create(publicKeyPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
defer publicKeyFile.Close()
|
|
||||||
|
|
||||||
publicKey := &privateKey.PublicKey
|
|
||||||
publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
publicKeyPEM := pem.EncodeToMemory(&pem.Block{
|
|
||||||
Type: "RSA PUBLIC KEY",
|
|
||||||
Bytes: publicKeyBytes,
|
|
||||||
})
|
|
||||||
_, err = publicKeyFile.Write(publicKeyPEM)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
fmt.Printf("Public key saved to %s\n", publicKeyPath)
|
|
||||||
|
|
||||||
return privateKey, publicKey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadKeys(path string) (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
|
||||||
// Load private key from file
|
|
||||||
privateKeyPath := path + privateKeyName
|
|
||||||
privateKeyData, err := os.ReadFile(privateKeyPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to read private key: %v", err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
block, _ := pem.Decode(privateKeyData)
|
|
||||||
if block == nil || block.Type != "RSA PRIVATE KEY" {
|
|
||||||
log.Fatalf("Failed to decode PEM block containing private key")
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to parse private key: %v", err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load public key from file
|
|
||||||
publicKeyPath := path + publicKeyName
|
|
||||||
publicKeyData, err := os.ReadFile(publicKeyPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to read public key: %v", err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
block, _ = pem.Decode(publicKeyData)
|
|
||||||
if block == nil || block.Type != "RSA PUBLIC KEY" {
|
|
||||||
log.Fatalf("Failed to decode PEM block containing public key")
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to parse public key: %v", err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
publicKey := publicKeyInterface.(*rsa.PublicKey)
|
|
||||||
|
|
||||||
return privateKey, publicKey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func LoadOrGenerateKeys(path string) (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
|
||||||
_, err := os.Open(path + privateKeyName)
|
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
|
||||||
fmt.Println("Not Exists - Generate Keys")
|
|
||||||
return GenerateKeys(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
return LoadKeys(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func Encrypt(data []byte, key *rsa.PublicKey) ([]byte, error) {
|
|
||||||
ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, key, data)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to encrypt: %v", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ciphertext, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Decrypt(data []byte, key *rsa.PrivateKey) ([]byte, error) {
|
|
||||||
decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, key, data)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to decrypt: %v", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return decrypted, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
29
go.mod
29
go.mod
@@ -4,15 +4,18 @@ go 1.22.5
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
filippo.io/age v1.2.0
|
filippo.io/age v1.2.0
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
github.com/hsanjuan/ipfs-lite v1.8.2
|
github.com/hsanjuan/ipfs-lite v1.8.2
|
||||||
github.com/ipfs/go-datastore v0.6.0
|
github.com/ipfs/go-datastore v0.6.0
|
||||||
github.com/ipfs/go-ds-badger2 v0.1.3
|
github.com/ipfs/go-ds-badger2 v0.1.3
|
||||||
github.com/ipfs/go-ds-crdt v0.5.2
|
github.com/ipfs/go-ds-crdt v0.5.2
|
||||||
github.com/ipfs/go-log/v2 v2.5.1
|
|
||||||
github.com/libp2p/go-libp2p v0.35.4
|
github.com/libp2p/go-libp2p v0.35.4
|
||||||
github.com/libp2p/go-libp2p-kad-dht v0.25.2
|
github.com/libp2p/go-libp2p-kad-dht v0.25.2
|
||||||
github.com/libp2p/go-libp2p-pubsub v0.11.0
|
github.com/libp2p/go-libp2p-pubsub v0.11.0
|
||||||
|
github.com/mudler/edgevpn v0.28.3
|
||||||
github.com/multiformats/go-multiaddr v0.13.0
|
github.com/multiformats/go-multiaddr v0.13.0
|
||||||
|
github.com/sirupsen/logrus v1.8.1
|
||||||
|
github.com/spf13/cobra v0.0.5
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -21,6 +24,8 @@ require (
|
|||||||
github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 // indirect
|
github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 // indirect
|
||||||
github.com/benbjohnson/clock v1.3.5 // indirect
|
github.com/benbjohnson/clock v1.3.5 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/c-robinson/iplib v1.0.8 // indirect
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
github.com/cespare/xxhash v1.1.0 // indirect
|
github.com/cespare/xxhash v1.1.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/containerd/cgroups v1.1.0 // indirect
|
github.com/containerd/cgroups v1.1.0 // indirect
|
||||||
@@ -48,13 +53,13 @@ require (
|
|||||||
github.com/golang/snappy v0.0.1 // indirect
|
github.com/golang/snappy v0.0.1 // indirect
|
||||||
github.com/google/gopacket v1.1.19 // indirect
|
github.com/google/gopacket v1.1.19 // indirect
|
||||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
|
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
|
||||||
github.com/gorilla/websocket v1.5.3 // indirect
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/huin/goupnp v1.3.0 // indirect
|
github.com/huin/goupnp v1.3.0 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
github.com/ipfs/bbloom v0.0.4 // indirect
|
github.com/ipfs/bbloom v0.0.4 // indirect
|
||||||
github.com/ipfs/boxo v0.21.0 // indirect
|
github.com/ipfs/boxo v0.21.0 // indirect
|
||||||
github.com/ipfs/go-bitfield v1.1.0 // indirect
|
github.com/ipfs/go-bitfield v1.1.0 // indirect
|
||||||
@@ -67,6 +72,7 @@ require (
|
|||||||
github.com/ipfs/go-ipld-format v0.6.0 // indirect
|
github.com/ipfs/go-ipld-format v0.6.0 // indirect
|
||||||
github.com/ipfs/go-ipld-legacy v0.2.1 // indirect
|
github.com/ipfs/go-ipld-legacy v0.2.1 // indirect
|
||||||
github.com/ipfs/go-log v1.0.5 // indirect
|
github.com/ipfs/go-log v1.0.5 // indirect
|
||||||
|
github.com/ipfs/go-log/v2 v2.5.1 // indirect
|
||||||
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
|
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
|
||||||
github.com/ipfs/go-peertaskqueue v0.8.1 // indirect
|
github.com/ipfs/go-peertaskqueue v0.8.1 // indirect
|
||||||
github.com/ipld/go-codec-dagpb v1.6.0 // indirect
|
github.com/ipld/go-codec-dagpb v1.6.0 // indirect
|
||||||
@@ -91,7 +97,7 @@ require (
|
|||||||
github.com/libp2p/go-yamux/v4 v4.0.1 // indirect
|
github.com/libp2p/go-yamux/v4 v4.0.1 // indirect
|
||||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/miekg/dns v1.1.61 // indirect
|
github.com/miekg/dns v1.1.62 // indirect
|
||||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
||||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
||||||
github.com/minio/sha256-simd v1.0.1 // indirect
|
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||||
@@ -106,7 +112,7 @@ require (
|
|||||||
github.com/multiformats/go-multistream v0.5.0 // indirect
|
github.com/multiformats/go-multistream v0.5.0 // indirect
|
||||||
github.com/multiformats/go-varint v0.0.7 // indirect
|
github.com/multiformats/go-varint v0.0.7 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.19.1 // indirect
|
github.com/onsi/ginkgo/v2 v2.20.1 // indirect
|
||||||
github.com/opencontainers/runtime-spec v1.2.0 // indirect
|
github.com/opencontainers/runtime-spec v1.2.0 // indirect
|
||||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||||
@@ -138,6 +144,7 @@ require (
|
|||||||
github.com/quic-go/webtransport-go v0.8.0 // indirect
|
github.com/quic-go/webtransport-go v0.8.0 // indirect
|
||||||
github.com/raulk/go-watchdog v1.3.0 // indirect
|
github.com/raulk/go-watchdog v1.3.0 // indirect
|
||||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.3 // indirect
|
||||||
github.com/stretchr/testify v1.9.0 // indirect
|
github.com/stretchr/testify v1.9.0 // indirect
|
||||||
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect
|
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect
|
||||||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
|
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
|
||||||
@@ -151,14 +158,14 @@ require (
|
|||||||
go.uber.org/mock v0.4.0 // indirect
|
go.uber.org/mock v0.4.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
golang.org/x/crypto v0.25.0 // indirect
|
golang.org/x/crypto v0.26.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||||
golang.org/x/mod v0.19.0 // indirect
|
golang.org/x/mod v0.20.0 // indirect
|
||||||
golang.org/x/net v0.27.0 // indirect
|
golang.org/x/net v0.28.0 // indirect
|
||||||
golang.org/x/sync v0.7.0 // indirect
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
golang.org/x/sys v0.22.0 // indirect
|
golang.org/x/sys v0.24.0 // indirect
|
||||||
golang.org/x/text v0.16.0 // indirect
|
golang.org/x/text v0.17.0 // indirect
|
||||||
golang.org/x/tools v0.23.0 // indirect
|
golang.org/x/tools v0.24.0 // indirect
|
||||||
gonum.org/v1/gonum v0.15.0 // indirect
|
gonum.org/v1/gonum v0.15.0 // indirect
|
||||||
google.golang.org/protobuf v1.34.2 // indirect
|
google.golang.org/protobuf v1.34.2 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|||||||
54
go.sum
54
go.sum
@@ -33,6 +33,10 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
|||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||||
|
github.com/c-robinson/iplib v1.0.8 h1:exDRViDyL9UBLcfmlxxkY5odWX5092nPsQIykHXhIn4=
|
||||||
|
github.com/c-robinson/iplib v1.0.8/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
@@ -188,6 +192,7 @@ github.com/hsanjuan/ipfs-lite v1.8.2 h1:PwYpfvh4HpActJyP03O4k6QznBR3xd6NmRWeOSJu
|
|||||||
github.com/hsanjuan/ipfs-lite v1.8.2/go.mod h1:PfY4I2whwnZBHviwoajNzwjSyR9IQIJHxkpPAc5SLxw=
|
github.com/hsanjuan/ipfs-lite v1.8.2/go.mod h1:PfY4I2whwnZBHviwoajNzwjSyR9IQIJHxkpPAc5SLxw=
|
||||||
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
||||||
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
|
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
|
||||||
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
|
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
|
||||||
@@ -315,8 +320,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
|||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||||
github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
|
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
|
||||||
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
|
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
|
||||||
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8=
|
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8=
|
||||||
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms=
|
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms=
|
||||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc=
|
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc=
|
||||||
@@ -334,6 +339,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
|
|||||||
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||||
|
github.com/mudler/edgevpn v0.28.3 h1:yIuoMExwKHy/mNMBXIsm6FUFbnB9ELIxw9KXrK9KHDk=
|
||||||
|
github.com/mudler/edgevpn v0.28.3/go.mod h1:HWcdIwj5zBgOD04Hn3I+J5E5Yb3kK1CwwWaEe6/QERo=
|
||||||
github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=
|
github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=
|
||||||
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
|
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
|
||||||
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
|
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
|
||||||
@@ -362,10 +369,10 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
|
|||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||||
github.com/onsi/ginkgo/v2 v2.19.1 h1:QXgq3Z8Crl5EL1WBAC98A5sEBHARrAJNzAmMxzLcRF0=
|
github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo=
|
||||||
github.com/onsi/ginkgo/v2 v2.19.1/go.mod h1:O3DtEWQkPa/F7fBMgmZQKKsluAy8pd3rEQdrjkPb9zA=
|
github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI=
|
||||||
github.com/onsi/gomega v1.34.0 h1:eSSPsPNp6ZpsG8X1OVmOTxig+CblTc4AxpPBykhe2Os=
|
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||||
github.com/onsi/gomega v1.34.0/go.mod h1:MIKI8c+f+QLWk+hxbePD4i0LMJSExPaZOVfkoex4cAo=
|
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||||
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
|
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
|
||||||
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||||
@@ -476,8 +483,11 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
|||||||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
||||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||||
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||||
|
github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN23diwyr69Qs=
|
||||||
|
github.com/smartystreets/assertions v1.13.0/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8=
|
||||||
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
|
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
|
||||||
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
|
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
|
||||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||||
@@ -487,8 +497,10 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b
|
|||||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
|
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@@ -574,8 +586,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
|||||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||||
@@ -592,8 +604,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||||
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -617,8 +629,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
|||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@@ -634,8 +646,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -666,8 +678,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
@@ -683,8 +695,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
@@ -708,8 +720,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
|
|||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"filippo.io/age"
|
"filippo.io/age"
|
||||||
|
|
||||||
|
. "github.com/k4lipso/pentapass/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -30,7 +32,7 @@ func GenerateAgeKey(filename string) (*age.X25519Identity, error) {
|
|||||||
return nil, fmt.Errorf("failed to save private key to file: %w", err)
|
return nil, fmt.Errorf("failed to save private key to file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Private key saved to %s\n", filename)
|
Logger.Infof("Private key saved to %s\n", filename)
|
||||||
return identity, nil
|
return identity, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +55,7 @@ func LoadAgeKey(filename string) (*age.X25519Identity, error) {
|
|||||||
func LoadOrGenerateKeys(filename string) (*age.X25519Identity, error) {
|
func LoadOrGenerateKeys(filename string) (*age.X25519Identity, error) {
|
||||||
_, err := os.Open(filename)
|
_, err := os.Open(filename)
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
fmt.Println("Not Exists - Generate Keys")
|
Logger.Info("No Key found. Generating Key")
|
||||||
return GenerateAgeKey(filename)
|
return GenerateAgeKey(filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
package crypto
|
package crypto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/rand"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const DEFAULT_LENGTH int = 25
|
||||||
|
|
||||||
type Password struct {
|
type Password struct {
|
||||||
Service string `json:"Service"`
|
Service string `json:"Service"`
|
||||||
Url string `json:"Url"`
|
Url string `json:"Url"`
|
||||||
@@ -21,7 +24,7 @@ func (p *Password) ToJson() ([]byte, error) {
|
|||||||
|
|
||||||
func GetPasswordFromJson(b []byte) (Password, error) {
|
func GetPasswordFromJson(b []byte) (Password, error) {
|
||||||
var result Password
|
var result Password
|
||||||
err := json.Unmarshal(b, result)
|
err := json.Unmarshal(b, &result)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Password{}, err
|
return Password{}, err
|
||||||
@@ -30,9 +33,20 @@ func GetPasswordFromJson(b []byte) (Password, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPassword() *Password {
|
func NewPassword(length int) *Password {
|
||||||
return &Password{
|
return &Password{
|
||||||
Id: uuid.New(),
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
48
internal/log/log.go
Normal file
48
internal/log/log.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Logger = logrus.New()
|
||||||
|
|
||||||
|
type CustomTextFormatter struct {
|
||||||
|
logrus.TextFormatter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *CustomTextFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||||
|
if entry.Level != logrus.InfoLevel {
|
||||||
|
return f.TextFormatter.Format(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
b.WriteString(entry.Message)
|
||||||
|
b.WriteByte('\n')
|
||||||
|
return b.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func InitLogger(debug bool) {
|
||||||
|
if debug {
|
||||||
|
Logger.SetFormatter(&logrus.TextFormatter{
|
||||||
|
DisableLevelTruncation: true,
|
||||||
|
PadLevelText: true,
|
||||||
|
DisableTimestamp: true,
|
||||||
|
})
|
||||||
|
Logger.SetLevel(logrus.DebugLevel)
|
||||||
|
} else {
|
||||||
|
Logger.SetFormatter(&CustomTextFormatter{
|
||||||
|
logrus.TextFormatter{
|
||||||
|
DisableLevelTruncation: true,
|
||||||
|
PadLevelText: true,
|
||||||
|
DisableTimestamp: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
Logger.SetLevel(logrus.InfoLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.SetOutput(os.Stdout)
|
||||||
|
}
|
||||||
211
internal/rpc/rpc.go
Normal file
211
internal/rpc/rpc.go
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/rpc"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/k4lipso/pentapass/internal/storage"
|
||||||
|
"github.com/k4lipso/pentapass/internal/crypto"
|
||||||
|
"github.com/k4lipso/pentapass/internal/crypto/age"
|
||||||
|
. "github.com/k4lipso/pentapass/internal/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var StorageHandler *storage.StorageHandler
|
||||||
|
|
||||||
|
type Query int
|
||||||
|
|
||||||
|
type VaultService struct {
|
||||||
|
Vault string
|
||||||
|
Service string
|
||||||
|
}
|
||||||
|
|
||||||
|
type VaultPeer struct {
|
||||||
|
Vault string
|
||||||
|
Peer string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Query) Generate(np *VaultService, reply *crypto.Password) error {
|
||||||
|
val, ok := StorageHandler.Vaults[np.Vault]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Vault 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 *VaultService, reply *crypto.Password) error {
|
||||||
|
vault := np.Vault
|
||||||
|
val, ok := StorageHandler.Vaults[vault]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Vault 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) GetPeerString(_ *int, result *string) error {
|
||||||
|
*result = StorageHandler.Host.ID().String() + "/" + StorageHandler.Key.Recipient().String()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Query) AddPeer(np *VaultPeer, success *bool) error {
|
||||||
|
vault := np.Vault
|
||||||
|
val, ok := StorageHandler.Vaults[vault]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Vault does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
peer, err := storage.PeerFromString(np.Peer)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Infof("Error parsing peer string: %s\n", err)
|
||||||
|
*success = false
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
val.AddPeer(peer)
|
||||||
|
*success = true
|
||||||
|
StorageHandler.UpdateConfig()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Query) DeletePeer(np *VaultPeer, success *bool) error {
|
||||||
|
vault := np.Vault
|
||||||
|
val, ok := StorageHandler.Vaults[vault]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Vault does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
peer, err := storage.PeerFromString(np.Peer)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Infof("Error parsing peer string: %s\n", err)
|
||||||
|
*success = false
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
val.RemovePeer(peer)
|
||||||
|
*success = true
|
||||||
|
StorageHandler.UpdateConfig()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Query) Delete(np *VaultService, success *bool) error {
|
||||||
|
vault := np.Vault
|
||||||
|
val, ok := StorageHandler.Vaults[vault]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Vault does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := val.Delete(np.Service)
|
||||||
|
if err != nil {
|
||||||
|
*success = false
|
||||||
|
if err == storage.ErrNotFound {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*success = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Query) AddVault(vault *string, _ *int) error {
|
||||||
|
_, err := StorageHandler.AddVault(*vault)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Query) DeleteVault(vault *string, _ *int) error {
|
||||||
|
err := StorageHandler.DeleteVault(*vault)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Query) ListVaults(_ *int, reply *[]string) error {
|
||||||
|
*reply = StorageHandler.ListVaults()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Query) GetAllNames(vault *string, reply *[]string) error {
|
||||||
|
Logger.Infof("Listing content of %s", *vault)
|
||||||
|
|
||||||
|
val, ok := StorageHandler.Vaults[*vault]
|
||||||
|
|
||||||
|
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 {
|
||||||
|
Logger.Errorf("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
|
||||||
|
Logger.Infof("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 {
|
||||||
|
Logger.Errorf("Cant connect to RPC server: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, err
|
||||||
|
}
|
||||||
469
internal/storage/storage.go
Normal file
469
internal/storage/storage.go
Normal file
@@ -0,0 +1,469 @@
|
|||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"fmt"
|
||||||
|
"encoding/json"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
"sync"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mudler/edgevpn/pkg/utils"
|
||||||
|
"github.com/libp2p/go-libp2p"
|
||||||
|
dht "github.com/libp2p/go-libp2p-kad-dht"
|
||||||
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
|
"github.com/libp2p/go-libp2p/core/host"
|
||||||
|
"github.com/libp2p/go-libp2p/core/peer"
|
||||||
|
"github.com/libp2p/go-libp2p/core/control"
|
||||||
|
"github.com/libp2p/go-libp2p/core/network"
|
||||||
|
//"github.com/libp2p/go-libp2p/core/peerstore"
|
||||||
|
discovery "github.com/libp2p/go-libp2p/p2p/discovery/routing"
|
||||||
|
ipfslite "github.com/hsanjuan/ipfs-lite"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
multiaddr "github.com/multiformats/go-multiaddr"
|
||||||
|
|
||||||
|
badger "github.com/ipfs/go-ds-badger2"
|
||||||
|
dsq "github.com/ipfs/go-datastore/query"
|
||||||
|
crypto "github.com/libp2p/go-libp2p/core/crypto"
|
||||||
|
routed "github.com/libp2p/go-libp2p/p2p/host/routed"
|
||||||
|
|
||||||
|
agelib "filippo.io/age"
|
||||||
|
. "github.com/k4lipso/pentapass/internal/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Listen = libp2p.ListenAddrStrings("/ip4/0.0.0.0/tcp/0")
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetupLibp2pHost(ctx context.Context, dbPath string) (host host.Host, dht *dht.IpfsDHT, err error) {
|
||||||
|
data := dbPath
|
||||||
|
keyPath := filepath.Join(data, "key")
|
||||||
|
var priv crypto.PrivKey
|
||||||
|
_, err = os.Stat(keyPath)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
priv, _, err = crypto.GenerateKeyPair(crypto.Ed25519, 1)
|
||||||
|
if err != nil {
|
||||||
|
Logger.Fatal(err)
|
||||||
|
}
|
||||||
|
data, err := crypto.MarshalPrivateKey(priv)
|
||||||
|
if err != nil {
|
||||||
|
Logger.Fatal(err)
|
||||||
|
}
|
||||||
|
err = os.WriteFile(keyPath, data, 0400)
|
||||||
|
if err != nil {
|
||||||
|
Logger.Fatal(err)
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
Logger.Fatal(err)
|
||||||
|
} else {
|
||||||
|
key, err := os.ReadFile(keyPath)
|
||||||
|
if err != nil {
|
||||||
|
Logger.Fatal(err)
|
||||||
|
}
|
||||||
|
priv, err = crypto.UnmarshalPrivateKey(key)
|
||||||
|
if err != nil {
|
||||||
|
Logger.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
host, err = libp2p.New(libp2p.Identity(priv), Listen)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dht = initDHT(ctx, host)
|
||||||
|
host = routed.Wrap(host, dht)
|
||||||
|
|
||||||
|
return host, dht, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Peer struct {
|
||||||
|
Id string `json:"Id"`
|
||||||
|
Key string `json:"Key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type VaultConfig struct {
|
||||||
|
Name string `json:"Name"`
|
||||||
|
Id string `json:"Id"`
|
||||||
|
Peers []Peer `json:"Peers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config []VaultConfig
|
||||||
|
|
||||||
|
|
||||||
|
type WhitelistConnectionGater struct {
|
||||||
|
whitelistedPeers map[peer.ID]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *WhitelistConnectionGater) InterceptPeerDial(p peer.ID) (allowed bool) {
|
||||||
|
//_, allowed = wg.whitelistedPeers[p]
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *WhitelistConnectionGater) InterceptAddrDial(p peer.ID, addr multiaddr.Multiaddr) (bool) {
|
||||||
|
return wg.InterceptPeerDial(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *WhitelistConnectionGater) InterceptAccept(conn network.ConnMultiaddrs) (bool) {
|
||||||
|
addr, err := peer.AddrInfoFromP2pAddr(conn.RemoteMultiaddr())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Debugf("Error InterceptAccept: %s\n", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return wg.InterceptPeerDial(addr.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *WhitelistConnectionGater) InterceptSecured(direction network.Direction, p peer.ID, conn network.ConnMultiaddrs) (allow bool) {
|
||||||
|
return wg.InterceptPeerDial(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *WhitelistConnectionGater) InterceptUpgraded(conn network.Conn) (allow bool, reason control.DisconnectReason) {
|
||||||
|
return wg.InterceptPeerDial(conn.RemotePeer()), 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTrustedPeers(config []VaultConfig) map[string][]Peer {
|
||||||
|
result := make(map[string][]Peer)
|
||||||
|
for _, c := range config {
|
||||||
|
result[c.Id] = c.Peers
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitRootNs() {
|
||||||
|
//TODO: check if "SharedKeyRegistry" key exists, if not create
|
||||||
|
}
|
||||||
|
|
||||||
|
func PeerFromString(str string) (Peer, error) {
|
||||||
|
parts := strings.Split(str, "/")
|
||||||
|
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return Peer{}, fmt.Errorf("Invalid Peer String")
|
||||||
|
}
|
||||||
|
//TODO: validate each part
|
||||||
|
|
||||||
|
return Peer{ Id: parts[0], Key: parts[1] }, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type StorageHandler struct {
|
||||||
|
Ctx context.Context
|
||||||
|
Store *badger.Datastore
|
||||||
|
Host host.Host
|
||||||
|
Ipfs *ipfslite.Peer
|
||||||
|
PubSub *pubsub.PubSub
|
||||||
|
Key *agelib.X25519Identity
|
||||||
|
Config []VaultConfig
|
||||||
|
Vaults map[string]*Vault
|
||||||
|
ConfigPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageHandler) GetSelfPeer() Peer {
|
||||||
|
return Peer {
|
||||||
|
Id: s.Host.ID().String(),
|
||||||
|
Key: s.Key.Recipient().String(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageHandler) UpdateConfig() {
|
||||||
|
Logger.Debug("Updating Config...")
|
||||||
|
s.recreateConfig()
|
||||||
|
s.writeConfig(s.ConfigPath, s.Config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageHandler) recreateConfig() {
|
||||||
|
var newCfg []VaultConfig
|
||||||
|
for key, val := range s.Vaults {
|
||||||
|
newCfg = append(newCfg, VaultConfig{
|
||||||
|
Name: key,
|
||||||
|
Id: val.ID,
|
||||||
|
Peers: val.TrustedPeers,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
s.Config = newCfg
|
||||||
|
//for idx, vaultConfig := range s.Config {
|
||||||
|
// s.Config[idx].Peers = s.Vaults[vaultConfig.Name].TrustedPeers
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageHandler) writeConfig(filename string, config []VaultConfig) error {
|
||||||
|
jsonData, err := json.Marshal(config)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
err = os.WriteFile(filename, jsonData, 0644)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageHandler) NewConfig(filename string) ([]VaultConfig, error) {
|
||||||
|
if _, err := os.Stat(filename); errors.Is(err, os.ErrNotExist) {
|
||||||
|
err := s.writeConfig(filename, []VaultConfig{
|
||||||
|
{
|
||||||
|
Name: "root",
|
||||||
|
Id: uuid.New().String(),
|
||||||
|
Peers: []Peer{
|
||||||
|
{
|
||||||
|
Id: s.Host.ID().String(),
|
||||||
|
Key: s.Key.Recipient().String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not create config file: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := os.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not read config file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []VaultConfig
|
||||||
|
err = json.Unmarshal(content, &result)
|
||||||
|
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not parse config file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageHandler) GetDefaultVault(Name string) *Vault {
|
||||||
|
return s.Vaults["root"]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageHandler) InitVaults() {
|
||||||
|
VaultMap := make(map[string]*Vault)
|
||||||
|
for _, nsCfg := range s.Config {
|
||||||
|
ns1, err := CreateVault(nsCfg.Id, s)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
Logger.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
VaultMap[nsCfg.Name] = ns1
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Vaults = VaultMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsTrustedPeer(ctx context.Context, id peer.ID, vault string, config []VaultConfig) bool {
|
||||||
|
peerMap := GetTrustedPeers(config)
|
||||||
|
|
||||||
|
val, ok := peerMap[vault]
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
for _, v := range val {
|
||||||
|
if v.Id == id.String() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintDBContent(ctx context.Context, store *badger.Datastore) {
|
||||||
|
q := dsq.Query{}
|
||||||
|
result, _ := store.Query(ctx, q)
|
||||||
|
|
||||||
|
entries, _ := result.Rest()
|
||||||
|
for _, entry := range entries {
|
||||||
|
Logger.Infof("Key: %s, Value: %s\n", entry.Key, string(entry.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageHandler) ListVaults() []string {
|
||||||
|
var result []string
|
||||||
|
for k := range s.Vaults {
|
||||||
|
result = append(result, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageHandler) DeleteVault(ID string) error {
|
||||||
|
ns, ok := s.Vaults[ID]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
Logger.Debug("DeleteVault that does not exists")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(s.Vaults, ID)
|
||||||
|
ns.Close()
|
||||||
|
s.UpdateConfig()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageHandler) AddVault(Name string) (*Vault, error) {
|
||||||
|
ns, ok := s.Vaults[Name]
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
return ns, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := CreateVault(uuid.New().String(), s)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result.TrustedPeers = append(result.TrustedPeers, s.GetSelfPeer())
|
||||||
|
s.Vaults[Name] = result
|
||||||
|
s.UpdateConfig()
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func initDHT(ctx context.Context, h host.Host) *dht.IpfsDHT {
|
||||||
|
// Start a DHT, for use in peer discovery. We can't just make a new DHT
|
||||||
|
// client because we want each peer to maintain its own local copy of the
|
||||||
|
// DHT, so that the bootstrapping node of the DHT can go down without
|
||||||
|
// inhibiting future peer discovery.
|
||||||
|
kademliaDHT, err := dht.New(ctx, h)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// if err = kademliaDHT.Bootstrap(ctx); err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
return kademliaDHT
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageHandler) bootstrapPeers(ctx context.Context, h host.Host) {
|
||||||
|
Logger.Info("Bootstrapping DHT")
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for _, peerAddr := range dht.DefaultBootstrapPeers {
|
||||||
|
peerinfo, _ := peer.AddrInfoFromP2pAddr(peerAddr)
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
if err := h.Connect(ctx, *peerinfo); err != nil {
|
||||||
|
Logger.Debugf("Bootstrap warning: %s", err)
|
||||||
|
} else {
|
||||||
|
Logger.Debugf("Connection established with bootstrap node: %q\n", *peerinfo)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageHandler) RunBackground(ctx context.Context, h host.Host, dht *dht.IpfsDHT) {
|
||||||
|
s.discoverPeers(ctx, h, dht)
|
||||||
|
t := utils.NewBackoffTicker(utils.BackoffInitialInterval(2 * time.Minute),
|
||||||
|
utils.BackoffMaxInterval(6 * time.Minute))
|
||||||
|
defer t.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-t.C:
|
||||||
|
// We announce ourselves to the rendezvous point for all the peers.
|
||||||
|
// We have a safeguard of 1 hour to avoid blocking the main loop
|
||||||
|
// in case of network issues.
|
||||||
|
// The TTL of DHT is by default no longer than 3 hours, so we should
|
||||||
|
// be safe by having an entry less than that.
|
||||||
|
safeTimeout, cancel := context.WithTimeout(ctx, time.Hour)
|
||||||
|
|
||||||
|
endChan := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
s.discoverPeers(safeTimeout, h, dht)
|
||||||
|
endChan <- struct{}{}
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-endChan:
|
||||||
|
cancel()
|
||||||
|
case <-safeTimeout.Done():
|
||||||
|
Logger.Error("Timeout while peer discovery")
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageHandler) discoverPeers(ctx context.Context, h host.Host, dht *dht.IpfsDHT) error {
|
||||||
|
s.bootstrapPeers(ctx, h)
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
for vaultName, v := range s.Vaults {
|
||||||
|
Logger.Debugf("Announcing vault \"%s\" with id: %s", vaultName, v.ID)
|
||||||
|
routingDiscovery := discovery.NewRoutingDiscovery(dht)
|
||||||
|
routingDiscovery.Advertise(ctx, v.ID)
|
||||||
|
|
||||||
|
Logger.Debugf("Start peer discovery...")
|
||||||
|
|
||||||
|
timedCtx, cf := context.WithTimeout(ctx, time.Second*120)
|
||||||
|
defer cf()
|
||||||
|
|
||||||
|
peerChan, err := routingDiscovery.FindPeers(timedCtx, v.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for peer := range peerChan {
|
||||||
|
if peer.ID == h.ID() || len(peer.Addrs) == 0 {
|
||||||
|
continue // No self connection
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Debugf("Found peer with id %s", peer.ID.String())
|
||||||
|
if h.Network().Connectedness(peer.ID) == network.Connected {
|
||||||
|
Logger.Debugf("Already connected to %s", peer.ID.String())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutCtx, cancel := context.WithTimeout(ctx, time.Second*120)
|
||||||
|
defer cancel()
|
||||||
|
err := h.Connect(timeoutCtx, peer)
|
||||||
|
if err != nil {
|
||||||
|
Logger.Debugf("Failed connecting to %s, error: %s\n", peer.ID, err)
|
||||||
|
} else {
|
||||||
|
Logger.Debugf("Connected to: %s", peer.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Debug("Peer discovery complete")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func printErr(err error) {
|
||||||
|
Logger.Errorf("error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConnectedPeers(h host.Host) []*peer.AddrInfo {
|
||||||
|
var pinfos []*peer.AddrInfo
|
||||||
|
for _, c := range h.Network().Conns() {
|
||||||
|
pinfos = append(pinfos, &peer.AddrInfo{
|
||||||
|
ID: c.RemotePeer(),
|
||||||
|
Addrs: []multiaddr.Multiaddr{c.RemoteMultiaddr()},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return pinfos
|
||||||
|
}
|
||||||
272
internal/storage/vault.go
Normal file
272
internal/storage/vault.go
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-datastore/query"
|
||||||
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
|
"github.com/libp2p/go-libp2p/core/peer"
|
||||||
|
ds "github.com/ipfs/go-datastore"
|
||||||
|
|
||||||
|
crdt "github.com/ipfs/go-ds-crdt"
|
||||||
|
|
||||||
|
agelib "filippo.io/age"
|
||||||
|
password "github.com/k4lipso/pentapass/internal/crypto"
|
||||||
|
"github.com/k4lipso/pentapass/internal/crypto/age"
|
||||||
|
. "github.com/k4lipso/pentapass/internal/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrNotFound error = errors.New("Not found")
|
||||||
|
|
||||||
|
type Vault struct {
|
||||||
|
ID string
|
||||||
|
Datastore *crdt.Datastore
|
||||||
|
//Registry *sharedKeyRegistry
|
||||||
|
CancelFunc context.CancelFunc
|
||||||
|
ctx context.Context
|
||||||
|
Key *agelib.X25519Identity
|
||||||
|
TrustedPeers []Peer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Vault) AddPeer(peer Peer) {
|
||||||
|
for _, CurrentPeer := range n.TrustedPeers {
|
||||||
|
if CurrentPeer.Id == peer.Id && CurrentPeer.Key == peer.Key {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n.TrustedPeers = append(n.TrustedPeers, peer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Vault) RemovePeer(peer Peer) {
|
||||||
|
var Peers []Peer
|
||||||
|
for _, CurrentPeer := range n.TrustedPeers {
|
||||||
|
if CurrentPeer.Id == peer.Id && CurrentPeer.Key == peer.Key {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
Peers = append(Peers, CurrentPeer)
|
||||||
|
}
|
||||||
|
|
||||||
|
n.TrustedPeers = Peers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Vault) GetRecipients() []string {
|
||||||
|
var result []string
|
||||||
|
|
||||||
|
for _, peer := range n.TrustedPeers {
|
||||||
|
result = append(result, peer.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Vault) Put(k string, v string) error {
|
||||||
|
key := ds.NewKey(k)
|
||||||
|
err := n.Datastore.Put(n.ctx, key, []byte(v))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
printErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Vault) Delete(k string) error {
|
||||||
|
_, err := n.GetPassword(k)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
key := ds.NewKey(k)
|
||||||
|
|
||||||
|
err = n.Datastore.Delete(n.ctx, key)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
printErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Vault) 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 *Vault) Get(k string) (string, error) {
|
||||||
|
v, err := n.Datastore.Get(n.ctx, ds.NewKey(k))
|
||||||
|
if err != nil {
|
||||||
|
printErr(err)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(v), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Vault) 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 *Vault) List() {
|
||||||
|
q := query.Query{}
|
||||||
|
results, err := n.Datastore.Query(n.ctx, q)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
printErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for r := range results.Next() {
|
||||||
|
if r.Error != nil {
|
||||||
|
printErr(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := age.Decrypt(r.Value, n.Key)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
printErr(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Infof("[%s] -> %s\n", r.Key, string(val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Vault) GetAllPasswords() ([]password.Password, error) {
|
||||||
|
q := query.Query{}
|
||||||
|
results, err := n.Datastore.Query(n.ctx, q)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error during GetAllPasswords: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []password.Password
|
||||||
|
|
||||||
|
for r := range results.Next() {
|
||||||
|
if r.Error != nil {
|
||||||
|
printErr(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := age.Decrypt(r.Value, n.Key)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
printErr(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pw, err := password.GetPasswordFromJson(val)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
printErr(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, pw)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Vault) Close() {
|
||||||
|
n.CancelFunc()
|
||||||
|
n.Datastore.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateVault(ID string, storageHandler *StorageHandler) (*Vault, error) {
|
||||||
|
Logger.Infof("Creating Vault %s\n", ID)
|
||||||
|
err := storageHandler.PubSub.RegisterTopicValidator(
|
||||||
|
ID, //== topicName
|
||||||
|
func(ctx context.Context, id peer.ID, msg *pubsub.Message) bool {
|
||||||
|
if id == storageHandler.Host.ID() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Debugf("PubSubmsg TOPIC: %s, PEER: %s\n", ID, id)
|
||||||
|
trusted := IsTrustedPeer(ctx, id, ID, storageHandler.Config)
|
||||||
|
if !trusted {
|
||||||
|
Logger.Debugf("discarded pubsub message from non trusted source %s\n", id)
|
||||||
|
}
|
||||||
|
return trusted
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
Logger.Errorf("error registering topic validator: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
psubCtx, psubCancel := context.WithCancel(storageHandler.Ctx)
|
||||||
|
pubsubBC, err := crdt.NewPubSubBroadcaster(psubCtx, storageHandler.PubSub, ID)
|
||||||
|
if err != nil {
|
||||||
|
Logger.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := crdt.DefaultOptions()
|
||||||
|
//opts.Logger = Logger
|
||||||
|
opts.RebroadcastInterval = 5 * time.Second
|
||||||
|
opts.PutHook = func(k ds.Key, v []byte) {
|
||||||
|
Logger.Infof("Added: [%s]\n", k)
|
||||||
|
}
|
||||||
|
opts.DeleteHook = func(k ds.Key) {
|
||||||
|
Logger.Infof("Removed: [%s]\n", k)
|
||||||
|
}
|
||||||
|
|
||||||
|
crdt, err := crdt.New(storageHandler.Store, ds.NewKey(ID), storageHandler.Ipfs, pubsubBC, opts)
|
||||||
|
if err != nil {
|
||||||
|
Logger.Fatal(err)
|
||||||
|
psubCancel()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
PeerMap := GetTrustedPeers(storageHandler.Config)
|
||||||
|
|
||||||
|
val, ok := PeerMap[ID]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
Logger.Debug("vault config does not contain any peers")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Vault{ID: ID, Datastore: crdt, CancelFunc: psubCancel, ctx: storageHandler.Ctx, Key: storageHandler.Key, TrustedPeers: val}, nil
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.5" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1984 3328"><svg id="d2-svg" class="d2-1224808988" width="1984" height="3328" viewBox="-91 -121 1984 3328"><rect x="-91.000000" y="-121.000000" width="1984.000000" height="3328.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.6" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1984 3328"><svg id="d2-svg" class="d2-1224808988" width="1984" height="3328" viewBox="-91 -121 1984 3328"><rect x="-91.000000" y="-121.000000" width="1984.000000" height="3328.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||||
.d2-1224808988 .text {
|
.d2-1224808988 .text {
|
||||||
font-family: "d2-1224808988-font-regular";
|
font-family: "d2-1224808988-font-regular";
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
@@ -1,502 +0,0 @@
|
|||||||
package storage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"encoding/json"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/ipfs/go-datastore/query"
|
|
||||||
"github.com/libp2p/go-libp2p"
|
|
||||||
dht "github.com/libp2p/go-libp2p-kad-dht"
|
|
||||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
|
||||||
"github.com/libp2p/go-libp2p/core/host"
|
|
||||||
"github.com/libp2p/go-libp2p/core/peer"
|
|
||||||
"github.com/libp2p/go-libp2p/core/control"
|
|
||||||
//"github.com/libp2p/go-libp2p/core/peerstore"
|
|
||||||
drouting "github.com/libp2p/go-libp2p/p2p/discovery/routing"
|
|
||||||
dutil "github.com/libp2p/go-libp2p/p2p/discovery/util"
|
|
||||||
ds "github.com/ipfs/go-datastore"
|
|
||||||
ipfslite "github.com/hsanjuan/ipfs-lite"
|
|
||||||
"github.com/libp2p/go-libp2p/core/network"
|
|
||||||
|
|
||||||
multiaddr "github.com/multiformats/go-multiaddr"
|
|
||||||
|
|
||||||
badger "github.com/ipfs/go-ds-badger2"
|
|
||||||
dsq "github.com/ipfs/go-datastore/query"
|
|
||||||
crdt "github.com/ipfs/go-ds-crdt"
|
|
||||||
crypto "github.com/libp2p/go-libp2p/core/crypto"
|
|
||||||
routed "github.com/libp2p/go-libp2p/p2p/host/routed"
|
|
||||||
logging "github.com/ipfs/go-log/v2"
|
|
||||||
|
|
||||||
agelib "filippo.io/age"
|
|
||||||
password "github.com/k4lipso/pentapass/crypto"
|
|
||||||
"github.com/k4lipso/pentapass/crypto/age"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
topicNameFlag = "afbjlask-23klaj2idalj2-ajl2kjd3i-2ldakjd2"
|
|
||||||
logger = logging.Logger("globaldb")
|
|
||||||
Listen = libp2p.ListenAddrStrings("/ip4/0.0.0.0/tcp/0")
|
|
||||||
)
|
|
||||||
|
|
||||||
func SetupLibp2pHost(ctx context.Context, dbPath string) (host host.Host, dht *dht.IpfsDHT, err error) {
|
|
||||||
data := dbPath
|
|
||||||
keyPath := filepath.Join(data, "key")
|
|
||||||
var priv crypto.PrivKey
|
|
||||||
_, err = os.Stat(keyPath)
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
priv, _, err = crypto.GenerateKeyPair(crypto.Ed25519, 1)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
data, err := crypto.MarshalPrivateKey(priv)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
err = os.WriteFile(keyPath, data, 0400)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
} else if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
} else {
|
|
||||||
key, err := os.ReadFile(keyPath)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
priv, err = crypto.UnmarshalPrivateKey(key)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
//whitelistedPeers := map[peer.ID]struct{} {
|
|
||||||
// "12D3KooWLF7BU5VgpqWdS1XwSTFCLphENozhYQAj6i5LqU8BPZZZ": {},
|
|
||||||
// "12D3KooWBRvtW83QYnPgJCyVyAgMXtg71wjkGefVB2fBnm1A36kS": {},
|
|
||||||
// "12D3KooWMmc4kYy78vSumqWtPkUNAoPeCpJ66ysFv1U8S554B7e2": {},
|
|
||||||
//}
|
|
||||||
|
|
||||||
//connectionGater := &WhitelistConnectionGater{whitelistedPeers: whitelistedPeers}
|
|
||||||
|
|
||||||
//host, err = libp2p.New(libp2p.Identity(priv), libp2p.ConnectionGater(connectionGater), Listen)
|
|
||||||
host, err = libp2p.New(libp2p.Identity(priv), Listen)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
dht = initDHT(ctx, host)
|
|
||||||
host = routed.Wrap(host, dht)
|
|
||||||
|
|
||||||
|
|
||||||
return host, dht, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Peer struct {
|
|
||||||
Id string `json:"Id"`
|
|
||||||
Key string `json:"Key"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type NamespaceConfig struct {
|
|
||||||
Name string `json:"Name"`
|
|
||||||
Id string `json:"Id"`
|
|
||||||
Peers []Peer `json:"Peers"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config []NamespaceConfig
|
|
||||||
|
|
||||||
func NewConfig(filename string) ([]NamespaceConfig, error) {
|
|
||||||
//fmt.Println("NewConfig Path not implemented yet")
|
|
||||||
content, err := os.ReadFile(filename)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Could not read config file: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var result []NamespaceConfig
|
|
||||||
err = json.Unmarshal(content, &result)
|
|
||||||
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Could not parse config file: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type WhitelistConnectionGater struct {
|
|
||||||
whitelistedPeers map[peer.ID]struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wg *WhitelistConnectionGater) InterceptPeerDial(p peer.ID) (allowed bool) {
|
|
||||||
//fmt.Println("PeerDial")
|
|
||||||
//_, allowed = wg.whitelistedPeers[p]
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wg *WhitelistConnectionGater) InterceptAddrDial(p peer.ID, addr multiaddr.Multiaddr) (bool) {
|
|
||||||
//fmt.Println("AddrDial")
|
|
||||||
return wg.InterceptPeerDial(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wg *WhitelistConnectionGater) InterceptAccept(conn network.ConnMultiaddrs) (bool) {
|
|
||||||
//fmt.Println("InterceptAccept")
|
|
||||||
addr, err := peer.AddrInfoFromP2pAddr(conn.RemoteMultiaddr())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error InterceptAccept: %s\n", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return wg.InterceptPeerDial(addr.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wg *WhitelistConnectionGater) InterceptSecured(direction network.Direction, p peer.ID, conn network.ConnMultiaddrs) (allow bool) {
|
|
||||||
//fmt.Println("InterceptSecured")
|
|
||||||
return wg.InterceptPeerDial(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wg *WhitelistConnectionGater) InterceptUpgraded(conn network.Conn) (allow bool, reason control.DisconnectReason) {
|
|
||||||
//fmt.Println("InterceptUpgraded")
|
|
||||||
return wg.InterceptPeerDial(conn.RemotePeer()), 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetTrustedPeers(config []NamespaceConfig) map[string][]Peer {
|
|
||||||
result := make(map[string][]Peer)
|
|
||||||
for _, c := range config {
|
|
||||||
result[c.Id] = c.Peers
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitRootNs() {
|
|
||||||
//TODO: check if "SharedKeyRegistry" key exists, if not create
|
|
||||||
}
|
|
||||||
|
|
||||||
type Namespace struct {
|
|
||||||
ID string
|
|
||||||
Datastore *crdt.Datastore
|
|
||||||
//Registry *sharedKeyRegistry
|
|
||||||
CancelFunc context.CancelFunc
|
|
||||||
ctx context.Context
|
|
||||||
Key *agelib.X25519Identity
|
|
||||||
TrustedPeers []Peer
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (n *Namespace) GetRecipients() []string {
|
|
||||||
var result []string
|
|
||||||
|
|
||||||
for _, peer := range n.TrustedPeers {
|
|
||||||
result = append(result, peer.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Namespace) Put(k string, v string) error {
|
|
||||||
key := ds.NewKey(k)
|
|
||||||
err := n.Datastore.Put(n.ctx, key, []byte(v))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
printErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Namespace) Get(k string) (string, error) {
|
|
||||||
v, err := n.Datastore.Get(n.ctx, ds.NewKey(k))
|
|
||||||
if err != nil {
|
|
||||||
printErr(err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(v), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Namespace) List() {
|
|
||||||
q := query.Query{}
|
|
||||||
results, err := n.Datastore.Query(n.ctx, q)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
printErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for r := range results.Next() {
|
|
||||||
if r.Error != nil {
|
|
||||||
printErr(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
val, err := age.Decrypt(r.Value, n.Key)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
printErr(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("[%s] -> %s\n", r.Key, string(val))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Namespace) GetAllPasswords() ([]password.Password, error) {
|
|
||||||
q := query.Query{}
|
|
||||||
results, err := n.Datastore.Query(n.ctx, q)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error during GetAllPasswords: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var result []password.Password
|
|
||||||
|
|
||||||
for r := range results.Next() {
|
|
||||||
if r.Error != nil {
|
|
||||||
printErr(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
val, err := age.Decrypt(r.Value, n.Key)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
printErr(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
pw, err := password.GetPasswordFromJson(val)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
printErr(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
result = append(result, pw)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Namespace) Close() {
|
|
||||||
n.Datastore.Close()
|
|
||||||
n.CancelFunc()
|
|
||||||
}
|
|
||||||
|
|
||||||
type StorageHandler struct {
|
|
||||||
Ctx context.Context
|
|
||||||
Store *badger.Datastore
|
|
||||||
Host host.Host
|
|
||||||
Ipfs *ipfslite.Peer
|
|
||||||
PubSub *pubsub.PubSub
|
|
||||||
Key *agelib.X25519Identity
|
|
||||||
Config []NamespaceConfig
|
|
||||||
Namespaces map[string]*Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StorageHandler) GetDefaultNamespace(Name string) *Namespace {
|
|
||||||
return s.Namespaces["root"]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StorageHandler) InitNamespaces() {
|
|
||||||
NamespaceMap := make(map[string]*Namespace)
|
|
||||||
for _, nsCfg := range s.Config {
|
|
||||||
ns1, err := CreateNamespace(nsCfg.Id, *s)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
NamespaceMap[nsCfg.Name] = ns1
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Namespaces = NamespaceMap
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsTrustedPeer(ctx context.Context, id peer.ID, namespace string, config []NamespaceConfig) bool {
|
|
||||||
peerMap := GetTrustedPeers(config)
|
|
||||||
|
|
||||||
val, ok := peerMap[namespace]
|
|
||||||
|
|
||||||
if ok {
|
|
||||||
for _, v := range val {
|
|
||||||
if v.Id == id.String() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func PrintDBContent(ctx context.Context, store *badger.Datastore) {
|
|
||||||
q := dsq.Query{}
|
|
||||||
result, _ := store.Query(ctx, q)
|
|
||||||
|
|
||||||
entries, _ := result.Rest()
|
|
||||||
for _, entry := range entries {
|
|
||||||
fmt.Printf("Key: %s, Value: %s\n", entry.Key, string(entry.Value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateNamespace(ID string, storageHandler StorageHandler) (*Namespace, error) {
|
|
||||||
fmt.Printf("Creating Namespace %s\n", ID)
|
|
||||||
err := storageHandler.PubSub.RegisterTopicValidator(
|
|
||||||
ID, //== topicName
|
|
||||||
func(ctx context.Context, _ peer.ID, msg *pubsub.Message) bool {
|
|
||||||
signer := msg.GetFrom()
|
|
||||||
trusted := IsTrustedPeer(ctx, signer, ID, storageHandler.Config)
|
|
||||||
if !trusted {
|
|
||||||
logger.Debug("discarded pubsub message from non trusted source %s ", signer)
|
|
||||||
}
|
|
||||||
return trusted
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("error registering topic validator: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
psubCtx, psubCancel := context.WithCancel(storageHandler.Ctx)
|
|
||||||
pubsubBC, err := crdt.NewPubSubBroadcaster(psubCtx, storageHandler.PubSub, ID)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := crdt.DefaultOptions()
|
|
||||||
opts.Logger = logger
|
|
||||||
opts.RebroadcastInterval = 5 * time.Second
|
|
||||||
opts.PutHook = func(k ds.Key, v []byte) {
|
|
||||||
fmt.Printf("Added: [%s] -> %s\n", k, string(v))
|
|
||||||
|
|
||||||
}
|
|
||||||
opts.DeleteHook = func(k ds.Key) {
|
|
||||||
fmt.Printf("Removed: [%s]\n", k)
|
|
||||||
}
|
|
||||||
|
|
||||||
crdt, err := crdt.New(storageHandler.Store, ds.NewKey(ID), storageHandler.Ipfs, pubsubBC, opts)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
psubCancel()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
PeerMap := GetTrustedPeers(storageHandler.Config)
|
|
||||||
|
|
||||||
val, ok := PeerMap[ID]
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
logger.Fatal("namespace config does not contain any peers")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Namespace{ID: ID, Datastore: crdt, CancelFunc: psubCancel, ctx: storageHandler.Ctx, Key: storageHandler.Key, TrustedPeers: val}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func initDHT(ctx context.Context, h host.Host) *dht.IpfsDHT {
|
|
||||||
// Start a DHT, for use in peer discovery. We can't just make a new DHT
|
|
||||||
// client because we want each peer to maintain its own local copy of the
|
|
||||||
// DHT, so that the bootstrapping node of the DHT can go down without
|
|
||||||
// inhibiting future peer discovery.
|
|
||||||
kademliaDHT, err := dht.New(ctx, h)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if err = kademliaDHT.Bootstrap(ctx); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
for _, peerAddr := range dht.DefaultBootstrapPeers {
|
|
||||||
peerinfo, _ := peer.AddrInfoFromP2pAddr(peerAddr)
|
|
||||||
wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
if err := h.Connect(ctx, *peerinfo); err != nil {
|
|
||||||
fmt.Println("Bootstrap warning:", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
return kademliaDHT
|
|
||||||
}
|
|
||||||
|
|
||||||
func DiscoverPeers(ctx context.Context, h host.Host, dht *dht.IpfsDHT) {
|
|
||||||
//cfg := NewConfig()
|
|
||||||
|
|
||||||
//for _, v := range cfg {
|
|
||||||
// for _, p := range v.Peers {
|
|
||||||
// peerID, err := peer.Decode(p.Id)
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// logger.Fatal(err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// peerInfo, err := dht.FindPeer(ctx, peerID)
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// fmt.Println(err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// h.Peerstore().AddAddrs(peerInfo.ID, peerInfo.Addrs, peerstore.PermanentAddrTTL)
|
|
||||||
|
|
||||||
// err = h.Connect(ctx, peerInfo)
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// fmt.Printf("Failed connecting to %s, error: %s\n", peerInfo.ID, err)
|
|
||||||
// } else {
|
|
||||||
// fmt.Println("Connected to:", peerInfo.ID)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
routingDiscovery := drouting.NewRoutingDiscovery(dht)
|
|
||||||
dutil.Advertise(ctx, routingDiscovery, topicNameFlag)
|
|
||||||
|
|
||||||
// Look for others who have announced and attempt to connect to them
|
|
||||||
anyConnected := false
|
|
||||||
fmt.Printf("Own Id: %s\n", h.ID())
|
|
||||||
for !anyConnected {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
//debug fmt.Println("Searching for peers...")
|
|
||||||
peerChan, err := routingDiscovery.FindPeers(ctx, topicNameFlag)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
for peer := range peerChan {
|
|
||||||
if peer.ID == h.ID() {
|
|
||||||
continue // No self connection
|
|
||||||
}
|
|
||||||
err := h.Connect(ctx, peer)
|
|
||||||
if err != nil {
|
|
||||||
//debug fmt.Printf("Failed connecting to %s, error: %s\n", peer.ID, err)
|
|
||||||
} else {
|
|
||||||
fmt.Println("Connected to:", peer.ID)
|
|
||||||
anyConnected = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println("Peer discovery complete")
|
|
||||||
}
|
|
||||||
|
|
||||||
func printErr(err error) {
|
|
||||||
fmt.Println("error:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ConnectedPeers(h host.Host) []*peer.AddrInfo {
|
|
||||||
var pinfos []*peer.AddrInfo
|
|
||||||
for _, c := range h.Network().Conns() {
|
|
||||||
pinfos = append(pinfos, &peer.AddrInfo{
|
|
||||||
ID: c.RemotePeer(),
|
|
||||||
Addrs: []multiaddr.Multiaddr{c.RemoteMultiaddr()},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return pinfos
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user