├── .github
└── workflows
│ └── tests.yml
├── .gitignore
├── .run
├── test pkg local.run.xml
└── test-pkg-ci.xml
├── LICENSE
├── README.md
├── cmd
├── bumper
│ └── main.go
├── docker
│ ├── doc.go
│ └── release
│ │ ├── builds.go
│ │ ├── main.go
│ │ ├── packaging.go
│ │ └── sources.go
└── indra
│ ├── client
│ └── client.go
│ ├── gui
│ └── gui.go
│ ├── main.go
│ ├── relay
│ └── relay.go
│ ├── root.go
│ ├── seed
│ ├── client
│ │ ├── client.go
│ │ └── unlock.go
│ ├── rpc.go
│ ├── seed.go
│ └── serve.go
│ └── version.go
├── contrib
└── init
│ └── indra.service
├── contributors.md
├── docker
├── build
│ ├── build.Dockerfile
│ ├── package.Dockerfile
│ ├── scripts
│ │ └── package.sh
│ └── targets
│ │ ├── btcd.sh
│ │ ├── btcwallet.sh
│ │ ├── indra.sh
│ │ └── lnd.sh
├── dev.Dockerfile
├── release
│ ├── scripts
│ │ ├── assemble.sh
│ │ ├── extract.sh
│ │ ├── link.sh
│ │ ├── manifest.sh
│ │ ├── push.sh
│ │ └── run.sh
│ └── targets
│ │ ├── btcd
│ │ ├── bin
│ │ │ ├── btcctl
│ │ │ └── btcctl-wallet
│ │ ├── btcctl.Dockerfile
│ │ ├── btcd.Dockerfile
│ │ ├── docker-compose.yml
│ │ └── setup.sh
│ │ ├── btcwallet
│ │ └── btcwallet.Dockerfile
│ │ ├── indra
│ │ └── indra.Dockerfile
│ │ └── lnd
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── bin
│ │ ├── lnsim-btcctl
│ │ ├── lnsim-lncli-alice
│ │ ├── lnsim-lncli-bob
│ │ └── lnsim-lncli-miner
│ │ ├── docker-compose.yml
│ │ ├── lncli.Dockerfile
│ │ ├── lnd.Dockerfile
│ │ └── scripts
│ │ └── setup.sh
├── scratch
│ ├── defaults
│ │ ├── btcd.conf
│ │ └── lnd.conf
│ ├── root-fs.Dockerfile
│ ├── run.sh
│ └── scripts
│ │ └── build.sh
├── sim
│ ├── docker-compose-dev.yml
│ ├── docker-compose.yml
│ └── run.sh
└── sources
│ ├── btcd
│ └── official.Dockerfile
│ ├── btcwallet
│ └── official.Dockerfile
│ ├── indra
│ ├── local.Dockerfile
│ └── official.Dockerfile
│ └── lnd
│ └── official.Dockerfile
├── docs
├── .gitignore
├── 1507.05724v1.pdf
├── 2008-080.pdf
├── 2018-126.pdf
├── DanezisG09.pdf
├── acns11-certificateless.pdf
├── architecture.md
├── formats.md
├── formats.pdf
├── hidden1.png
├── hidden2.png
├── hidden3.png
├── image-20220912120917831.png
├── indra.png
├── indra.svg
├── logo-for-dark-ground.png
├── logo-for-dark-ground.svg
├── logo-for-dark-tshirt.png
├── logo-for-dark-tshirt.svg
├── logo-mono-black.svg
├── logo-mono-white.svg
├── logo.png
├── logo.svg
├── message_format.jpg
├── onions.svg
├── protocols.md
├── readme.md
├── scripts
│ ├── installtoc.sh
│ └── toc.sh
├── session.png
├── torrelaycount.png
├── whitepaper.md
└── whitepaper.pdf
├── go.mod
├── go.sum
├── keys
├── greg.stone.asc
└── херетик.asc
├── localversion.go
├── pkg
├── cert
│ └── ad.go
├── cfg
│ ├── doc.go
│ ├── params.go
│ └── seed_address.go
├── codec
│ ├── ad
│ │ ├── ad.go
│ │ ├── addresses
│ │ │ ├── addresses.go
│ │ │ └── addresses_test.go
│ │ ├── intro
│ │ │ ├── intro.go
│ │ │ └── intro_test.go
│ │ ├── load
│ │ │ ├── load.go
│ │ │ └── load_test.go
│ │ ├── peer
│ │ │ ├── peer.go
│ │ │ └── peer_test.go
│ │ └── services
│ │ │ ├── services.go
│ │ │ └── services_test.go
│ ├── interfaces.go
│ ├── onion
│ │ ├── cores
│ │ │ ├── balance
│ │ │ │ ├── balance.go
│ │ │ │ └── balance_test.go
│ │ │ ├── confirmation
│ │ │ │ ├── confirmation.go
│ │ │ │ └── confirmation_test.go
│ │ │ ├── end
│ │ │ │ └── template.go
│ │ │ └── response
│ │ │ │ ├── response.go
│ │ │ │ └── response_test.go
│ │ ├── crypt
│ │ │ ├── crypt.go
│ │ │ └── crypt_test.go
│ │ ├── delay
│ │ │ ├── delay.go
│ │ │ └── delay_test.go
│ │ ├── exit
│ │ │ ├── exit.go
│ │ │ └── exit_test.go
│ │ ├── forward
│ │ │ ├── forward.go
│ │ │ └── forward_test.go
│ │ ├── getbalance
│ │ │ ├── getbalance.go
│ │ │ └── getbalance_test.go
│ │ ├── hidden
│ │ │ ├── introquery
│ │ │ │ ├── introquery.go
│ │ │ │ └── introquery_test.go
│ │ │ ├── ready
│ │ │ │ └── ready.go
│ │ │ ├── route
│ │ │ │ └── route.go
│ │ │ ├── services
│ │ │ │ ├── hiddenservice.go
│ │ │ │ └── hiddenservice_test.go
│ │ │ └── whisper
│ │ │ │ ├── whisper.go
│ │ │ │ └── whisper_test.go
│ │ ├── reverse
│ │ │ ├── reverse.go
│ │ │ └── reverse_test.go
│ │ └── session
│ │ │ ├── session.go
│ │ │ └── session_test.go
│ ├── ont
│ │ └── interfaces.go
│ └── reg
│ │ └── registry.go
├── crypto
│ ├── ciph
│ │ └── cipher.go
│ ├── cloaked_test.go
│ ├── crypto.go
│ ├── crypto_test.go
│ ├── doc.go
│ ├── libp2p_impls.go
│ ├── nonce
│ │ ├── id.go
│ │ └── nonce.go
│ ├── public_test.go
│ ├── sha256
│ │ ├── sha256.go
│ │ └── sha256_test.go
│ ├── signature_test.go
│ ├── signer_test.go
│ ├── types.go
│ └── util.go
├── docker
│ ├── builder.go
│ ├── config.go
│ └── doc.go
├── engine
│ ├── acct.go
│ ├── ads
│ │ └── ads.go
│ ├── consts
│ │ └── hiddenconst.go
│ ├── dispatcher
│ │ ├── dispatcher.go
│ │ ├── dispatcher_messages.go
│ │ ├── dispatcher_test.go
│ │ └── doc.go
│ ├── doc.go
│ ├── eng_senders.go
│ ├── eng_sessions.go
│ ├── engine.go
│ ├── engine_test.go
│ ├── fail_test.go
│ ├── magic
│ │ └── magic.go
│ ├── mock.go
│ ├── mockengine.go
│ ├── node
│ │ └── node.go
│ ├── onion_skins.go
│ ├── packet
│ │ ├── doc.go
│ │ ├── packet.go
│ │ ├── packet_test.go
│ │ ├── segcalc.go
│ │ ├── segcalc_test.go
│ │ ├── segment.go
│ │ └── segment_test.go
│ ├── payments
│ │ └── payments.go
│ ├── peerstore.go
│ ├── peerstore_test.go
│ ├── protocols
│ │ └── protocols.go
│ ├── reply.go
│ ├── responses
│ │ └── responses.go
│ ├── sendgetbalance_test.go
│ ├── services
│ │ └── services.go
│ ├── sess
│ │ ├── data.go
│ │ ├── doc.go
│ │ ├── select.go
│ │ ├── send.go
│ │ └── sessionmanager.go
│ ├── sessions
│ │ └── sessions.go
│ ├── tpt
│ │ └── interfaces.go
│ └── transport
│ │ ├── common.go
│ │ ├── conn.go
│ │ ├── discovery.go
│ │ ├── doc.go
│ │ ├── listener.go
│ │ ├── listener_test.go
│ │ ├── pstoreds
│ │ ├── addr_book.go
│ │ ├── addr_book_gc.go
│ │ ├── addr_book_gc_test.go
│ │ ├── cache.go
│ │ ├── cyclic_batch.go
│ │ ├── ds_test.go
│ │ ├── keybook.go
│ │ ├── metadata.go
│ │ ├── pb
│ │ │ ├── pstore.pb.go
│ │ │ └── pstore.proto
│ │ ├── peerstore.go
│ │ └── protobook.go
│ │ ├── pstoremem
│ │ ├── addr_book.go
│ │ ├── inmem_test.go
│ │ ├── keybook.go
│ │ ├── metadata.go
│ │ ├── peerstore.go
│ │ ├── protobook.go
│ │ ├── sorting.go
│ │ └── sorting_test.go
│ │ ├── readme.md
│ │ └── tpt_sim.go
├── headers
│ └── headers.go
├── hidden
│ └── hidden.go
├── interrupt
│ ├── LICENSE
│ ├── README.md
│ ├── doc.go
│ ├── interrupt.go
│ └── sigterm.go
├── node
│ └── protocol.go
├── p2p
│ ├── config.go
│ ├── configure.go
│ ├── doc.go
│ ├── flags.go
│ ├── log.go
│ ├── metrics
│ │ └── host.go
│ ├── service.go
│ ├── signals.go
│ ├── util.go
│ └── util_test.go
├── proc
│ ├── app
│ │ ├── app.go
│ │ └── app_test.go
│ ├── cmds
│ │ ├── args.go
│ │ ├── args_test.go
│ │ ├── commands.go
│ │ ├── commands_test.go
│ │ ├── env.go
│ │ ├── example.go
│ │ ├── help.go
│ │ └── marshal.go
│ ├── log
│ │ ├── length.go
│ │ ├── log.go
│ │ ├── log_test.go
│ │ └── maxlen
│ │ │ └── maxlen.go
│ └── opts
│ │ ├── config
│ │ └── interface.go
│ │ ├── duration
│ │ └── spec.go
│ │ ├── float
│ │ └── spec.go
│ │ ├── integer
│ │ └── spec.go
│ │ ├── list
│ │ └── spec.go
│ │ ├── meta
│ │ └── metadata.go
│ │ ├── normalize
│ │ ├── addresses.go
│ │ └── paths.go
│ │ ├── text
│ │ └── spec.go
│ │ └── toggle
│ │ └── spec.go
├── rpc
│ ├── auth.go
│ ├── client.go
│ ├── device.go
│ ├── dialer.go
│ ├── dialer_options.go
│ ├── doc.go
│ ├── endpoint.go
│ ├── examples
│ │ ├── log.go
│ │ ├── tunnel_hello.go
│ │ ├── unix_hello.go
│ │ └── unix_unlock.go
│ ├── flags.go
│ ├── keys.go
│ ├── log.go
│ ├── server.go
│ ├── server_options.go
│ ├── signals.go
│ ├── socket_unix.go
│ ├── store.go
│ ├── tunnel.go
│ ├── tunnel_config.go
│ └── util.go
├── seed
│ ├── log.go
│ ├── server.go
│ └── signals.go
├── splicer
│ ├── i32
│ │ ├── int32.go
│ │ └── int32_test.go
│ ├── magic
│ │ ├── magic.go
│ │ └── magic_test.go
│ ├── readme.md
│ ├── splicer.go
│ ├── splicer_test.go
│ └── t64
│ │ ├── time.go
│ │ └── time_test.go
├── storage
│ ├── configure.go
│ ├── doc.go
│ ├── flags.go
│ ├── key.go
│ ├── log.go
│ ├── service.go
│ ├── service_unlock.go
│ ├── signals.go
│ ├── unlock.go
│ ├── unlock.pb.go
│ ├── unlock.proto
│ └── unlock_grpc.pb.go
└── util
│ ├── appdata
│ ├── appdata.go
│ └── appdata_test.go
│ ├── b32
│ ├── based32
│ │ ├── based32.go
│ │ └── based32_test.go
│ ├── codec
│ │ └── types.go
│ ├── codecer
│ │ └── interface.go
│ └── constant.go
│ ├── ci
│ └── trace.go
│ ├── cryptorand
│ └── cryptorand.go
│ ├── file
│ └── file.go
│ ├── math
│ └── math.go
│ ├── multi
│ └── multiaddr.go
│ ├── multikey
│ └── multikey.go
│ ├── norm
│ └── norm.go
│ ├── options
│ └── default.go
│ ├── path
│ └── path.go
│ ├── qu
│ └── quit.go
│ ├── slice
│ ├── interfaces_test.go
│ ├── slice.go
│ └── slice_test.go
│ ├── splice
│ └── splice.go
│ ├── tests
│ └── testutils.go
│ └── windows
│ └── windows.go
├── release
└── .gitignore
├── scripts
├── cdwork.sh
├── readme.md
├── run.sh
├── runci.sh
├── test.sh
├── testci.sh
├── testpkg.sh
└── trace.sh
└── version.go
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a golang project
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
3 |
4 | name: Test All in pkg
5 |
6 | on:
7 | push:
8 | branches: [ "master" ]
9 | pull_request:
10 | branches: [ "master" ]
11 |
12 | jobs:
13 |
14 | build:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v3
18 |
19 | - name: Set up Go
20 | uses: actions/setup-go@v3
21 | with:
22 | go-version: 1.19
23 |
24 | - name: Test
25 | run: go test -v ./pkg/...
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | # Dependency directories (remove the comment below to include it)
15 | vendor/
16 | /.idea/vcs.xml
17 | /.idea/modules.xml
18 | /.idea/indranet.iml
19 | /.idea/.gitignore
20 | /.idea/indra.iml
21 | /.idea/codeStyles/codeStyleConfig.xml
22 | /.idea/**
23 |
--------------------------------------------------------------------------------
/.run/test pkg local.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.run/test-pkg-ci.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/cmd/docker/doc.go:
--------------------------------------------------------------------------------
1 | // Package docker contains tools for Docker deployments of Indra and components.
2 | package docker
3 |
--------------------------------------------------------------------------------
/cmd/indra/client/client.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "github.com/spf13/cobra"
5 | )
6 |
7 | func Init(c *cobra.Command) {
8 | c.AddCommand(clientCommand)
9 | }
10 |
11 | var clientCommand = &cobra.Command{
12 | Use: "client",
13 | Short: "run a client",
14 | Long: "Runs indra as a client, providing a wireguard tunnel and socks5 " +
15 | "proxy as connectivity options",
16 | Run: func(cmd *cobra.Command, args []string) {
17 |
18 | },
19 | }
20 |
--------------------------------------------------------------------------------
/cmd/indra/gui/gui.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "github.com/spf13/cobra"
5 | )
6 |
7 | func Init(c *cobra.Command) {
8 | c.AddCommand(clientCommand)
9 | }
10 |
11 | var clientCommand = &cobra.Command{
12 | Use: "client",
13 | Short: "run a client",
14 | Long: "Runs indra as a client, providing a wireguard tunnel and socks5 " +
15 | "proxy as connectivity options",
16 | Run: func(cmd *cobra.Command, args []string) {
17 |
18 | },
19 | }
20 |
--------------------------------------------------------------------------------
/cmd/indra/main.go:
--------------------------------------------------------------------------------
1 | // Indra is a low latency, source routed mixnet distributed virtual private network protocol.
2 | //
3 | // This application includes a client, client GUI, relay and seed node according to the subcommand invocation.
4 | package main
5 |
6 | import (
7 | "os"
8 |
9 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
10 | )
11 |
12 | var (
13 | log = log2.GetLogger()
14 | check = log.E.Chk
15 | )
16 |
17 | func init() {
18 | log2.App.Store("indra")
19 | }
20 |
21 | func main() {
22 |
23 | var err error
24 |
25 | if err = rootCmd.Execute(); check(err) {
26 | os.Exit(1)
27 | }
28 |
29 | os.Exit(0)
30 | }
31 |
--------------------------------------------------------------------------------
/cmd/indra/relay/relay.go:
--------------------------------------------------------------------------------
1 | package relay
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind"
5 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
6 | "github.com/spf13/cobra"
7 | "github.com/spf13/viper"
8 | )
9 |
10 | var (
11 | log = log2.GetLogger()
12 | check = log.E.Chk
13 | )
14 |
15 | var (
16 | wireguardEnable bool
17 | wireguardCIDR string // todo: there must be something like this. default route to 1
18 | socksEnable bool
19 | socksListener string
20 | )
21 |
22 | func Init(c *cobra.Command) {
23 | relayCommand.PersistentFlags().BoolVarP(&wireguardEnable, "wireguard",
24 | "w", false, "enable wireguard tunnel")
25 | relayCommand.PersistentFlags().BoolVarP(&socksEnable, "socks",
26 | "s", false, "enable socks proxy")
27 | relayCommand.PersistentFlags().StringVarP(&socksListener, "socks-listener",
28 | "l", "localhost:8080", "set address for socks 5 proxy listener")
29 |
30 | viper.BindPFlag("wireguard", relayCommand.PersistentFlags().Lookup("wireguard"))
31 | viper.BindPFlag("socks", relayCommand.PersistentFlags().Lookup("socks"))
32 | viper.BindPFlag("socks-listener", relayCommand.PersistentFlags().Lookup("socks-listener"))
33 |
34 | c.AddCommand(relayCommand)
35 | }
36 |
37 | var relayCommand = &cobra.Command{
38 | Use: "relay",
39 | Short: "run a relay",
40 | Long: "Runs indra as a full relay, with optional client.",
41 |
42 | Run: func(cmd *cobra.Command, args []string) {
43 | log.I.Ln(log2.App.Load(), indra.SemVer)
44 | nw, _ := cmd.Parent().PersistentFlags().GetString("network")
45 | var dd string
46 | dd, _ = cmd.Parent().PersistentFlags().GetString("data-dir")
47 | log.T.S("cmd", dd, nw, args)
48 | },
49 | }
50 |
--------------------------------------------------------------------------------
/cmd/indra/seed/client/client.go:
--------------------------------------------------------------------------------
1 | // Package client is a client for the seed RPC service for remote unlock and management.
2 | package client
3 |
4 | import (
5 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
6 | "github.com/spf13/cobra"
7 | )
8 |
9 | var (
10 | log = log2.GetLogger()
11 | check = log.E.Chk
12 | )
13 |
14 | func init() {
15 | initUnlock(unlockRPCCmd)
16 | }
17 |
18 | func Init(c *cobra.Command) {
19 | c.AddCommand(unlockRPCCmd)
20 | }
21 |
--------------------------------------------------------------------------------
/cmd/indra/seed/client/unlock.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "context"
5 | "os"
6 |
7 | "github.com/spf13/cobra"
8 | "github.com/spf13/viper"
9 | "google.golang.org/grpc"
10 |
11 | "git.indra-labs.org/dev/ind/pkg/rpc"
12 | "git.indra-labs.org/dev/ind/pkg/storage"
13 | )
14 |
15 | var (
16 | unlockTargetFlag = "target"
17 | unlockPassFileFlag = "keyfile"
18 | )
19 |
20 | var (
21 | unlockTarget string
22 | unlockPassFilePath string
23 | )
24 |
25 | func initUnlock(cmd *cobra.Command) {
26 |
27 | cmd.Flags().StringVarP(&unlockTarget, unlockTargetFlag, "",
28 | "unix:///tmp/indra.sock",
29 | "the url of the rpc server",
30 | )
31 |
32 | viper.BindPFlag(unlockTargetFlag, cmd.Flags().Lookup(unlockTargetFlag))
33 |
34 | cmd.Flags().StringVarP(&unlockPassFilePath, unlockPassFileFlag, "",
35 | "",
36 | "",
37 | )
38 |
39 | viper.BindPFlag(unlockPassFileFlag, cmd.Flags().Lookup(unlockPassFileFlag))
40 | }
41 |
42 | var unlockRPCCmd = &cobra.Command{
43 | Use: "unlock",
44 | Short: "unlocks the encrypted storage",
45 | Long: `unlocks the encrypted storage.`,
46 | Run: func(cmd *cobra.Command, args []string) {
47 |
48 | var err error
49 | var conn *grpc.ClientConn
50 |
51 | conn, err = rpc.Dial(viper.GetString(unlockTargetFlag))
52 |
53 | if err != nil {
54 | check(err)
55 | os.Exit(1)
56 | }
57 |
58 | var keyFileBytes []byte
59 |
60 | if keyFileBytes, err = os.ReadFile(viper.GetString(unlockPassFileFlag)); check(err) {
61 | os.Exit(0)
62 | }
63 |
64 | // var password []byte
65 | //
66 | // fmt.Print("Enter Encryption HiddenService: ")
67 | // password, err = term.ReadPassword(int(syscall.Stdin))
68 | // fmt.Println()
69 |
70 | u := storage.NewUnlockServiceClient(conn)
71 |
72 | _, err = u.Unlock(context.Background(), &storage.UnlockRequest{
73 | Key: string(string(keyFileBytes)),
74 | })
75 |
76 | if err != nil {
77 | check(err)
78 | return
79 | }
80 |
81 | log.I.Ln("successfully unlocked")
82 | },
83 | }
84 |
--------------------------------------------------------------------------------
/cmd/indra/seed/rpc.go:
--------------------------------------------------------------------------------
1 | package seed
2 |
3 | import "github.com/spf13/cobra"
4 |
5 | var rpcCmd = &cobra.Command{
6 | Use: "rpc",
7 | Short: "A list of commands for interacting with a seed",
8 | Long: `A list of commands for interacting with a seed.`,
9 | }
10 |
--------------------------------------------------------------------------------
/cmd/indra/seed/seed.go:
--------------------------------------------------------------------------------
1 | // Package seed is a non-relay node that simply accepts and propagates peer advertisment gossip to clients and relays on the network.
2 | package seed
3 |
4 | import (
5 | "git.indra-labs.org/dev/ind/cmd/indra/seed/client"
6 | "git.indra-labs.org/dev/ind/pkg/p2p"
7 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
8 | "git.indra-labs.org/dev/ind/pkg/rpc"
9 | "git.indra-labs.org/dev/ind/pkg/storage"
10 | "github.com/spf13/cobra"
11 | )
12 |
13 | var (
14 | log = log2.GetLogger()
15 | check = log.E.Chk
16 | )
17 |
18 | func init() {
19 | storage.InitFlags(serveCmd)
20 | p2p.InitFlags(serveCmd)
21 | rpc.InitFlags(serveCmd)
22 | }
23 |
24 | func Init(c *cobra.Command) {
25 | client.Init(rpcCmd)
26 |
27 | seedCommand.AddCommand(rpcCmd)
28 | seedCommand.AddCommand(serveCmd)
29 |
30 | c.AddCommand(seedCommand)
31 | }
32 |
33 | var seedCommand = &cobra.Command{
34 | Use: "seed",
35 | Short: "run and manage your seed node",
36 | Long: `run and manage your seed node`,
37 | }
38 |
--------------------------------------------------------------------------------
/cmd/indra/seed/serve.go:
--------------------------------------------------------------------------------
1 | package seed
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/spf13/cobra"
7 | "github.com/spf13/viper"
8 |
9 | "git.indra-labs.org/dev/ind"
10 | "git.indra-labs.org/dev/ind/pkg/cfg"
11 | "git.indra-labs.org/dev/ind/pkg/interrupt"
12 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
13 | "git.indra-labs.org/dev/ind/pkg/seed"
14 | )
15 |
16 | var serveCmd = &cobra.Command{
17 | Use: "serve",
18 | Short: "Serves an instance of the seed node",
19 | Long: `Serves an instance of the seed node.`,
20 | Run: func(cmd *cobra.Command, args []string) {
21 |
22 | log.I.Ln("-- ", log2.App.Load(), "("+viper.GetString("network")+") -", indra.SemVer, "- Network Freedom. --")
23 |
24 | cfg.SelectNetworkParams(viper.GetString("network"))
25 |
26 | ctx, cancel := context.WithCancel(context.Background())
27 | interrupt.AddHandler(cancel)
28 |
29 | // Seed //
30 |
31 | go seed.Run(ctx)
32 |
33 | select {
34 | case <-seed.WhenStartFailed():
35 | log.I.Ln("stopped")
36 | case <-seed.WhenShutdown():
37 | log.I.Ln("shutdown complete")
38 | }
39 |
40 | log.I.Ln("-- fin --")
41 | },
42 | }
43 |
--------------------------------------------------------------------------------
/cmd/indra/version.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "git.indra-labs.org/dev/ind"
6 |
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func init() {
11 | rootCmd.AddCommand(versionCmd)
12 | }
13 |
14 | var versionCmd = &cobra.Command{
15 | Use: "version",
16 | Short: "Prints the version number",
17 | Long: `All software has versions. This is mine. Semver formatted.`,
18 | Run: func(cmd *cobra.Command, args []string) {
19 | fmt.Println(indra.SemVer)
20 | },
21 | }
22 |
--------------------------------------------------------------------------------
/contrib/init/indra.service:
--------------------------------------------------------------------------------
1 | # A sample systemd service file for ind running with a lnd service.
2 |
3 | [Unit]
4 | Description=Indra Network Daemon
5 |
6 | # Make sure ind starts after lnd is ready
7 | # Requires=lnd.service
8 | # After=lnd.service
9 |
10 | [Service]
11 | ExecStart=/usr/local/bin/ind
12 | ExecStop=/usr/local/bin/indcli stop
13 |
14 | # Replace these with the user:group that will run lnd
15 | User=indra
16 | Group=indra
17 |
18 | # Try restarting lnd if it stops due to a failure
19 | Restart=on-failure
20 | RestartSec=60
21 |
22 | # Type=notify is required for lnd to notify systemd when it is ready
23 | Type=notify
24 |
25 | # An extended timeout period is needed to allow for time intensive operations during startup. We also extend the
26 | # stop timeout to ensure graceful shutdowns.
27 | TimeoutStartSec=10
28 | TimeoutStopSec=30
29 |
30 | # Hardening Measures
31 | ####################
32 |
33 | # Mount /usr, /boot/ and /etc read-only for the process.
34 | ProtectSystem=full
35 |
36 | # Disallow the process and all of its children to gain
37 | # new privileges through execute().
38 | NoNewPrivileges=true
39 |
40 | # Use a new /dev namespace only populated with API pseudo devices
41 | # such as /dev/null, /dev/zero and /dev/random.
42 | PrivateDevices=true
43 |
44 | # Deny the creation of writable and executable memory mappings.
45 | MemoryDenyWriteExecute=true
46 |
47 | [Install]
48 | WantedBy=multi-user.target
--------------------------------------------------------------------------------
/docker/build/build.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | # ---
3 | # Build Process
4 | # ---
5 |
6 | ARG source_image="indralabs/indra-source"
7 | ARG source_version="dev"
8 |
9 | ARG builder_image="golang:1.19.4"
10 |
11 | FROM ${source_image}:${source_version} as source
12 |
13 | FROM ${builder_image} as build
14 |
15 | ARG source_version="dev"
16 |
17 | ARG target_name="indra"
18 | ARG target_build_script="docker/indra/build/build.sh"
19 |
20 | COPY --from=source /source /tmp/source
21 | COPY --from=source /source.tar.gz /tmp/source.tar.gz
22 |
23 | WORKDIR /tmp/source
24 |
25 | RUN set -ex echo "making directories for release and binaries" \
26 | && mkdir -pv /tmp/${target_name}-${source_version}/release \
27 | && mkdir -pv /tmp/${target_name}-${source_version}/bin
28 |
29 | RUN set -ex echo "migrating source files to release" \
30 | && cp /tmp/source.tar.gz /tmp/${target_name}-${source_version}/release/${target_name}-source-${source_version}.tar.gz
31 |
32 | ADD ${target_build_script} ./build.sh
33 |
34 | RUN set -ex echo "running build" && ./build.sh
35 |
36 | FROM scratch
37 |
38 | ARG target_name="indra"
39 | ARG source_version="dev"
40 |
41 | COPY --from=build /tmp/${target_name}-${source_version} /${target_name}-${source_version}
42 |
--------------------------------------------------------------------------------
/docker/build/package.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | # ---
3 | # Packaging Process
4 | # ---
5 |
6 | ARG binaries_image="indralabs/indra-build"
7 | ARG binaries_version="dev"
8 |
9 | ARG packaging_image="golang:1.19.4"
10 |
11 | FROM ${binaries_image}:${binaries_version} as build
12 |
13 | FROM ${packaging_image} as packager
14 |
15 | ARG binaries_version="dev"
16 |
17 | ARG target_name="indra"
18 | ARG target_packaging_script="docker/indra/build/package.sh"
19 |
20 | COPY --from=build /${target_name}-${binaries_version} /tmp/${target_name}-${binaries_version}
21 |
22 | WORKDIR /tmp/${target_name}-${binaries_version}
23 |
24 | ADD docker/build/scripts/package.sh /tmp/package.sh
25 |
26 | RUN set -ex echo "running packaging" \
27 | && /tmp/package.sh
28 |
29 | WORKDIR /tmp/${target_name}-${binaries_version}/release
30 |
31 | RUN set -ex echo "generating shasum for release" \
32 | && shasum -a 256 * > manifest-${binaries_version}.txt
33 |
34 | RUN set -ex echo "generating tar archive for the whole release" \
35 | && tar -czvf /tmp/${target_name}-${binaries_version}.tar.gz -C /tmp/${target_name}-${binaries_version} .
36 |
37 | FROM busybox
38 |
39 | ARG target_name="indra"
40 | ARG binaries_version="dev"
41 |
42 | COPY --from=packager /tmp/${target_name}-${binaries_version} /tmp/${target_name}-${binaries_version}
43 | COPY --from=packager /tmp/${target_name}-${binaries_version}.tar.gz /tmp/${target_name}-${binaries_version}.tar.gz
44 |
--------------------------------------------------------------------------------
/docker/build/scripts/package.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PLATFORMS=$(find ./bin -type d | grep -oP "(^.*bin/\K).*")
4 |
5 | # PACKAGE LOOP
6 | for PLATFORM in $PLATFORMS; do
7 |
8 | echo "running packaging for $PLATFORM to release/${target_name}-$PLATFORM-${binaries_version}.tar.gz"
9 |
10 | tar -czvf ./release/${target_name}-$PLATFORM-${binaries_version}.tar.gz -C ./bin/$PLATFORM/. .
11 |
12 | done
13 |
--------------------------------------------------------------------------------
/docker/build/targets/btcd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | NAME="btcd"
4 |
5 | PLATFORMS=(
6 | "linux/386"
7 | "linux/amd64"
8 | "linux/arm/v5"
9 | "linux/arm/v6"
10 | "linux/arm/v7"
11 | "linux/arm64"
12 | # "linux/loong64"
13 | "linux/mips"
14 | "linux/mips64"
15 | "linux/mips64le"
16 | "linux/mipsle"
17 | "linux/ppc64"
18 | "linux/ppc64le"
19 | # "linux/riscv64"
20 | "linux/s390x"
21 | )
22 |
23 | #PLATFORMS=(
24 | # "linux/amd64"
25 | # "linux/arm64"
26 | # "linux/arm/v7"
27 | #)
28 |
29 |
30 | # C bad
31 | export CGO_ENABLED=0
32 |
33 | # BUIDL LOOP
34 | for i in "${PLATFORMS[@]}"; do
35 |
36 | OS=$(echo $i | cut -f1 -d/)
37 | ARCH=$(echo $i | cut -f2 -d/)
38 | ARM=$(echo $i | cut -f3 -d/)
39 |
40 | ARM_VARIANT=""
41 |
42 | if [ "$ARM" != "" ]; then
43 | ARM_VARIANT="-${ARM}"
44 | fi
45 |
46 | echo "running build for $OS-$ARCH$ARM_VARIANT"
47 |
48 | GOOS=$OS GOARCH=$ARCH GOARM=$(echo $ARM | cut -f1 -dv) go build --ldflags '-w -s' \
49 | -o /tmp/$NAME-${source_version}/bin/$OS-$ARCH$ARM_VARIANT/btcd .
50 | GOOS=$OS GOARCH=$ARCH GOARM=$(echo $ARM | cut -f1 -dv) go build --ldflags '-w -s' \
51 | -o /tmp/$NAME-${source_version}/bin/$OS-$ARCH$ARM_VARIANT/btcctl ./cmd/btcctl/.
52 | GOOS=$OS GOARCH=$ARCH GOARM=$(echo $ARM | cut -f1 -dv) go build --ldflags '-w -s' \
53 | -o /tmp/$NAME-${source_version}/bin/$OS-$ARCH$ARM_VARIANT/gencerts ./cmd/gencerts/.
54 |
55 | done
56 |
--------------------------------------------------------------------------------
/docker/build/targets/btcwallet.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | NAME="btcwallet"
4 |
5 | PLATFORMS=(
6 | "linux/386"
7 | "linux/amd64"
8 | "linux/arm/v5"
9 | "linux/arm/v6"
10 | "linux/arm/v7"
11 | "linux/arm64"
12 | # "linux/loong64"
13 | "linux/mips"
14 | "linux/mips64"
15 | "linux/mips64le"
16 | "linux/mipsle"
17 | "linux/ppc64"
18 | "linux/ppc64le"
19 | # "linux/riscv64"
20 | "linux/s390x"
21 | )
22 |
23 | #PLATFORMS=(
24 | # "linux/amd64"
25 | # "linux/arm64"
26 | # "linux/arm/v7"
27 | #)
28 |
29 |
30 | # C bad
31 | export CGO_ENABLED=0
32 |
33 | # BUIDL LOOP
34 | for i in "${PLATFORMS[@]}"; do
35 |
36 | OS=$(echo $i | cut -f1 -d/)
37 | ARCH=$(echo $i | cut -f2 -d/)
38 | ARM=$(echo $i | cut -f3 -d/)
39 |
40 | ARM_VARIANT=""
41 |
42 | if [ "$ARM" != "" ]; then
43 | ARM_VARIANT="-${ARM}"
44 | fi
45 |
46 | echo "running build for $OS-$ARCH$ARM_VARIANT"
47 |
48 | GOOS=$OS GOARCH=$ARCH GOARM=$(echo $ARM | cut -f1 -dv) go build --ldflags '-w -s' \
49 | -o /tmp/$NAME-${source_version}/bin/$OS-$ARCH$ARM_VARIANT/btcwallet .
50 |
51 | done
52 |
--------------------------------------------------------------------------------
/docker/build/targets/indra.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | NAME="indra"
4 |
5 | #PLATFORMS=(
6 | # "linux/386"
7 | # "linux/amd64"
8 | # "linux/arm/v5"
9 | # "linux/arm/v6"
10 | # "linux/arm/v7"
11 | # "linux/arm64"
12 | ## "linux/loong64"
13 | # "linux/mips"
14 | # "linux/mips64"
15 | # "linux/mips64le"
16 | # "linux/mipsle"
17 | # "linux/ppc64"
18 | # "linux/ppc64le"
19 | ## "linux/riscv64"
20 | # "linux/s390x"
21 | #)
22 |
23 | PLATFORMS=(
24 | "linux/amd64"
25 | "linux/arm64"
26 | "linux/arm/v7"
27 | )
28 |
29 | # C bad
30 | export CGO_ENABLED=0
31 |
32 | # BUIDL LOOP
33 | for i in "${PLATFORMS[@]}"; do
34 |
35 | OS=$(echo $i | cut -f1 -d/)
36 | ARCH=$(echo $i | cut -f2 -d/)
37 | ARM=$(echo $i | cut -f3 -d/)
38 |
39 | ARM_VARIANT=""
40 |
41 | if [ "$ARM" != "" ]; then
42 | ARM_VARIANT="-${ARM}"
43 | fi
44 |
45 | echo "running build for $OS-$ARCH$ARM_VARIANT"
46 |
47 | GOOS=$OS GOARCH=$ARCH GOARM=$(echo $ARM | cut -f1 -dv) go build --ldflags '-w -s' \
48 | -o /tmp/$NAME-${source_version}/bin/$OS-$ARCH$ARM_VARIANT/indra ./cmd/indra/.
49 |
50 | done
51 |
--------------------------------------------------------------------------------
/docker/build/targets/lnd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | NAME="lnd"
4 |
5 | #PLATFORMS=(
6 | # "linux/386"
7 | # "linux/amd64"
8 | # "linux/arm/v5"
9 | # "linux/arm/v6"
10 | # "linux/arm/v7"
11 | # "linux/arm64"
12 | ## "linux/loong64"
13 | # "linux/mips"
14 | # "linux/mips64"
15 | # "linux/mips64le"
16 | # "linux/mipsle"
17 | # "linux/ppc64"
18 | # "linux/ppc64le"
19 | ## "linux/riscv64"
20 | # "linux/s390x"
21 | #)
22 |
23 | PLATFORMS=(
24 | "linux/amd64"
25 | "linux/arm64"
26 | "linux/arm/v7"
27 | )
28 |
29 | # C bad
30 | export CGO_ENABLED=0
31 |
32 | # BUIDL LOOP
33 | for i in "${PLATFORMS[@]}"; do
34 |
35 | OS=$(echo $i | cut -f1 -d/)
36 | ARCH=$(echo $i | cut -f2 -d/)
37 | ARM=$(echo $i | cut -f3 -d/)
38 |
39 | ARM_VARIANT=""
40 |
41 | if [ "$ARM" != "" ]; then
42 | ARM_VARIANT="-${ARM}"
43 | fi
44 |
45 | echo "running build for $OS-$ARCH$ARM_VARIANT"
46 |
47 | GOOS=$OS GOARCH=$ARCH GOARM=$(echo $ARM | cut -f1 -dv) go build -tags="signrpc walletrpc chainrpc invoicesrpc" --ldflags '-w -s' \
48 | -o /tmp/$NAME-${source_version}/bin/$OS-$ARCH$ARM_VARIANT/lnd ./cmd/lnd/.
49 | GOOS=$OS GOARCH=$ARCH GOARM=$(echo $ARM | cut -f1 -dv) go build -tags="signrpc walletrpc chainrpc invoicesrpc" --ldflags '-w -s' \
50 | -o /tmp/$NAME-${source_version}/bin/$OS-$ARCH$ARM_VARIANT/lncli ./cmd/lncli/.
51 |
52 | done
53 |
--------------------------------------------------------------------------------
/docker/dev.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | FROM golang:1.19.4
3 |
4 | # Source/Target release defaults
5 | ARG ARCH=amd64
6 | ARG GOARCH=amd64
7 | ENV GO111MODULE=on GOOS=linux
8 |
9 | RUN set -ex \
10 | && apt update && apt install net-tools
11 |
12 | WORKDIR /indra
13 |
14 | # ENV defaults
15 | # ENV IND_LOGFILEPATH=""
16 |
17 | # Set the data volume
18 | # VOLUME ["/var/indra"]
19 |
20 | # :8337 indra peer-to-peer port
21 | # :8338 indra RPC port
22 | EXPOSE 8337 8338
23 |
24 | ENTRYPOINT ["/indra/docker/sim/run.sh"]
25 |
--------------------------------------------------------------------------------
/docker/release/scripts/assemble.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ -z "${TARGET_NAME}" ]; then
4 | echo "-- error: a release name is required to run the assembler"
5 | exit 1
6 | fi
7 |
8 | if [ -z "${TARGET_TAG}" ]; then
9 | echo "-- error: a release tag is required to run an extract"
10 | exit 1
11 | fi
12 |
13 | DOCKERFILES=$(find ./docker/release/targets/$TARGET_NAME -maxdepth 1 -type f -iname "*.Dockerfile" | grep -oP "(.$TARGET_NAME/\K).*")
14 |
15 | PLATFORMS=$(find release/$TARGET_NAME-$TARGET_TAG/bin -type d | grep -oP "(^.*/bin/\K).*" | cut -f1 -d/)
16 |
17 | if [ -z "${RELEASE}" ]; then
18 | PLATFORMS=(
19 | "linux-amd64"
20 | "linux-arm64"
21 | "linux-arm-v7"
22 | )
23 | fi
24 |
25 | echo "-- assembling images for package ${TARGET_NAME}-${TARGET_TAG}"
26 |
27 | for DOCKERFILE in $DOCKERFILES; do
28 |
29 | IMAGE=$(echo $DOCKERFILE | cut -f1 -d.)
30 | TARGET_REPOSITORY="indralabs/$(echo $DOCKERFILE | cut -f1 -d.)-multi-arch"
31 |
32 | echo "-- running assembler on $IMAGE"
33 |
34 | docker image ls --filter="reference=$TARGET_REPOSITORY*-$TARGET_TAG" -q | xargs docker image rm -f
35 |
36 | for PLATFORM in $PLATFORMS; do
37 |
38 | echo "--- assembling $TARGET_REPOSITORY:$PLATFORM-$TARGET_TAG"
39 |
40 | DOCKER_PLATFORM=$(echo $PLATFORM | tr '-' '/')
41 | DOCKER_PLATFORM_TAG=$PLATFORM-$TARGET_TAG
42 | SCRATCH_PLATFORM_TAG=$PLATFORM-latest
43 |
44 | if [ -z "${RELEASE}" ]; then
45 | DOCKER_PLATFORM_TAG=$PLATFORM-dev
46 | fi
47 |
48 | docker build --quiet --platform=$DOCKER_PLATFORM \
49 | --build-arg platform=$PLATFORM \
50 | --build-arg version=$TARGET_TAG \
51 | --build-arg scratch_version=$SCRATCH_PLATFORM_TAG \
52 | -t "$TARGET_REPOSITORY:$DOCKER_PLATFORM_TAG" \
53 | -f ./docker/release/targets/$TARGET_NAME/$DOCKERFILE .
54 |
55 | done
56 | done
57 |
58 | #PKGS="indralabs/indra-package:dev,indralabs/btcd-package:v0.23.3,indralabs/lnd-package:v0.15.5-beta" docker/release/scripts/run.sh
59 |
--------------------------------------------------------------------------------
/docker/release/scripts/extract.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ -z "${PKG}" ]; then
4 | echo "-- error: a pkg name is required to run an extract"
5 | exit 1
6 | fi
7 |
8 | if [ -z "${PKG_REPOSITORY}" ]; then
9 | echo "-- error: a pkg repository is required to run an extract"
10 | exit 1
11 | fi
12 |
13 | echo "- finding package $PKG"
14 |
15 | if [ ! -d "release/${PKG}" ]; then
16 |
17 | echo "-- binaries not found in release/${PKG}"
18 | echo "-- checking if archive exists release/${PKG}.tar.gz"
19 |
20 | if [ ! -e "release/${PKG}.tar.gz" ]; then
21 |
22 | echo "-- archive does not exist, attempting to extract from $PKG_REPOSITORY"
23 |
24 | docker run --rm -it --user=$UID:$GID \
25 | --volume=${PWD}/release:/tmp/release $PKG_REPOSITORY \
26 | find /tmp/ -maxdepth 1 -name *.tar.gz -exec cp {} /tmp/release \;
27 | fi
28 |
29 | echo "-- extracting archive from release/${PKG}.tar.gz"
30 |
31 | mkdir release/${PKG}
32 | tar -xzf release/${PKG}.tar.gz --directory ./release/${PKG}
33 | fi
34 |
35 | echo "-- found $PKG"
36 |
--------------------------------------------------------------------------------
/docker/release/scripts/link.sh:
--------------------------------------------------------------------------------
1 |
2 | if [ -z "${RELEASE_TAG}" ]; then
3 | echo "a release tag is required. use RELEASE_TAG='' to continue."
4 | exit 1
5 | fi
6 |
7 | if [ -z "${PKGS}" ]; then
8 | PKGS="indralabs/indra-package:dev"
9 | fi
10 |
11 | PKGS=$(echo $PKGS | tr ",", "\n")
12 |
13 | echo "- pushing packages to docker repositories"
14 |
15 | for PKG in $PKGS
16 | do
17 |
18 | echo "-- linking $PKG to $RELEASE_TAG"
19 |
20 | TARGET_NAME=$(echo $PKG | cut -f2 -d/ | cut -f1 -d:)
21 | TARGET_TAG=$(echo $PKG | cut -f2 -d:)
22 |
23 | SERVICES=$(find ./docker/release/targets/$TARGET_NAME -maxdepth 1 -type f -iname "*.Dockerfile" | grep -oP ".*$TARGET_NAME/\K(.*)(?=.Dockerfile)")
24 |
25 | for SERVICE in $SERVICES
26 | do
27 |
28 | echo "-- creating manifest for indralabs/$SERVICE:$RELEASE_TAG"
29 |
30 | docker manifest rm indralabs/$SERVICE:$RELEASE_TAG
31 |
32 | CMD="docker manifest create indralabs/$SERVICE:$RELEASE_TAG"
33 |
34 | IMAGES=$(docker image ls --filter="reference=indralabs/$SERVICE-multi-arch*$TARGET_TAG" --format="{{.Repository}}:{{.Tag}}")
35 |
36 | for image in $IMAGES; do
37 | CMD+=" --amend $image"
38 | done
39 |
40 | $CMD
41 |
42 | docker manifest push indralabs/$SERVICE:$RELEASE_TAG
43 | docker manifest inspect indralabs/$SERVICE:$RELEASE_TAG > release/$TARGET_NAME-$TARGET_TAG/release/manifest-docker-$SERVICE-$RELEASE_TAG.json
44 |
45 | done
46 |
47 | done
48 |
49 | # RELEASE_TAG="latest" PKGS="indralabs/btcd:v0.23.3" docker/release/scripts/link.sh
50 |
--------------------------------------------------------------------------------
/docker/release/scripts/manifest.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | MANIFEST_REPOSITORY="indralabs/indra"
4 | TARGET_REPOSITORY="indralabs/indra-multi-arch"
5 | TARGET_TAG="dev"
6 |
7 | IMAGES=$(docker image ls --filter="reference=$TARGET_REPOSITORY*-$TARGET_TAG" --format="{{.Repository}}:{{.Tag}}")
8 |
9 | echo "removing old manifest"
10 |
11 | docker manifest rm indralabs/indra:$TARGET_TAG
12 |
13 | CMD="docker manifest create $MANIFEST_REPOSITORY:$TARGET_TAG"
14 |
15 | for image in $IMAGES; do
16 | CMD+=" --amend $image"
17 | done
18 |
19 | $CMD
20 |
21 | docker manifest push $MANIFEST_REPOSITORY:$TARGET_TAG
22 | docker manifest inspect $MANIFEST_REPOSITORY:$TARGET_TAG > release/indra-$TARGET_TAG/release/manifest-docker-$TARGET_TAG.json
23 |
--------------------------------------------------------------------------------
/docker/release/scripts/push.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | TARGET_REPOSITORY="indralabs/indra-multi-arch"
4 | TARGET_TAG="dev"
5 |
6 | IMAGES=$(docker image ls --filter="reference=$TARGET_REPOSITORY*-$TARGET_TAG" --format="{{.Repository}}:{{.Tag}}")
7 |
8 | for i in $IMAGES; do
9 |
10 | echo "pushing "$i
11 |
12 | docker push $i
13 |
14 | done
15 |
--------------------------------------------------------------------------------
/docker/release/targets/btcd/bin/btcctl:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | docker run --rm -it --network=btcd_indranet \
4 | --volume=btcd_config:/etc/btcd:ro \
5 | indralabs/btcctl-multi-arch:linux-amd64-dev \
6 | --rpcserver=172.16.42.2:8334 \
7 | --rpcuser=simnet --rpcpass=simnet \
8 | --simnet $@
9 |
--------------------------------------------------------------------------------
/docker/release/targets/btcd/bin/btcctl-wallet:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | docker run --rm -it --network=btcd_indranet \
4 | --volume=btcd_btcwallet_config:/etc/btcwallet:ro \
5 | --volume=btcd_btcwallet_data:/var/btcwallet \
6 | indralabs/btcctl-multi-arch:linux-amd64-dev \
7 | --configfile=/dev/null \
8 | --rpcserver=172.16.42.3:8332 --rpccert=/etc/btcwallet/rpc.cert \
9 | --rpcuser=simnet --rpcpass=simnet \
10 | --simnet --wallet $@
11 |
12 |
--------------------------------------------------------------------------------
/docker/release/targets/btcd/btcctl.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | # ---
3 | # Target Configuration
4 | # ---
5 |
6 | ARG scratch_version="latest"
7 |
8 | FROM indralabs/scratch-multi-arch:${scratch_version}
9 |
10 | ARG platform
11 | ARG version
12 |
13 | ## We can't use 'COPY --from=...' here. Using ADD will enable multi-architecture releases
14 | ADD ./release/btcd-${version}/bin/${platform}/btcctl /bin
15 | ADD ./release/btcd-${version}/bin/${platform}/gencerts /bin
16 |
17 | # Enable the btcd user
18 | USER btcd:btcd
19 |
20 | # Set the data volumes
21 | #VOLUME ["/etc/btcd"]
22 | #VOLUME ["/var/btcd"]
23 |
24 | ENTRYPOINT ["/bin/btcctl", "--configfile=/dev/null", "--rpccert=/etc/btcd/keys/rpc.cert"]
25 |
26 |
--------------------------------------------------------------------------------
/docker/release/targets/btcd/btcd.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | # ---
3 | # Target Configuration
4 | # ---
5 |
6 | ARG scratch_version="latest"
7 |
8 | FROM indralabs/scratch-multi-arch:${scratch_version}
9 |
10 | ARG platform
11 | ARG version
12 |
13 | ## We can't use 'COPY --from=...' here. Using ADD will enable multi-architecture releases
14 | ADD ./release/btcd-${version}/bin/${platform}/btcd /bin
15 |
16 | # Enable the btcd user
17 | USER btcd:btcd
18 |
19 | # Set the data volumes
20 | #VOLUME ["/etc/btcd"]
21 | #VOLUME ["/var/btcd"]
22 |
23 | # :8333 btcd peer-to-peer port
24 | # :8334 btcd RPC port
25 | EXPOSE 8333 8334
26 |
27 | ENTRYPOINT ["/bin/btcd", "--configfile=/dev/null", "--datadir=/var/btcd", "--logdir=/var/btcd", "--listen=0.0.0.0:8333", "--rpckey=/etc/btcd/keys/rpc.key", "--rpccert=/etc/btcd/keys/rpc.cert", "--rpclisten=0.0.0.0:8334"]
28 |
--------------------------------------------------------------------------------
/docker/release/targets/btcd/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | btcd:
4 | image: indralabs/btcd-multi-arch:linux-amd64-dev
5 | volumes:
6 | - config:/etc/btcd
7 | - data:/var/btcd
8 | networks:
9 | indranet:
10 | ipv4_address: 172.16.42.2
11 | command:
12 | - "--rpcuser=simnet"
13 | - "--rpcpass=simnet"
14 | - "--simnet"
15 | - "--txindex"
16 | - "--miningaddr=SQWX48N37PFYbSrNqbZ8b4ZeYA3SPwwApR"
17 | btcwallet:
18 | image: indralabs/btcwallet-multi-arch:linux-amd64-dev
19 | volumes:
20 | - config:/etc/btcd:ro
21 | - btcwallet_config:/etc/btcwallet
22 | - btcwallet_data:/var/btcwallet
23 | networks:
24 | indranet:
25 | ipv4_address: 172.16.42.3
26 | depends_on:
27 | - btcd
28 | command:
29 | - "--simnet"
30 | - "--rpcconnect=172.16.42.2:8334"
31 | - "--username=simnet"
32 | - "--password=simnet"
33 | volumes:
34 | config:
35 | data:
36 | btcwallet_config:
37 | btcwallet_data:
38 | networks:
39 | indranet:
40 | driver: bridge
41 | ipam:
42 | driver: default
43 | config:
44 | - subnet: 172.16.42.0/24
45 | gateway: 172.16.42.1
46 |
47 | # docker-compose -f docker/btcd/docker-compose.yml up
--------------------------------------------------------------------------------
/docker/release/targets/btcd/setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Remove existing containers
4 | docker rm btcd-btcd-1 btcd-btcctl-1 btcd-btcwallet-1 2>/dev/null
5 |
6 | # Remove existing volumes
7 | docker volume rm btcd_config btcd_data btcd_btcwallet_config btcd_btcwallet_data 2>/dev/null
8 |
9 | # Setup an rpc key/cert for the btcwallet daemon
10 | docker run --rm -it \
11 | --volume=btcd_btcwallet_config:/etc/btcwallet \
12 | --entrypoint="/bin/gencerts" \
13 | --user=8332:8332 \
14 | indralabs/btcd-multi-arch:linux-amd64-dev \
15 | --directory=/etc/btcwallet -H 172.16.42.3 -f
16 |
17 | # Create a new wallet
18 | docker run --rm -it \
19 | --volume=btcd_btcwallet_config:/etc/btcwallet \
20 | --volume=btcd_btcwallet_data:/var/btcwallet \
21 | indralabs/btcwallet-multi-arch:linux-amd64-dev \
22 | --simnet --createtemp
23 |
24 | #docker run --rm -it \
25 | # --volume=btcd_btcwallet_config:/etc/btcwallet \
26 | # --volume=btcd_btcwallet_data:/var/btcwallet \
27 | # indralabs/btcwallet-multi-arch:linux-amd64-dev \
28 | # --simnet importprivkey FuarsNCxniX277tBYt1BDGPB6cRTUfeEhUBXNAjrg3cdsWZTNcPj
29 |
--------------------------------------------------------------------------------
/docker/release/targets/btcwallet/btcwallet.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | # ---
3 | # Target Configuration
4 | # ---
5 |
6 | ARG scratch_version="latest"
7 |
8 | FROM indralabs/scratch-multi-arch:${scratch_version}
9 |
10 | ARG platform
11 | ARG version
12 |
13 | ## We can't use 'COPY --from=...' here. Using ADD will enable multi-architecture releases
14 | ADD ./release/btcwallet-${version}/bin/${platform}/btcwallet /bin
15 |
16 | # Enable the btcd user
17 | USER btcwallet:btcwallet
18 |
19 | # Set the data volumes
20 | #VOLUME ["/etc/btcd"]
21 | #VOLUME ["/var/btcd"]
22 |
23 | # :8332 btcwallet RPC port
24 | EXPOSE 8332
25 |
26 | ENTRYPOINT ["/bin/btcwallet", "--configfile=/dev/null", "--appdata=/var/btcwallet", "--logdir=/var/btcwallet", "--cafile=/etc/btcd/keys/rpc.cert", "--rpckey=/etc/btcwallet/rpc.key", "--rpccert=/etc/btcwallet/rpc.cert", "--rpclisten=0.0.0.0:8332"]
27 |
--------------------------------------------------------------------------------
/docker/release/targets/indra/indra.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | # ---
3 | # Target Configuration
4 | # ---
5 |
6 | ARG scratch_version="latest"
7 |
8 | FROM indralabs/scratch-multi-arch:${scratch_version}
9 |
10 | ARG platform
11 | ARG version
12 |
13 | ## We can't use 'COPY --from=...' here. Using ADD will enable multi-architecture releases
14 | ADD ./release/indra-${version}/bin/${platform}/indra /bin
15 |
16 | # Enable the btcd user
17 | USER indra:indra
18 |
19 | # Set the data volumes
20 | #VOLUME ["/etc/indra"]
21 | #VOLUME ["/var/indra"]
22 | #VOLUME ["/var/log/indra"]
23 |
24 | # :8333 indra peer-to-peer port
25 | # :8334 indra RPC port
26 | EXPOSE 8337 8338
27 |
28 | ENV INDRA_CONF_FILE=/etc/indra/indra.conf
29 | ENV INDRA_DATA_DIR=/var/indra
30 | ENV INDRA_LOGS_DIR=/var/log/indra
31 |
32 | ENV INDRA_RPC_UNIX_LISTEN=/var/run/indra/indra.sock
33 |
34 | ENTRYPOINT ["/bin/indra"]
35 |
--------------------------------------------------------------------------------
/docker/release/targets/lnd/.gitignore:
--------------------------------------------------------------------------------
1 | .env
--------------------------------------------------------------------------------
/docker/release/targets/lnd/bin/lnsim-btcctl:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | docker run --rm -it --network=lnd_indranet \
4 | --volume=lnd_btcd_config:/etc/btcd:ro \
5 | indralabs/btcctl-multi-arch:linux-amd64-dev \
6 | --rpcserver=172.16.43.2:8334 \
7 | --rpcuser=simnet --rpcpass=simnet \
8 | --simnet $@
9 |
--------------------------------------------------------------------------------
/docker/release/targets/lnd/bin/lnsim-lncli-alice:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | docker run --rm -it \
4 | --network=lnd_indranet \
5 | --volume=lnd_lnd_alice_config:/etc/lnd:ro \
6 | --volume=lnd_lnd_alice_data:/var/lnd:ro \
7 | indralabs/lncli-multi-arch:linux-amd64-dev \
8 | --rpcserver=172.16.43.10 \
9 | --tlscertpath=/etc/lnd/keys/rpc.cert \
10 | --chain=bitcoin --network=simnet $@
11 |
--------------------------------------------------------------------------------
/docker/release/targets/lnd/bin/lnsim-lncli-bob:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | docker run --rm -it \
4 | --network=lnd_indranet \
5 | --volume=lnd_lnd_bob_config:/etc/lnd:ro \
6 | --volume=lnd_lnd_bob_data:/var/lnd:ro \
7 | indralabs/lncli-multi-arch:linux-amd64-dev \
8 | --rpcserver=172.16.43.11 \
9 | --tlscertpath=/etc/lnd/keys/rpc.cert \
10 | --chain=bitcoin --network=simnet $@
11 |
--------------------------------------------------------------------------------
/docker/release/targets/lnd/bin/lnsim-lncli-miner:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | docker run --rm -it \
4 | --network=lnd_indranet \
5 | --volume=lnd_lnd_miner_config:/etc/lnd:ro \
6 | --volume=lnd_lnd_miner_data:/var/lnd:ro \
7 | indralabs/lncli-multi-arch:linux-amd64-dev \
8 | --rpcserver=172.16.43.9 \
9 | --tlscertpath=/etc/lnd/keys/rpc.cert \
10 | --chain=bitcoin --network=simnet $@
11 |
--------------------------------------------------------------------------------
/docker/release/targets/lnd/lncli.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | # ---
3 | # Target Configuration
4 | # ---
5 |
6 | ARG scratch_version="latest"
7 |
8 | FROM indralabs/scratch-multi-arch:${scratch_version}
9 |
10 | ARG platform
11 | ARG version
12 |
13 | ## We can't use 'COPY --from=...' here. Using ADD will enable multi-architecture releases
14 | ADD ./release/lnd-${version}/bin/${platform}/lncli /bin
15 |
16 | # Enable the btcd user
17 | USER lnd:lnd
18 |
19 | # Set the data volumes
20 | #VOLUME ["/etc/lnd"]
21 | #VOLUME ["/var/lnd"]
22 |
23 | ENTRYPOINT ["/bin/lncli", "--lnddir=/var/lnd", "--tlscertpath=/etc/lnd/keys/rpc.cert"]
24 |
--------------------------------------------------------------------------------
/docker/release/targets/lnd/lnd.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | # ---
3 | # Target Configuration
4 | # ---
5 |
6 | ARG scratch_version="latest"
7 |
8 | FROM indralabs/scratch-multi-arch:${scratch_version}
9 |
10 | ARG platform
11 | ARG version
12 |
13 | ## We can't use 'COPY --from=...' here. Using ADD will enable multi-architecture releases
14 | ADD ./release/lnd-${version}/bin/${platform}/lnd /bin
15 |
16 | # Enable the btcd user
17 | USER lnd:lnd
18 |
19 | # Set the data volumes
20 | #VOLUME ["/etc/lnd"]
21 | #VOLUME ["/var/lnd"]
22 |
23 | # :9735 lnd peer-to-peer port
24 | # :10009 lnd RPC port
25 | EXPOSE 9735 10009
26 |
27 | ENTRYPOINT ["/bin/lnd", "--configfile=/dev/null", "--lnddir=/var/lnd", "--datadir=/var/lnd", "--logdir=/var/lnd", "--tlscertpath=/etc/lnd/keys/tls.cert", "--tlskeypath=/etc/lnd/keys/tls.key", "--feeurl=https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json", "--listen=0.0.0.0:9735", "--rpclisten=0.0.0.0:10009"]
28 | CMD ["--bitcoin.active", "--bitcoin.mainnet", "--bitcoin.node=neutrino"]
29 |
30 |
--------------------------------------------------------------------------------
/docker/scratch/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PLATFORMS=${SYS:-"
4 | linux/386
5 | linux/amd64
6 | linux/arm/v5
7 | linux/arm/v6
8 | linux/arm/v7
9 | linux/arm64
10 | linux/loong64
11 | linux/mips
12 | linux/mips64
13 | linux/mips64le
14 | linux/mipsle
15 | linux/ppc64
16 | linux/ppc64le
17 | linux/riscv64
18 | linux/s390x
19 | "}
20 |
21 | if [ -z "${TAG}" ]; then
22 | TAG="latest"
23 | fi
24 |
25 | if [ -z "${TARGET_TAG}" ]; then
26 | TARGET_TAG=$TAG
27 | fi
28 |
29 | for PLATFORM in $PLATFORMS; do
30 |
31 | DOCKER_PLATFORM_TAG=$(echo $PLATFORM | tr '/', '-')"-$TAG"
32 |
33 | echo "generating image: "$PLATFORM
34 |
35 | touch ${PWD}/release/scratch-$TAG/arch
36 |
37 | echo -e "FROM scratch\nADD release/scratch-$TAG/arch /$(echo $PLATFORM | tr '/', '-').arch\nADD release/scratch-$TAG/root-fs.tar.gz /\n" | \
38 | docker build -t indralabs/scratch-multi-arch:$DOCKER_PLATFORM_TAG --platform=$PLATFORM -f- .
39 |
40 | done
41 |
42 | for PLATFORM in $PLATFORMS; do
43 |
44 | DOCKER_PLATFORM_TAG=$(echo $PLATFORM | tr '/', '-')"-$TAG"
45 |
46 | docker push indralabs/scratch-multi-arch:$DOCKER_PLATFORM_TAG
47 |
48 | done
49 |
50 | docker manifest rm indralabs/scratch:$TARGET_TAG
51 |
52 | CMD="docker manifest create indralabs/scratch:$TARGET_TAG"
53 |
54 | for PLATFORM in $PLATFORMS; do
55 |
56 | DOCKER_PLATFORM_TAG=$(echo $PLATFORM | tr '/', '-')"-$TAG"
57 |
58 | CMD+=" --amend indralabs/scratch-multi-arch:$DOCKER_PLATFORM_TAG"
59 |
60 | done
61 |
62 | $CMD
63 |
64 | docker manifest push indralabs/scratch:$TARGET_TAG
65 |
--------------------------------------------------------------------------------
/docker/scratch/scripts/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ -z "${TAG}" ]; then
4 | TAG="latest"
5 | fi
6 |
7 | if [ -z "${TARGET_TAG}" ]; then
8 | TARGET_TAG=$TAG
9 | fi
10 |
11 | docker build -f ./docker/scratch/root-fs.Dockerfile -t indralabs/scratch-root-fs:$TAG .
12 |
13 | rm -rf release/scratch-$TARGET_TAG && mkdir -pv release/scratch-$TARGET_TAG
14 |
15 | docker run --rm -it --user=$UID:$GID \
16 | --volume=${PWD}/release:/tmp/release indralabs/scratch-root-fs:$TAG \
17 | cp /tmp/root-fs.tar.gz /tmp/release/scratch-$TARGET_TAG/root-fs.tar.gz
18 |
--------------------------------------------------------------------------------
/docker/sim/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | #volumes:
3 | #vol_name:
4 | services:
5 | seed_1:
6 | image: indralabs/indra:latest
7 | container_name: indra-seed-1
8 | networks:
9 | indranet:
10 | ipv4_address: 172.16.238.2
11 | #ports:
12 | #- 8337:8337
13 | #- 8338:8338
14 | #environment:
15 | #POSTGRES_DB: indra-local
16 | #POSTGRES_USER: indra
17 | #POSTGRES_PASSWORD: password
18 | command: ["serve"]
19 | peer_1:
20 | image: indralabs/indra:latest
21 | container_name: indra-peer-1
22 | networks:
23 | indranet:
24 | ipv4_address: 172.16.238.3
25 | depends_on:
26 | - seed_1
27 | #ports:
28 | #- 8337:8337
29 | #- 8338:8338
30 | #environment:
31 | #POSTGRES_DB: indra-local
32 | #POSTGRES_USER: indra
33 | #POSTGRES_PASSWORD: password
34 | command: ["serve"]
35 | peer_2:
36 | image: indralabs/indra:latest
37 | container_name: indra-peer-2
38 | networks:
39 | indranet:
40 | ipv4_address: 172.16.238.4
41 | depends_on:
42 | - seed_1
43 | #ports:
44 | #- 8337:8337
45 | #- 8338:8338
46 | #environment:
47 | #POSTGRES_DB: indra-local
48 | #POSTGRES_USER: indra
49 | #POSTGRES_PASSWORD: password
50 | command: ["serve"]
51 | networks:
52 | indranet:
53 | driver: bridge
54 | ipam:
55 | driver: default
56 | config:
57 | - subnet: 172.16.238.0/24
58 | gateway: 172.16.238.1
59 |
--------------------------------------------------------------------------------
/docker/sim/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | GOINSECURE="git-indra.lan/*" GOPRIVATE="git-indra.lan/*" go mod tidy
4 |
5 | IPFS_LOGGING=info go run ./cmd/indra/. $@
--------------------------------------------------------------------------------
/docker/sources/btcd/official.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | # ---
3 | # Build Process
4 | # ---
5 |
6 | ARG sourcing_image="golang"
7 |
8 | FROM indralabs/scratch:latest as scratch
9 |
10 | FROM ${sourcing_image} as source
11 |
12 | ARG source_url="https://github.com/btcsuite/btcd/releases/download"
13 | ARG source_version="v0.23.3"
14 |
15 | WORKDIR /tmp
16 |
17 | RUN set -ex echo "downloading source and binaries with manifest and signature." \
18 | && wget ${source_url}/${source_version}/manifest-${source_version}.txt \
19 | && wget ${source_url}/${source_version}/manifest-guggero-${source_version}.sig \
20 | && wget ${source_url}/${source_version}/btcd-source-${source_version}.tar.gz
21 |
22 | # Importing keys from scratch
23 | COPY --from=scratch /etc/btcd/keys/guggero.asc /tmp/guggero.asc
24 |
25 | RUN set -ex echo "importing keys" \
26 | && cat guggero.asc | gpg --import
27 |
28 | RUN set -ex echo "running signature verification on manifest" \
29 | && gpg --verify manifest-guggero-${source_version}.sig manifest-${source_version}.txt
30 |
31 | RUN set -ex echo "verifying checksum on btcd-source-${source_version}.tar.gz" \
32 | && cat manifest-${source_version}.txt | grep btcd-source-${source_version}.tar.gz | shasum -a 256 -c
33 |
34 | RUN set -ex echo "untarring binaries and source code" \
35 | && mv btcd-source-${source_version}.tar.gz /tmp/btcd-source.tar.gz \
36 | && mkdir -pv /tmp/btcd-source \
37 | && tar -xzvf btcd-source.tar.gz --directory /tmp/btcd-source
38 |
39 | WORKDIR /tmp/btcd-source
40 |
41 | RUN set -ex echo "downloading modules" \
42 | && go mod vendor
43 |
44 | FROM scratch
45 |
46 | COPY --from=source /tmp/btcd-source /source
47 | COPY --from=source /tmp/btcd-source.tar.gz /source.tar.gz
48 |
--------------------------------------------------------------------------------
/docker/sources/btcwallet/official.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | # ---
3 | # Build Process
4 | # ---
5 |
6 | ARG sourcing_image="golang"
7 |
8 | FROM indralabs/scratch:latest as scratch
9 |
10 | FROM ${sourcing_image} as source
11 |
12 | ARG source_url="https://github.com/btcsuite/btcwallet"
13 | ARG source_version="v0.16.5"
14 |
15 | WORKDIR /tmp
16 |
17 | RUN set -ex echo "downloading source" \
18 | && git clone ${source_url}
19 |
20 | # Importing keys from scratch
21 | COPY --from=scratch /etc/btcd/keys/guggero.asc /tmp/guggero.asc
22 |
23 | RUN set -ex echo "importing keys" \
24 | && cat guggero.asc | gpg --import
25 |
26 | WORKDIR /tmp/btcwallet
27 |
28 | RUN set -ex echo "checking out tag" \
29 | && git checkout -b ${source_version}
30 |
31 | RUN set -ex echo "running signature verification on tag" \
32 | && git verify-tag ${source_version}
33 |
34 | RUN set -ex "archiving indra source files" \
35 | && git archive --format=tar.gz -o /tmp/btcwallet-source.tar.gz ${source_version}
36 |
37 | WORKDIR /tmp
38 |
39 | RUN set -ex echo "untarring archived source code" \
40 | && rm -rf btcwallet \
41 | && mkdir -pv btcwallet-source \
42 | && tar -xzvf btcwallet-source.tar.gz --directory btcwallet-source
43 |
44 | WORKDIR /tmp/btcwallet-source
45 |
46 | RUN set -ex echo "downloading modules" \
47 | && go mod vendor
48 |
49 | FROM scratch
50 |
51 | COPY --from=source /tmp/btcwallet-source /source
52 | COPY --from=source /tmp/btcwallet-source.tar.gz /source.tar.gz
53 |
--------------------------------------------------------------------------------
/docker/sources/indra/local.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | # ---
3 | # Build Process
4 | # ---
5 |
6 | ARG sourcing_image="golang"
7 |
8 | FROM ${sourcing_image} as source
9 |
10 | ADD . /tmp/indra-source
11 |
12 | WORKDIR /tmp/indra-source
13 |
14 | RUN set -ex "archiving indra source files" \
15 | && git archive --format=tar.gz -o /tmp/indra-source.tar.gz HEAD
16 |
17 | WORKDIR /tmp
18 |
19 | RUN set -ex "cleaning up repository" \
20 | && rm -rf /tmp/indra-source && mkdir /tmp/indra-source \
21 | && tar -xzvf /tmp/indra-source.tar.gz --directory indra-source
22 |
23 | WORKDIR /tmp/indra-source
24 |
25 | RUN set -ex echo "downloading modules" \
26 | && GOINSECURE=git-indra.lan/* GOPRIVATE=git-indra.lan/* go mod vendor
27 |
28 | FROM scratch
29 |
30 | COPY --from=source /tmp/indra-source /source
31 | COPY --from=source /tmp/indra-source.tar.gz /source.tar.gz
32 |
--------------------------------------------------------------------------------
/docker/sources/indra/official.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | # ---
3 | # Build Process
4 | # ---
5 |
6 | ARG sourcing_image="golang"
7 |
8 | FROM indralabs/scratch:latest as scratch
9 |
10 | FROM ${sourcing_image} as source
11 |
12 | ARG source_url="https://git-indra.lan/indra-labs/indra/releases/download"
13 | ARG source_version="v0.1.10"
14 |
15 | WORKDIR /tmp
16 |
17 | RUN set -ex echo "downloading source and binaries with manifest and signature." \
18 | && wget ${source_url}/${source_version}/manifest-${source_version}.txt \
19 | && wget ${source_url}/${source_version}/manifest-greg.stone-${source_version}.sig \
20 | && wget ${source_url}/${source_version}/manifest-херетик-${source_version}.sig \
21 | && wget ${source_url}/${source_version}/indra-source-${source_version}.tar.gz
22 |
23 | # Importing keys from scratch
24 | COPY --from=scratch /etc/indra/keys/greg.stone.asc /tmp/greg.stone.asc
25 | COPY --from=scratch /etc/indra/keys/херетик.asc /tmp/херетик.asc
26 |
27 | RUN set -ex echo "importing keys" \
28 | && cat a.asc | gpg --import \
29 | && cat b.asc | gpg --import
30 |
31 | RUN set -ex echo "running signature verification on manifest" \
32 | && gpg --verify manifest-greg.stone-${source_version}.sig manifest-${source_version}.txt \
33 | && gpg --verify manifest-херетик-${source_version}.sig manifest-${source_version}.txt
34 |
35 | RUN set -ex echo "verifying checksum on indra-source-${source_version}.tar.gz" \
36 | && cat manifest-${source_version}.txt | grep indra-source-${source_version}.tar.gz | shasum -a 256 -c
37 |
38 | RUN set -ex echo "untarring binaries and source code" \
39 | && mv indra-source-${source_version}.tar.gz /tmp/indra-source.tar.gz \
40 | && mkdir -pv /tmp/indra-source \
41 | && tar -xzvf indra-source.tar.gz --directory /tmp/indra-source
42 |
43 | WORKDIR /tmp/indra-source
44 |
45 | RUN set -ex echo "downloading modules" \
46 | && go mod vendor
47 |
48 | FROM scratch
49 |
50 | COPY --from=source /tmp/indra-source /source
51 | COPY --from=source /tmp/indra-source.tar.gz /source.tar.gz
52 |
--------------------------------------------------------------------------------
/docker/sources/lnd/official.Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | # ---
3 | # Build Process
4 | # ---
5 |
6 | ARG sourcing_image="golang"
7 |
8 | FROM indralabs/scratch:latest as scratch
9 |
10 | FROM ${sourcing_image} as source
11 |
12 | ARG source_url="https://github.com/lightningnetwork/lnd/releases/download"
13 | ARG source_version="v0.15.5-beta"
14 |
15 | WORKDIR /tmp
16 |
17 | RUN set -ex echo "downloading source and binaries with manifest and signature." \
18 | && wget ${source_url}/${source_version}/manifest-${source_version}.txt \
19 | && wget ${source_url}/${source_version}/manifest-roasbeef-${source_version}.sig \
20 | && wget ${source_url}/${source_version}/lnd-source-${source_version}.tar.gz
21 |
22 | # Importing keys from scratch
23 | COPY --from=scratch /etc/lnd/keys/roasbeef.asc /tmp/roasbeef.asc
24 |
25 | RUN set -ex echo "importing keys" \
26 | && cat roasbeef.asc | gpg --import
27 |
28 | RUN set -ex echo "running signature verification on manifest" \
29 | && gpg --verify manifest-roasbeef-${source_version}.sig manifest-${source_version}.txt
30 |
31 | RUN set -ex echo "verifying checksum on lnd-source-${source_version}.tar.gz" \
32 | && cat manifest-${source_version}.txt | grep lnd-source-${source_version}.tar.gz | shasum -a 256 -c
33 |
34 | RUN set -ex echo "untarring binaries and source code" \
35 | && mv lnd-source-${source_version}.tar.gz /tmp/lnd-source.tar.gz \
36 | && mkdir -pv /tmp/lnd-source \
37 | && tar -xzvf lnd-source.tar.gz --directory /tmp/lnd-source
38 |
39 | WORKDIR /tmp/lnd-source/lnd-source
40 |
41 | RUN set -ex echo "downloading modules" \
42 | && go mod vendor
43 |
44 | FROM scratch
45 |
46 | COPY --from=source /tmp/lnd-source/lnd-source /source
47 | COPY --from=source /tmp/lnd-source.tar.gz /source.tar.gz
48 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 |
--------------------------------------------------------------------------------
/docs/1507.05724v1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/1507.05724v1.pdf
--------------------------------------------------------------------------------
/docs/2008-080.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/2008-080.pdf
--------------------------------------------------------------------------------
/docs/2018-126.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/2018-126.pdf
--------------------------------------------------------------------------------
/docs/DanezisG09.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/DanezisG09.pdf
--------------------------------------------------------------------------------
/docs/acns11-certificateless.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/acns11-certificateless.pdf
--------------------------------------------------------------------------------
/docs/architecture.md:
--------------------------------------------------------------------------------
1 | # architecture
2 |
3 | ## Overview
4 |
5 |
6 |
7 | ## Relay Engine
8 |
9 |
10 |
11 | ## Client
12 |
13 |
--------------------------------------------------------------------------------
/docs/formats.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/formats.pdf
--------------------------------------------------------------------------------
/docs/hidden1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/hidden1.png
--------------------------------------------------------------------------------
/docs/hidden2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/hidden2.png
--------------------------------------------------------------------------------
/docs/hidden3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/hidden3.png
--------------------------------------------------------------------------------
/docs/image-20220912120917831.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/image-20220912120917831.png
--------------------------------------------------------------------------------
/docs/indra.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/indra.png
--------------------------------------------------------------------------------
/docs/logo-for-dark-ground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/logo-for-dark-ground.png
--------------------------------------------------------------------------------
/docs/logo-for-dark-tshirt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/logo-for-dark-tshirt.png
--------------------------------------------------------------------------------
/docs/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/logo.png
--------------------------------------------------------------------------------
/docs/message_format.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/message_format.jpg
--------------------------------------------------------------------------------
/docs/readme.md:
--------------------------------------------------------------------------------
1 | # docs
2 |
3 | [white paper](./whitepaper.md)
4 |
5 | [architecture](./architecture.md)
6 |
7 | [protocols](./protocols.md)
--------------------------------------------------------------------------------
/docs/scripts/installtoc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | sudo apt install -y fswatch
4 | go install github.com/nochso/tocenize/cmd/tocenize@latest
5 |
--------------------------------------------------------------------------------
/docs/scripts/toc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | find .|grep md$|xargs -n1 tocenize -max 3 -min 2
4 |
--------------------------------------------------------------------------------
/docs/session.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/session.png
--------------------------------------------------------------------------------
/docs/torrelaycount.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/torrelaycount.png
--------------------------------------------------------------------------------
/docs/whitepaper.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indra-labs/indra/089a0df491fd76ac393875053625f9fd4fdbe140/docs/whitepaper.pdf
--------------------------------------------------------------------------------
/keys/greg.stone.asc:
--------------------------------------------------------------------------------
1 | -----BEGIN PGP PUBLIC KEY BLOCK-----
2 | Comment: User-ID: greg stone
3 | Comment: Valid from: 27/01/2023 17:05
4 | Comment: Valid until: 27/01/2025 12:00
5 | Comment: Type: 256-bit EdDSA (secret key available)
6 | Comment: Usage: Signing, Encryption, Certifying User-IDs, SSH Authentication
7 | Comment: Fingerprint: E6657BDDAFC53ACDDA4F330E374F2004300A0D84
8 |
9 | mDMEY9QEXBYJKwYBBAHaRw8BAQdAMGN2R95Vn8/g9UF4ELR5DbSaIIULZ5SHXja4
10 | Jya/eta0IWdyZWcgc3RvbmUgPGdyZWcuc3RvbmVAaW5kcmEub3JnPoiWBBMWCAA+
11 | FiEE5mV73a/FOs3aTzMON08gBDAKDYQFAmPUBFwCGyMFCQPDcOQFCwkIBwIGFQoJ
12 | CAsCBBYCAwECHgECF4AACgkQN08gBDAKDYRyNwD8Cjo/6jZaEUYAM8buTkiACmue
13 | Mny4tnMnOiYXv5q287AA/RtMUe6U2shzVi3gcNfYxvIlEJMI/FGiuFvqjNOSWIoI
14 | uDgEY9QEXBIKKwYBBAGXVQEFAQEHQPqEQ8QVXed0OEDmzSnNc216JqLvHuvovShH
15 | gjee+NgHAwEIB4h+BBgWCAAmFiEE5mV73a/FOs3aTzMON08gBDAKDYQFAmPUBFwC
16 | GwwFCQPDcOQACgkQN08gBDAKDYT9HgD+JvaMM2FPu5v4mCPyYRFZdwIlPcKQ5m8V
17 | hX/KBQ8bprAA/2cL6cNwWAv8RwpEUOt4yeRi07F0TDLuRoZhM/G76GAC
18 | =sseN
19 | -----END PGP PUBLIC KEY BLOCK-----
--------------------------------------------------------------------------------
/keys/херетик.asc:
--------------------------------------------------------------------------------
1 | -----BEGIN PGP PUBLIC KEY BLOCK-----
2 | Comment: User-ID: херетик
3 | Comment: Created: 02/07/2023 17:05
4 | Comment: Expires: 02/07/2025 12:00
5 | Comment: Type: 256-bit EdDSA (secret key available)
6 | Comment: Usage: Signing, Encryption, Certifying User-IDs, SSH Authentication
7 | Comment: Fingerprint: BB2D7666C9A72E94A8F25BE8CCE6B9B04F59BBDC
8 |
9 | mDMEZKGgPhYJKwYBBAHaRw8BAQdA0hxkL6gwZv79AGwAQ7JrzEugJxGxRXibUYDj
10 | yb0UlEO0ItGF0LXRgNC10YLQuNC6IDxoZXJldGlrQGluZHJhLm9yZz6IlgQTFggA
11 | PhYhBLstdmbJpy6UqPJb6MzmubBPWbvcBQJkoaA+AhsjBQkDw3DyBQsJCAcCBhUK
12 | CQgLAgQWAgMBAh4BAheAAAoJEMzmubBPWbvcYCQBAIhihZQ2b5GCU7mtQ3Dge/yc
13 | SEgkX7l9IvYpX8cXg8R5AQCAosx5EuXqu1gR1InVE3FxreT8e4ywLJ5hEi+EVbFM
14 | A7g4BGShoD4SCisGAQQBl1UBBQEBB0AR+gxrrIMixoPLx318412FGTeY+gcb+wO+
15 | iNcCyLfrRgMBCAeIfgQYFggAJhYhBLstdmbJpy6UqPJb6MzmubBPWbvcBQJkoaA+
16 | AhsMBQkDw3DyAAoJEMzmubBPWbvcNaMBAKfCmCMg7fBywZVdm0I+G7bV3scXnQGs
17 | ypm5LYxFFogVAQC3mMVrl/OnYoh6l49YA5K9l+HlN1nLNBo+DFArLATqBA==
18 | =YRa/
19 | -----END PGP PUBLIC KEY BLOCK-----
20 |
--------------------------------------------------------------------------------
/localversion.go:
--------------------------------------------------------------------------------
1 | //go:build local
2 |
3 | // Package indra is the root of the repository for the Indra distributed VPN, containing mainly the version information for included executables to use for information and identification on the network.
4 | //
5 | // todo: need to make cmd/bumper in use again so the below inaccurate git repo details are accurate.
6 | //
7 | // See [pkg/git.indra-labs.org/dev/ind/cmd/indra] for the main server executable.
8 | //
9 | // Put invocations to run all the generators in here check [pkg/git.indra-labs.org/dev/ind/cmd/bumper] to add them, and they will automatically run with:
10 | //
11 | // $ go generate .
12 | //
13 | // which will run all these generators below and finish with a go install.
14 | //
15 | //go:generate go install ./...
16 | package indra
17 |
18 | import "fmt"
19 |
20 | const (
21 | // URL is the git URL for the repository.
22 | URL = "git.indra-labs.org/dev/ind"
23 | // GitRef is the gitref, as in refs/heads/branchname.
24 | GitRef = "refs/heads/master"
25 | // ParentGitCommit is the commit hash of the parent HEAD.
26 | ParentGitCommit = "5380d5f01e7d712258d7c1baa99172cc4bf014ef"
27 | // BuildTime stores the time when the current binary was built.
28 | BuildTime = "2023-06-17T09:14:01+01:00"
29 | // SemVer lists the (latest) git tag on the release.
30 | SemVer = "v0.1.20"
31 | // Major is the major number from the tag.
32 | Major = 0
33 | // Minor is the minor number from the tag.
34 | Minor = 1
35 | // Patch is the patch version number from the tag.
36 | Patch = 20
37 | )
38 |
39 | var CI = "false"
40 |
41 | // Version returns a pretty printed version information string.
42 | func Version() string {
43 | return fmt.Sprint(
44 | "\nRepository Information\n",
45 | "\tGit repository: "+URL+"\n",
46 | "\tBranch: "+GitRef+"\n",
47 | "\tParentGitCommit: "+ParentGitCommit+"\n",
48 | "\tBuilt: "+BuildTime+"\n",
49 | "\tSemVer: "+SemVer+"\n",
50 | )
51 | }
52 |
--------------------------------------------------------------------------------
/pkg/cert/ad.go:
--------------------------------------------------------------------------------
1 | // Package cert is an interface for messages bearing signatures of network participants.
2 | package cert
3 |
4 | import (
5 | "git.indra-labs.org/dev/ind/pkg/codec"
6 | "git.indra-labs.org/dev/ind/pkg/crypto"
7 | "github.com/libp2p/go-libp2p/core/peer"
8 | )
9 |
10 | // Act is an interface for the signed messages stored in the PeerStore of the
11 | // libp2p host inside an indra engine.
12 | //
13 | // Note the abstract name and the open ended possibility of composing this into
14 | // other types of contract documents. In the language of Law an Act is the
15 | // prototype of a declaration or claim, a land title is an example of a type of
16 | // Act.
17 | type Act interface {
18 | codec.Codec
19 | Sign(key *crypto.Prv) (e error)
20 | Validate() bool
21 | PubKey() (pubKey *crypto.Pub)
22 | GetID() (id peer.ID, e error)
23 | Expired() (is bool)
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/cfg/doc.go:
--------------------------------------------------------------------------------
1 | // Package cfg contains settings for the various network modes and seeds for those networks.
2 | package cfg
3 |
--------------------------------------------------------------------------------
/pkg/cfg/seed_address.go:
--------------------------------------------------------------------------------
1 | package cfg
2 |
3 | // SeedAddress is a form of the key and network address for seeds on a network.
4 | type SeedAddress struct {
5 |
6 | // ID is the p2p identifier (peer identity key).
7 | ID string
8 |
9 | // DNSAddress is the hostname of the seed node
10 | DNSAddress string
11 | }
12 |
13 | // NewSeedAddress creates a new seed from a network address and seed public key in base58 encoding.
14 | func NewSeedAddress(dns string, id string) *SeedAddress {
15 |
16 | return &SeedAddress{
17 | ID: id,
18 | DNSAddress: dns,
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/pkg/codec/ad/ad.go:
--------------------------------------------------------------------------------
1 | // Package ad is an abstract message type that composes the common elements of all ads - nonce ID, public key (identity), expiry and signature.
2 | //
3 | // The concrete ad types are in subfolders of this package.
4 | package ad
5 |
6 | import (
7 | "git.indra-labs.org/dev/ind/pkg/crypto"
8 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
9 | "git.indra-labs.org/dev/ind/pkg/engine/magic"
10 | "git.indra-labs.org/dev/ind/pkg/util/slice"
11 | "time"
12 | )
13 |
14 | const (
15 | Len = magic.Len +
16 | nonce.IDLen +
17 | crypto.PubKeyLen +
18 | slice.Uint64Len +
19 | crypto.SigLen
20 | )
21 |
22 | // Ad is an abstract message that isn't actually used, but rather is composed
23 | // into the rest being the common fields to all ads.
24 | type Ad struct {
25 |
26 | // ID is a random number generated for each new add that practically guarantees
27 | // no repeated hash for a message to be signed with the same peer identity key.
28 | ID nonce.ID
29 |
30 | // Key is the public identity key of the peer.
31 | Key *crypto.Pub
32 |
33 | // Expiry is the time after which this ad is considered no longer current.
34 | Expiry time.Time
35 |
36 | // Sig is the signature, which must match the Key above.
37 | Sig crypto.SigBytes
38 | }
39 |
--------------------------------------------------------------------------------
/pkg/codec/ad/addresses/addresses_test.go:
--------------------------------------------------------------------------------
1 | package addresses
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
6 | "git.indra-labs.org/dev/ind/pkg/crypto"
7 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
8 | "git.indra-labs.org/dev/ind/pkg/util/ci"
9 | "git.indra-labs.org/dev/ind/pkg/util/splice"
10 | "github.com/multiformats/go-multiaddr"
11 | "testing"
12 | "time"
13 | )
14 |
15 | func TestNew(t *testing.T) {
16 | ci.TraceIfNot()
17 | var e error
18 | pr, _, _ := crypto.NewSigner()
19 | id := nonce.NewID()
20 | var ma4, ma6 multiaddr.Multiaddr
21 | if ma4, e = multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/4242"); fails(e) {
22 | t.FailNow()
23 | }
24 | if ma6, e = multiaddr.NewMultiaddr("/ip6/::1/tcp/4242"); fails(e) {
25 | t.FailNow()
26 | }
27 | aa := New(id, pr, []multiaddr.Multiaddr{ma4, ma6},
28 | time.Now().Add(time.Hour*24*7))
29 | l := aa.Len()
30 | log.I.Ln("l", l)
31 | s := splice.New(l)
32 | if e = aa.Encode(s); fails(e) {
33 | t.FailNow()
34 | }
35 | s.SetCursor(0)
36 | var onc codec.Codec
37 | if onc = reg.Recognise(s); onc == nil {
38 | t.Error("did not unwrap")
39 | t.FailNow()
40 | }
41 | if e = onc.Decode(s); fails(e) {
42 | t.Error("did not decode")
43 | t.FailNow()
44 | }
45 | var ad *Ad
46 | var ok bool
47 | if ad, ok = onc.(*Ad); !ok {
48 | t.Error("did not unwrap expected type")
49 | t.FailNow()
50 | }
51 | if ad.Expiry.Unix() != aa.Expiry.Unix() {
52 | t.Errorf("expiry did not decode correctly")
53 | t.FailNow()
54 | }
55 | log.D.S("received", ad)
56 | if ad.ID != aa.ID {
57 | t.Errorf("ID did not decode correctly")
58 | t.FailNow()
59 | }
60 | for i := range ad.Addresses {
61 | if ad.Addresses[i].String() != aa.Addresses[i].String() {
62 | t.Errorf("address did not decode correctly")
63 | t.FailNow()
64 | }
65 | }
66 | if !ad.Key.Equals(crypto.DerivePub(pr)) {
67 | t.Errorf("public key did not decode correctly")
68 | t.FailNow()
69 | }
70 | if !ad.Validate() {
71 | t.Errorf("received ad did not validate")
72 | t.FailNow()
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/pkg/codec/ad/intro/intro_test.go:
--------------------------------------------------------------------------------
1 | package intro
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
6 | "git.indra-labs.org/dev/ind/pkg/util/ci"
7 | "git.indra-labs.org/dev/ind/pkg/util/splice"
8 | "testing"
9 | "time"
10 |
11 | "git.indra-labs.org/dev/ind/pkg/crypto"
12 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
13 | )
14 |
15 | func TestNew(t *testing.T) {
16 | ci.TraceIfNot()
17 | var e error
18 | pr, ks, _ := crypto.NewSigner()
19 | introducer := ks.Next()
20 | id := nonce.NewID()
21 | in := New(id, pr, crypto.DerivePub(introducer),
22 | 20000, 80, time.Now().Add(time.Hour))
23 | s := splice.New(in.Len())
24 | if e = in.Encode(s); fails(e) {
25 | t.FailNow()
26 | }
27 | s.SetCursor(0)
28 | var onc codec.Codec
29 | if onc = reg.Recognise(s); onc == nil {
30 | t.Error("did not unwrap")
31 | t.FailNow()
32 | }
33 | if e = onc.Decode(s); fails(e) {
34 | t.Error("did not decode")
35 | t.FailNow()
36 | }
37 | var ad *Ad
38 | var ok bool
39 | if ad, ok = onc.(*Ad); !ok {
40 | t.Error("did not unwrap expected type")
41 | t.FailNow()
42 | }
43 | log.D.S(ad)
44 | if ad.ID != in.ID {
45 | t.Errorf("ID did not decode correctly")
46 | t.FailNow()
47 | }
48 | if ad.Port != in.Port {
49 | t.Errorf("port did not decode correctly")
50 | t.FailNow()
51 | }
52 | if ad.RelayRate != in.RelayRate {
53 | t.Errorf("relay rate did not decode correctly")
54 | t.FailNow()
55 | }
56 | if ad.Expiry.Unix() != in.Expiry.Unix() {
57 | t.Errorf("expiry did not decode correctly")
58 | t.FailNow()
59 | }
60 | if !ad.Key.Equals(crypto.DerivePub(pr)) {
61 | t.Errorf("public key did not decode correctly")
62 | t.FailNow()
63 | }
64 | if !ad.Introducer.Equals(crypto.DerivePub(introducer)) {
65 | t.Errorf("public key did not decode correctly")
66 | t.FailNow()
67 | }
68 | if !ad.Validate() {
69 | t.Errorf("received intro did not validate")
70 | t.FailNow()
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/pkg/codec/ad/load/load_test.go:
--------------------------------------------------------------------------------
1 | package load
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/util/ci"
6 | "testing"
7 | "time"
8 |
9 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
10 | "git.indra-labs.org/dev/ind/pkg/crypto"
11 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
12 | "git.indra-labs.org/dev/ind/pkg/util/splice"
13 | )
14 |
15 | func TestNew(t *testing.T) {
16 | ci.TraceIfNot()
17 | var e error
18 | pr, _, _ := crypto.NewSigner()
19 | id := nonce.NewID()
20 | aa := New(id, pr, 10, time.Now().Add(time.Hour))
21 | s := splice.New(aa.Len())
22 | if e = aa.Encode(s); fails(e) {
23 | t.FailNow()
24 | }
25 | s.SetCursor(0)
26 | var onc codec.Codec
27 | if onc = reg.Recognise(s); onc == nil {
28 | t.Error("did not unwrap")
29 | t.FailNow()
30 | }
31 | if e = onc.Decode(s); fails(e) {
32 | t.Error("did not decode")
33 | t.FailNow()
34 | }
35 | var ad *Ad
36 | var ok bool
37 | if ad, ok = onc.(*Ad); !ok {
38 | t.Error("did not unwrap expected type")
39 | t.FailNow()
40 | }
41 | log.D.S(ad)
42 | if ad.ID != aa.ID {
43 | t.Errorf("ID did not decode correctly")
44 | t.FailNow()
45 | }
46 | if ad.Expiry.Unix() != aa.Expiry.Unix() {
47 | t.Errorf("expiry did not decode correctly")
48 | t.FailNow()
49 | }
50 | if !ad.Key.Equals(crypto.DerivePub(pr)) {
51 | t.Errorf("public key did not decode correctly")
52 | t.FailNow()
53 | }
54 | if ad.Load != aa.Load {
55 | t.Errorf("received ad did not have same load")
56 | t.FailNow()
57 | }
58 | if !ad.Validate() {
59 | t.Errorf("received ad did not validate")
60 | t.FailNow()
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/pkg/codec/ad/peer/peer_test.go:
--------------------------------------------------------------------------------
1 | package peer
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/util/ci"
6 | "testing"
7 | "time"
8 |
9 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
10 | "git.indra-labs.org/dev/ind/pkg/crypto"
11 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
12 | "git.indra-labs.org/dev/ind/pkg/util/splice"
13 | )
14 |
15 | func TestNew(t *testing.T) {
16 | ci.TraceIfNot()
17 | var e error
18 | pr, _, _ := crypto.NewSigner()
19 | id := nonce.NewID()
20 | aa := New(id, pr, 20000, time.Now().Add(time.Hour))
21 | s := splice.New(aa.Len())
22 | if e = aa.Encode(s); fails(e) {
23 | t.FailNow()
24 | }
25 | s.SetCursor(0)
26 | var onc codec.Codec
27 | if onc = reg.Recognise(s); onc == nil {
28 | t.Error("did not unwrap")
29 | t.FailNow()
30 | }
31 | if e = onc.Decode(s); fails(e) {
32 | t.Error("did not decode")
33 | t.FailNow()
34 | }
35 | var ad *Ad
36 | var ok bool
37 | if ad, ok = onc.(*Ad); !ok {
38 | t.Error("did not unwrap expected type")
39 | t.FailNow()
40 | }
41 | log.T.S(ad)
42 | if ad.ID != aa.ID {
43 | t.Errorf("ID did not decode correctly")
44 | t.FailNow()
45 | }
46 | if ad.Expiry.Unix() != aa.Expiry.Unix() {
47 | t.Errorf("expiry did not decode correctly")
48 | t.FailNow()
49 | }
50 | if !ad.Key.Equals(crypto.DerivePub(pr)) {
51 | t.Errorf("public key did not decode correctly")
52 | t.FailNow()
53 | }
54 | if ad.RelayRate != aa.RelayRate {
55 | t.Errorf("received ad did not have same relay rate")
56 | t.FailNow()
57 | }
58 | if !ad.Validate() {
59 | t.Errorf("received ad did not validate")
60 | t.FailNow()
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/pkg/codec/ad/services/services_test.go:
--------------------------------------------------------------------------------
1 | package services
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
6 | "git.indra-labs.org/dev/ind/pkg/crypto"
7 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
8 | "git.indra-labs.org/dev/ind/pkg/util/ci"
9 | "git.indra-labs.org/dev/ind/pkg/util/splice"
10 | "testing"
11 | "time"
12 | )
13 |
14 | func TestServiceAd(t *testing.T) {
15 | ci.TraceIfNot()
16 | var e error
17 | pr, _, _ := crypto.NewSigner()
18 | id := nonce.NewID()
19 | sv := New(id, pr, []Service{{80, 62346}, {443, 42216}},
20 | time.Now().Add(time.Hour))
21 | log.D.S("service", sv)
22 | s := splice.New(sv.Len())
23 | if e = sv.Encode(s); fails(e) {
24 | t.FailNow()
25 | }
26 | s.SetCursor(0)
27 | var onc codec.Codec
28 | if onc = reg.Recognise(s); onc == nil {
29 | t.Error("did not unwrap")
30 | t.FailNow()
31 | }
32 | if e = onc.Decode(s); fails(e) {
33 | t.Error("did not decode")
34 | t.FailNow()
35 | }
36 | log.T.S(onc)
37 | var svcAd *Ad
38 | var ok bool
39 | if svcAd, ok = onc.(*Ad); !ok {
40 | t.Error("did not unwrap expected type")
41 | t.FailNow()
42 | }
43 | if len(sv.Services) != len(svcAd.Services) {
44 | t.Errorf("number of services incorrectly decoded")
45 | t.FailNow()
46 | }
47 | for i := range sv.Services {
48 | if svcAd.Services[i].RelayRate != sv.Services[i].RelayRate {
49 | t.Errorf("relay rate did not decode correctly")
50 | t.FailNow()
51 | }
52 | if svcAd.Services[i].Port != sv.Services[i].Port {
53 | t.Errorf("port did not decode correctly")
54 | t.FailNow()
55 | }
56 | }
57 | if !svcAd.Key.Equals(crypto.DerivePub(pr)) {
58 | t.Errorf("public key did not decode correctly")
59 | t.FailNow()
60 | }
61 | if !svcAd.Validate() {
62 | t.Errorf("received service ad did not validate")
63 | t.FailNow()
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/pkg/codec/interfaces.go:
--------------------------------------------------------------------------------
1 | // Package codec defines an interface for encoding and decoding message packets in the Indra network.
2 | //
3 | // These are implemented for onion messages, advertisements and other peer messages that are not for relaying.
4 | package codec
5 |
6 | import (
7 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
8 | "git.indra-labs.org/dev/ind/pkg/util/splice"
9 | )
10 |
11 | var (
12 | log = log2.GetLogger()
13 | fails = log.E.Chk
14 | )
15 |
16 | // Codec is a unit of data that can be read and written from a binary form. All
17 | // Onion are Codec but not all Codec are Onion. Codec is also used for the
18 | // Dispatcher's message headers.
19 | type Codec interface {
20 |
21 | // Magic is a 4 byte string identifying the type of the following message bytes.
22 | Magic() string
23 |
24 | // Encode uses the Codec's contents to encode into the splice.Splice next bytes.
25 | Encode(s *splice.Splice) (e error)
26 |
27 | // Decode reads in the data in the next bytes of the splice.Splice to populate this Codec.
28 | Decode(s *splice.Splice) (e error)
29 |
30 | // Len returns the number of bytes required to encode this Codec message (including Magic).
31 | //
32 | // This function must panic if called on a nil pointer as unconfigured
33 | // messages cannot yield a valid length value in many cases.
34 | Len() int
35 |
36 | // Unwrap gives access to any further layers embedded inside this (specifically, the Onion inside).
37 | Unwrap() interface{}
38 | }
39 |
40 | func MustNotBeNil(c Codec) {
41 | if c == nil {
42 | panic("cannot compute length without struct fields")
43 | }
44 | }
45 |
46 | // Encode is the generic encoder for a Codec, all can be encoded with it.
47 | func Encode(d Codec) (s *splice.Splice) {
48 | s = splice.New(d.Len())
49 | fails(d.Encode(s))
50 | return
51 | }
52 |
--------------------------------------------------------------------------------
/pkg/codec/onion/cores/balance/balance_test.go:
--------------------------------------------------------------------------------
1 | package balance
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/ont"
6 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
7 | "git.indra-labs.org/dev/ind/pkg/util/ci"
8 | "testing"
9 |
10 | "github.com/lightningnetwork/lnd/lnwire"
11 |
12 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
13 | )
14 |
15 | func TestOnions_Balance(t *testing.T) {
16 | ci.TraceIfNot()
17 | id := nonce.NewID()
18 | sats := lnwire.MilliSatoshi(10000)
19 | on := ont.Assemble([]ont.Onion{New(id, sats)})
20 | s := codec.Encode(on)
21 | s.SetCursor(0)
22 | var onc codec.Codec
23 | if onc = reg.Recognise(s); onc == nil {
24 | t.Error("did not unwrap")
25 | t.FailNow()
26 | }
27 | if e := onc.Decode(s); fails(e) {
28 | t.Error("did not decode")
29 | t.FailNow()
30 | }
31 | var ci *Balance
32 | var ok bool
33 | if ci, ok = onc.(*Balance); !ok {
34 | t.Error("did not unwrap expected type")
35 | t.FailNow()
36 | }
37 | if ci.ID != id {
38 | t.Error("Keys did not decode correctly")
39 | t.FailNow()
40 | }
41 | if ci.MilliSatoshi != sats {
42 | t.Error("amount did not decode correctly")
43 | t.FailNow()
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/pkg/codec/onion/cores/confirmation/confirmation_test.go:
--------------------------------------------------------------------------------
1 | package confirmation
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/ont"
6 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
7 | "git.indra-labs.org/dev/ind/pkg/util/ci"
8 | "testing"
9 |
10 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
11 | )
12 |
13 | func TestOnions_Confirmation(t *testing.T) {
14 | ci.TraceIfNot()
15 | id := nonce.NewID()
16 | on := ont.Assemble([]ont.Onion{New(id)})
17 | s := codec.Encode(on)
18 | s.SetCursor(0)
19 | var onc codec.Codec
20 | if onc = reg.Recognise(s); onc == nil {
21 |
22 | t.Error("did not unwrap")
23 | t.FailNow()
24 | }
25 | if e := onc.Decode(s); fails(e) {
26 | t.Error("did not decode")
27 | t.FailNow()
28 | }
29 | var ci *Confirmation
30 | var ok bool
31 | if ci, ok = onc.(*Confirmation); !ok {
32 | t.Error("did not unwrap expected type")
33 | t.FailNow()
34 | }
35 | if ci.ID != id {
36 | t.Error("Keys did not decode correctly")
37 | t.FailNow()
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/pkg/codec/onion/cores/end/template.go:
--------------------------------------------------------------------------------
1 | // Package end is a null tombstone type onion message that indicates there is no more data in the onion (used with encoding only).
2 | package end
3 |
4 | import (
5 | "git.indra-labs.org/dev/ind/pkg/codec"
6 | "git.indra-labs.org/dev/ind/pkg/codec/ont"
7 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
8 | "git.indra-labs.org/dev/ind/pkg/engine/sess"
9 | "git.indra-labs.org/dev/ind/pkg/engine/sessions"
10 | "git.indra-labs.org/dev/ind/pkg/util/splice"
11 | )
12 |
13 | const (
14 | Magic = "!!!!"
15 | Len = 0
16 | )
17 |
18 | type End struct{}
19 |
20 | func (x *End) Account(res *sess.Data, sm *sess.Manager,
21 | s *sessions.Data, last bool) (skip bool, sd *sessions.Data) {
22 | return
23 | }
24 |
25 | func (x *End) Decode(s *splice.Splice) (e error) { return }
26 | func (x *End) Encode(s *splice.Splice) (e error) { return }
27 | func EndGen() codec.Codec { return &End{} }
28 | func (x *End) Unwrap() interface{} { return x }
29 | func (x *End) Handle(s *splice.Splice, p ont.Onion, ni ont.Ngin) (e error) { return }
30 | func (x *End) Len() int {
31 |
32 | codec.MustNotBeNil(x)
33 |
34 | return Len
35 | }
36 | func (x *End) Magic() string { return Magic }
37 | func (x *End) Wrap(inner ont.Onion) {}
38 | func NewEnd() *End { return &End{} }
39 | func init() { reg.Register(Magic, EndGen) }
40 |
--------------------------------------------------------------------------------
/pkg/codec/onion/cores/response/response_test.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/onion/cores/end"
6 | "git.indra-labs.org/dev/ind/pkg/codec/ont"
7 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
8 | "testing"
9 |
10 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
11 | "git.indra-labs.org/dev/ind/pkg/crypto/sha256"
12 | "git.indra-labs.org/dev/ind/pkg/util/cryptorand"
13 | "git.indra-labs.org/dev/ind/pkg/util/slice"
14 | "git.indra-labs.org/dev/ind/pkg/util/tests"
15 | )
16 |
17 | func TestOnions_Response(t *testing.T) {
18 | var e error
19 | id := nonce.NewID()
20 | var msg slice.Bytes
21 | var hash sha256.Hash
22 | if msg, hash, e = tests.GenMessage(10000, ""); fails(e) {
23 | t.Error(e)
24 | t.FailNow()
25 | }
26 | port := uint16(cryptorand.IntN(65536))
27 | on := ont.Assemble([]ont.Onion{
28 | New(id, port, msg, 0),
29 | end.NewEnd(),
30 | })
31 | s := codec.Encode(on)
32 | s.SetCursor(0)
33 | var onc codec.Codec
34 | if onc = reg.Recognise(s); onc == nil {
35 | t.Error("did not unwrap")
36 | t.FailNow()
37 | }
38 | if e = onc.Decode(s); fails(e) {
39 | t.Error("did not decode")
40 | t.FailNow()
41 | }
42 | var rs *Response
43 | var ok bool
44 | if rs, ok = onc.(*Response); !ok {
45 | t.Error("did not unwrap expected type")
46 | t.FailNow()
47 | }
48 | plH := sha256.Single(rs.Bytes)
49 | if plH != hash {
50 | t.Errorf("exit message did not unwrap correctly")
51 | t.FailNow()
52 | }
53 | if rs.ID != id {
54 | t.Error("Keys did not decode correctly")
55 | t.FailNow()
56 | }
57 | if rs.Port != port {
58 | t.Error("port did not decode correctly")
59 | t.FailNow()
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/pkg/codec/onion/crypt/crypt_test.go:
--------------------------------------------------------------------------------
1 | package crypt
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/onion/cores/confirmation"
6 | "git.indra-labs.org/dev/ind/pkg/codec/ont"
7 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
8 | "git.indra-labs.org/dev/ind/pkg/util/ci"
9 | "testing"
10 |
11 | "git.indra-labs.org/dev/ind/pkg/crypto"
12 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
13 | )
14 |
15 | func TestOnions_SimpleCrypt(t *testing.T) {
16 | ci.TraceIfNot()
17 | var e error
18 | n := nonce.NewID()
19 | n1 := nonce.New()
20 | prv1, prv2 := crypto.GetTwoPrvKeys()
21 | pub1, pub2 := crypto.DerivePub(prv1), crypto.DerivePub(prv2)
22 | on := ont.Assemble([]ont.Onion{
23 | New(pub1, pub2, prv2, n1, 0),
24 | confirmation.New(n),
25 | })
26 | s := codec.Encode(on)
27 | s.SetCursor(0)
28 | log.D.S("encoded, encrypted onion:\n", s.GetAll().ToBytes())
29 | var oncr codec.Codec
30 | if oncr = reg.Recognise(s); oncr == nil {
31 | t.Error("did not unwrap")
32 | t.FailNow()
33 | }
34 | if e = oncr.Decode(s); fails(e) {
35 | t.Error("did not decode")
36 | t.FailNow()
37 | }
38 | oncr.(*Crypt).Decrypt(prv1, s)
39 | var oncn codec.Codec
40 | if oncn = reg.Recognise(s); oncn == nil {
41 | t.Error("did not unwrap")
42 | t.FailNow()
43 | }
44 | if e = oncn.Decode(s); fails(e) {
45 | t.Error("did not decode")
46 | t.FailNow()
47 | }
48 | if cn, ok := oncn.(*confirmation.Confirmation); !ok {
49 | t.Error("did not get expected confirmation")
50 | t.FailNow()
51 | } else {
52 | if cn.ID != n {
53 | t.Error("did not get expected confirmation Keys")
54 | t.FailNow()
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/pkg/codec/onion/delay/delay_test.go:
--------------------------------------------------------------------------------
1 | package delay
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/ont"
6 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
7 | "git.indra-labs.org/dev/ind/pkg/util/ci"
8 | "testing"
9 | "time"
10 | )
11 |
12 | func TestOnions_Delay(t *testing.T) {
13 | ci.TraceIfNot()
14 | dur := time.Second
15 | on := ont.Assemble([]ont.Onion{New(dur)})
16 | s := codec.Encode(on)
17 | s.SetCursor(0)
18 | var onc codec.Codec
19 | if onc = reg.Recognise(s); onc == nil {
20 | t.Error("did not unwrap")
21 | t.FailNow()
22 | }
23 | if e := onc.Decode(s); fails(e) {
24 | t.Error("did not decode")
25 | t.FailNow()
26 |
27 | }
28 | var dl *Delay
29 | var ok bool
30 | if dl, ok = onc.(*Delay); !ok {
31 | t.Error("did not decode expected type")
32 | t.FailNow()
33 | }
34 | if dl.Duration != dur {
35 | t.Error("did not unwrap expected duration")
36 | t.FailNow()
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/pkg/codec/onion/exit/exit_test.go:
--------------------------------------------------------------------------------
1 | package exit
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/ont"
6 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
7 | "math/rand"
8 | "testing"
9 |
10 | "git.indra-labs.org/dev/ind/pkg/crypto"
11 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
12 | "git.indra-labs.org/dev/ind/pkg/crypto/sha256"
13 | "git.indra-labs.org/dev/ind/pkg/engine/sessions"
14 | "git.indra-labs.org/dev/ind/pkg/util/slice"
15 | "git.indra-labs.org/dev/ind/pkg/util/tests"
16 | )
17 |
18 | func TestOnions_Exit(t *testing.T) {
19 | var e error
20 | prvs, pubs := crypto.GetCipherSet()
21 | ciphers := crypto.GenCiphers(prvs, pubs)
22 | var msg slice.Bytes
23 | var hash sha256.Hash
24 | if msg, hash, e = tests.GenMessage(512, "aoeu"); fails(e) {
25 | t.Error(e)
26 | t.FailNow()
27 | }
28 | n3 := crypto.Gen3Nonces()
29 | p := uint16(rand.Uint32())
30 | id := nonce.NewID()
31 | ep := &ExitPoint{
32 | Routing: &Routing{
33 | Sessions: [3]*sessions.Data{},
34 | Keys: prvs,
35 | Nonces: n3,
36 | },
37 | ReturnPubs: pubs,
38 | }
39 | on := ont.Assemble([]ont.Onion{New(id, p, msg, ep)})
40 | s := codec.Encode(on)
41 | s.SetCursor(0)
42 | var onc codec.Codec
43 | if onc = reg.Recognise(s); onc == nil {
44 | t.Error("did not unwrap")
45 | t.FailNow()
46 | }
47 | if e = onc.Decode(s); fails(e) {
48 | t.Error("did not decode")
49 | t.FailNow()
50 | }
51 | var ex *Exit
52 | var ok bool
53 | if ex, ok = onc.(*Exit); !ok {
54 | t.Error("did not unwrap expected type")
55 | t.FailNow()
56 | }
57 | if ex.ID != id {
58 | t.Error("Keys did not decode correctly")
59 | t.FailNow()
60 | }
61 | for i := range ex.Ciphers {
62 | if ex.Ciphers[i] != ciphers[i] {
63 | t.Errorf("cipher %d did not unwrap correctly", i)
64 | t.FailNow()
65 | }
66 | }
67 | for i := range ex.Nonces {
68 | if ex.Nonces[i] != n3[i] {
69 | t.Errorf("nonce %d did not unwrap correctly", i)
70 | t.FailNow()
71 | }
72 | }
73 | plH := sha256.Single(ex.Bytes)
74 | if plH != hash {
75 | t.Errorf("exit message did not unwrap correctly")
76 | t.FailNow()
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/pkg/codec/onion/forward/forward_test.go:
--------------------------------------------------------------------------------
1 | package forward
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/ont"
6 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
7 | "git.indra-labs.org/dev/ind/pkg/util/ci"
8 | "git.indra-labs.org/dev/ind/pkg/util/multi"
9 | "github.com/multiformats/go-multiaddr"
10 | "math/rand"
11 | "net"
12 | "net/netip"
13 | "reflect"
14 | "testing"
15 |
16 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
17 | )
18 |
19 | func TestOnions_Forward(t *testing.T) {
20 | ci.TraceIfNot()
21 | ipSizes := []int{net.IPv6len, net.IPv4len}
22 | for i := range ipSizes {
23 | n := nonce.New()
24 | ip := net.IP(n[:ipSizes[i]])
25 | var adr netip.Addr
26 | if ipSizes[i] == net.IPv4len {
27 | ip = ip.To4()
28 | }
29 | if ipSizes[i] == net.IPv6len {
30 | ip = ip.To16()
31 | }
32 | var ok bool
33 | if adr, ok = netip.AddrFromSlice(ip); !ok {
34 | t.Error("unable to get netip.Addrs")
35 | t.FailNow()
36 | }
37 | port := uint16(rand.Uint32())
38 | ap := netip.AddrPortFrom(adr, port)
39 | var ma multiaddr.Multiaddr
40 | var e error
41 | if ma, e = multi.AddrFromAddrPort(ap); fails(e) {
42 | t.FailNow()
43 | }
44 | log.D.S("ma", ma)
45 | on := ont.Assemble([]ont.Onion{New(ma)})
46 | s := codec.Encode(on)
47 | log.D.S("forward", s.GetAll().ToBytes())
48 | s.SetCursor(0)
49 | var onr codec.Codec
50 | if onr = reg.Recognise(s); onr == nil {
51 | t.Error("did not unwrap")
52 | t.FailNow()
53 | }
54 | if e := onr.Decode(s); fails(e) {
55 | t.Error("did not decode")
56 | t.FailNow()
57 |
58 | }
59 | var cf *Forward
60 | if cf, ok = onr.(*Forward); !ok {
61 | t.Error("did not unwrap expected type expected *Forward got",
62 | reflect.TypeOf(onr))
63 | t.FailNow()
64 | }
65 | if cf.Multiaddr.String() != ma.String() {
66 | t.Error("reverse Addresses did not unwrap correctly")
67 | t.FailNow()
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/pkg/codec/onion/getbalance/getbalance_test.go:
--------------------------------------------------------------------------------
1 | package getbalance
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/onion/exit"
6 | "git.indra-labs.org/dev/ind/pkg/codec/ont"
7 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
8 | "testing"
9 |
10 | "git.indra-labs.org/dev/ind/pkg/crypto"
11 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
12 | "git.indra-labs.org/dev/ind/pkg/engine/sessions"
13 | )
14 |
15 | func TestOnions_GetBalance(t *testing.T) {
16 | var e error
17 | n3 := crypto.Gen3Nonces()
18 | id := nonce.NewID()
19 | _, ks, _ := crypto.NewSigner()
20 | var prvs crypto.Privs
21 | for i := range prvs {
22 | prvs[i] = ks.Next()
23 | }
24 | var pubs crypto.Pubs
25 | for i := range pubs {
26 | pubs[i] = crypto.DerivePub(prvs[i])
27 | }
28 | ep := &exit.ExitPoint{
29 | Routing: &exit.Routing{
30 | Sessions: [3]*sessions.Data{},
31 | Keys: prvs,
32 | Nonces: n3,
33 | },
34 | ReturnPubs: pubs,
35 | }
36 | on := ont.Assemble([]ont.Onion{NewGetBalance(id, ep)})
37 | s := codec.Encode(on)
38 | s.SetCursor(0)
39 | var onc codec.Codec
40 | if onc = reg.Recognise(s); onc == nil {
41 | t.Error("did not unwrap")
42 | t.FailNow()
43 | }
44 | if e = onc.Decode(s); fails(e) {
45 | t.Error("did not decode")
46 | t.FailNow()
47 | }
48 | var ex *GetBalance
49 | var ok bool
50 | if ex, ok = onc.(*GetBalance); !ok {
51 | t.Error("did not unwrap expected type")
52 | t.FailNow()
53 | }
54 | if ex.ID != id {
55 | t.Error("Keys did not decode correctly")
56 | t.FailNow()
57 | }
58 | for i := range ex.Ciphers {
59 | if ex.Ciphers[i] != on.(*GetBalance).Ciphers[i] {
60 | t.Errorf("cipher %d did not unwrap correctly", i)
61 | t.FailNow()
62 | }
63 | }
64 | for i := range ex.Nonces {
65 | if ex.Nonces[i] != n3[i] {
66 | t.Errorf("nonce %d did not unwrap correctly", i)
67 | t.FailNow()
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/pkg/codec/onion/hidden/introquery/introquery_test.go:
--------------------------------------------------------------------------------
1 | package introquery
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/onion/cores/end"
6 | "git.indra-labs.org/dev/ind/pkg/codec/onion/exit"
7 | "git.indra-labs.org/dev/ind/pkg/codec/ont"
8 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
9 | "git.indra-labs.org/dev/ind/pkg/util/ci"
10 | "testing"
11 |
12 | "git.indra-labs.org/dev/ind/pkg/crypto"
13 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
14 | "git.indra-labs.org/dev/ind/pkg/engine/sessions"
15 | )
16 |
17 | func TestOnions_IntroQuery(t *testing.T) {
18 | ci.TraceIfNot()
19 | var e error
20 | prvs, pubs := crypto.GetCipherSet()
21 | ciphers := crypto.GenCiphers(prvs, pubs)
22 | prv1, _ := crypto.GetTwoPrvKeys()
23 | pub1 := crypto.DerivePub(prv1)
24 | n3 := crypto.Gen3Nonces()
25 | ep := &exit.ExitPoint{
26 | Routing: &exit.Routing{
27 | Sessions: [3]*sessions.Data{},
28 | Keys: prvs,
29 | Nonces: n3,
30 | },
31 | ReturnPubs: pubs,
32 | }
33 | id := nonce.NewID()
34 | on := ont.Assemble([]ont.Onion{
35 | New(id, crypto.DerivePub(prv1), ep),
36 | end.NewEnd(),
37 | })
38 | s := codec.Encode(on)
39 | s.SetCursor(0)
40 | var onc codec.Codec
41 | if onc = reg.Recognise(s); onc == nil {
42 | t.Error("did not unwrap")
43 | t.FailNow()
44 | }
45 | if e = onc.Decode(s); fails(e) {
46 | t.Error("did not decode")
47 | t.FailNow()
48 | }
49 | log.D.Ln(s)
50 | var ex *IntroQuery
51 | var ok bool
52 | if ex, ok = onc.(*IntroQuery); !ok {
53 | t.Error("did not unwrap expected type")
54 | t.FailNow()
55 | }
56 | for i := range ex.Ciphers {
57 | if ex.Ciphers[i] != ciphers[i] {
58 | t.Errorf("cipher %d did not unwrap correctly", i)
59 | t.FailNow()
60 | }
61 | }
62 | for i := range ex.Nonces {
63 | if ex.Nonces[i] != n3[i] {
64 | t.Errorf("nonce %d did not unwrap correctly", i)
65 | t.FailNow()
66 | }
67 | }
68 | if !ex.Key.Equals(pub1) {
69 | t.Error("HiddenService did not decode correctly")
70 | t.FailNow()
71 | }
72 | if ex.ID != id {
73 | t.Error("Keys did not decode correctly")
74 | t.FailNow()
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/pkg/codec/onion/hidden/whisper/whisper_test.go:
--------------------------------------------------------------------------------
1 | package whisper
2 |
--------------------------------------------------------------------------------
/pkg/codec/onion/reverse/reverse_test.go:
--------------------------------------------------------------------------------
1 | package reverse
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/ont"
6 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
7 | "git.indra-labs.org/dev/ind/pkg/util/ci"
8 | "git.indra-labs.org/dev/ind/pkg/util/multi"
9 | "github.com/multiformats/go-multiaddr"
10 | "math/rand"
11 | "net"
12 | "net/netip"
13 | "reflect"
14 | "testing"
15 |
16 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
17 | )
18 |
19 | func TestOnions_Reverse(t *testing.T) {
20 | ci.TraceIfNot()
21 | ipSizes := []int{net.IPv4len, net.IPv6len}
22 | for i := range ipSizes {
23 | n := nonce.New()
24 | ip := net.IP(n[:ipSizes[i]])
25 | var adr netip.Addr
26 | if ipSizes[i] == net.IPv4len {
27 | ip = ip.To4()
28 | }
29 | if ipSizes[i] == net.IPv6len {
30 | ip = ip.To16()
31 | }
32 | var ok bool
33 | if adr, ok = netip.AddrFromSlice(ip); !ok {
34 | t.Error("unable to get netip.Addrs")
35 | t.FailNow()
36 | }
37 | port := uint16(rand.Uint32())
38 | ap := netip.AddrPortFrom(adr, port)
39 | var ma multiaddr.Multiaddr
40 | var e error
41 | if ma, e = multi.AddrFromAddrPort(ap); fails(e) {
42 | t.FailNow()
43 | }
44 | on := ont.Assemble([]ont.Onion{New(ma)})
45 | s := codec.Encode(on)
46 | s.SetCursor(0)
47 | var onr codec.Codec
48 | if onr = reg.Recognise(s); onr == nil {
49 | t.Error("did not unwrap")
50 | t.FailNow()
51 | }
52 | if e := onr.Decode(s); fails(e) {
53 | t.Error("did not decode")
54 | t.FailNow()
55 |
56 | }
57 | var cf *Reverse
58 | if cf, ok = onr.(*Reverse); !ok {
59 | t.Error("did not unwrap expected type expected *Return got",
60 | reflect.TypeOf(onr))
61 | t.FailNow()
62 | }
63 | if cf.Multiaddr.String() != ma.String() {
64 | log.I.S(cf.Multiaddr, ap)
65 | t.Error("reverse Addresses did not unwrap correctly")
66 | t.FailNow()
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/pkg/codec/onion/session/session_test.go:
--------------------------------------------------------------------------------
1 | package session
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/reg"
6 | "git.indra-labs.org/dev/ind/pkg/util/ci"
7 | "testing"
8 | )
9 |
10 | func TestOnions_Session(t *testing.T) {
11 | ci.TraceIfNot()
12 | sess := New(1)
13 | ss := sess.(*Session)
14 | s := codec.Encode(sess)
15 | s.SetCursor(0)
16 | var onc codec.Codec
17 | if onc = reg.Recognise(s); onc == nil {
18 | t.Error("did not unwrap")
19 | t.FailNow()
20 | }
21 | if e := onc.Decode(s); fails(e) {
22 | t.Error("did not decode")
23 | t.FailNow()
24 |
25 | }
26 | var ci *Session
27 | var ok bool
28 | if ci, ok = onc.(*Session); !ok {
29 | t.Error("did not unwrap expected type")
30 | t.FailNow()
31 | }
32 | if !ci.Header.Prv.Equals(ss.Header.Prv) {
33 | t.Error("header key did not unwrap correctly")
34 | t.FailNow()
35 | }
36 | if !ci.Payload.Prv.Equals(ss.Payload.Prv) {
37 | t.Error("payload key did not unwrap correctly")
38 | t.FailNow()
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/crypto/ciph/cipher.go:
--------------------------------------------------------------------------------
1 | // Package ciph manages encryption ciphers and encrypting blobs of data. Keys
2 | // are generated using ECDH from a public and private secp256k1 combined, as
3 | // well as directly from a 32 byte secret in the form of a static array as used
4 | // in most cryptographic hash function implementations in Go.
5 | package ciph
6 |
7 | import (
8 | "crypto/aes"
9 | "crypto/cipher"
10 | "git.indra-labs.org/dev/ind/pkg/crypto"
11 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
12 | "git.indra-labs.org/dev/ind/pkg/crypto/sha256"
13 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
14 | )
15 |
16 | var (
17 | log = log2.GetLogger()
18 | fails = log.E.Chk
19 | )
20 |
21 | // BlockFromHash creates an AES block cipher from an sha256.Hash.
22 | func BlockFromHash(h sha256.Hash) (block cipher.Block) {
23 |
24 | // We can ignore the error because sha256.Hash is a valid key size.
25 | block, _ = aes.NewCipher(h[:])
26 | return
27 | }
28 |
29 | // Encipher XORs the data with the block stream. This encrypts unencrypted data
30 | // and decrypts encrypted data. If the cipher.Block is nil, it panics (this
31 | // should never happen).
32 | func Encipher(blk cipher.Block, n nonce.IV, b []byte) {
33 |
34 | if blk == nil {
35 | panic("Encipher called without a block cipher provided")
36 |
37 | } else {
38 | cipher.NewCTR(blk, n[:]).XORKeyStream(b, b)
39 |
40 | }
41 | }
42 |
43 | // GetBlock returns a block cipher with a secret generated from the provided
44 | // keys using ECDH.
45 | func GetBlock(from *crypto.Prv, to *crypto.Pub) (block cipher.Block) {
46 |
47 | secret := crypto.ComputeSharedSecret(from, to)
48 |
49 | block, _ = aes.NewCipher(secret[:])
50 |
51 | return
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/crypto/cloaked_test.go:
--------------------------------------------------------------------------------
1 | package crypto
2 |
3 | import (
4 | "math/rand"
5 | "testing"
6 | "time"
7 | )
8 |
9 | func TestCloakedPubKey(t *testing.T) {
10 | var e error
11 | var sendPriv *Prv
12 | if sendPriv, e = GeneratePrvKey(); fails(e) {
13 | return
14 | }
15 | sendPub := DerivePub(sendPriv)
16 | sendBytes := sendPub.ToBytes()
17 | var cloaked CloakedPubKey
18 | cloaked = GetCloak(sendPub)
19 | if !Match(cloaked, sendBytes) {
20 | t.Error("failed to recognise cloaked address")
21 | }
22 | rand.Seed(time.Now().Unix())
23 | flip := rand.Intn(CloakLen)
24 | var broken CloakedPubKey
25 | copy(broken[:], cloaked[:])
26 | broken[flip] = ^broken[flip]
27 | if Match(broken, sendBytes) {
28 | t.Error("recognised incorrectly broken cloaked address")
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/crypto/crypto_test.go:
--------------------------------------------------------------------------------
1 | package crypto
2 |
3 | import (
4 | rand2 "crypto/rand"
5 | "git.indra-labs.org/dev/ind/pkg/util/ci"
6 | "testing"
7 |
8 | "git.indra-labs.org/dev/ind/pkg/crypto/sha256"
9 | )
10 |
11 | func TestFromBased32(t *testing.T) {
12 | ci.TraceIfNot()
13 | var rBytes sha256.Hash
14 | var n int
15 | var e error
16 | if n, e = rand2.Read(rBytes[:]); n != 8 && fails(e) {
17 | t.FailNow()
18 | }
19 | var pr *Prv
20 | if pr, e = GeneratePrvKey(); fails(e) {
21 | t.FailNow()
22 | }
23 | for i := 0; i < 1<<16; i++ {
24 | var s SigBytes
25 | if s, e = Sign(pr, rBytes); fails(e) {
26 | t.FailNow()
27 | }
28 | // fmt.Println("sig", s)
29 | var sb SigBytes
30 | if sb, e = SigFromBased32(s.String()); fails(e) {
31 | t.FailNow()
32 | }
33 | if s != sb {
34 | t.Error("sig mismatch")
35 | t.FailNow()
36 | }
37 | rBytes = sha256.Single(rBytes[:])
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/pkg/crypto/doc.go:
--------------------------------------------------------------------------------
1 | // Package crypto contains all the cryptographic primitives used in Indra.
2 | //
3 | // There is the standard public/private keys, signature and validation functions, cloaked public keys used in message and packets.
4 | //
5 | // A set of implementations of these primitives based on the above are present for implementing interfaces to use them with libp2p.
6 | //
7 | // A set of helper functions for frequently used operations involving multiple items or derivations are here also.
8 | package crypto
9 |
--------------------------------------------------------------------------------
/pkg/crypto/nonce/id.go:
--------------------------------------------------------------------------------
1 | package nonce
2 |
3 | import (
4 | "crypto/rand"
5 | "encoding/base32"
6 | "git.indra-labs.org/dev/ind/pkg/crypto/sha256"
7 | "git.indra-labs.org/dev/ind/pkg/util/b32"
8 | "sync"
9 | )
10 |
11 | const IDLen = 8
12 |
13 | var (
14 | counter uint16
15 | // enc is a raw base32 encoder as IDs have a consistent set of extraneous
16 | // characters after 13 digits and do not need check bytes as they are compact
17 | // large numbers used as collision resistant nonces to identify items in lists.
18 | enc = base32.NewEncoding(b32.Based32Ciphers).EncodeToString
19 | idMx sync.Mutex
20 | seed sha256.Hash
21 | )
22 |
23 | // ID is a value generated by the first 8 bytes truncated from the values of a
24 | // hash chain that reseeds from a CSPRNG at first use and every time it
25 | // generates 2^16 (65536) new ID's.
26 | type ID [IDLen]byte
27 |
28 | // NewID returns a random 8 byte nonce to be used as identifiers.
29 | func NewID() (t ID) {
30 | idMx.Lock()
31 | defer idMx.Unlock()
32 | if counter == 0 {
33 | // We reseed when the counter value overflows.
34 | reseed()
35 | }
36 | s := sha256.Single(seed[:])
37 | copy(seed[:], s[:])
38 | copy(t[:], seed[:IDLen])
39 | counter++
40 | return
41 | }
42 |
43 | // String encodes the ID using Based32.
44 | func (id ID) String() string {
45 | return enc(id[:])[:13]
46 | }
47 |
48 | func reseed() {
49 | if c, e := rand.Read(seed[:]); fails(e) && c != IDLen {
50 | }
51 | counter++
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/crypto/nonce/nonce.go:
--------------------------------------------------------------------------------
1 | // Package nonce provides a simple interface for generating standard AES
2 | // encryption nonces that give strong cryptographic entropy to message
3 | // encryption, as well as 8 byte (64 bit) random private identifiers for
4 | // references between types.
5 | package nonce
6 |
7 | import (
8 | "crypto/aes"
9 | "crypto/rand"
10 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
11 | )
12 |
13 | // IVLen is the length of Initialization Vectors used in Indra.
14 | const IVLen = aes.BlockSize
15 |
16 | var (
17 | log = log2.GetLogger()
18 | fails = log.E.Chk
19 | )
20 |
21 | // IV is an Initialization Vector for AES-CTR encryption used in Indra.
22 | type IV [IVLen]byte
23 |
24 | // New reads a nonce from a cryptographically secure random number source.
25 | func New() (n IV) {
26 | if c, e := rand.Read(n[:]); fails(e) && c != IDLen {
27 | }
28 | return
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/crypto/public_test.go:
--------------------------------------------------------------------------------
1 | package crypto
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/util/ci"
5 | "testing"
6 | )
7 |
8 | func TestBase32(t *testing.T) {
9 | ci.TraceIfNot()
10 | for i := 0; i < 10000; i++ {
11 | var k *Prv
12 | var e error
13 | if k, e = GeneratePrvKey(); fails(e) {
14 | t.Error(e)
15 | t.FailNow()
16 | }
17 | p := DerivePub(k)
18 | b32 := p.ToBased32()
19 | pr32 := k.ToBased32()
20 | // log.D.F("pub key: %d %s priv key: %d %s\n", len(b32), b32, len(pr32), pr32)
21 | var kk *Pub
22 | if kk, e = PubFromBased32(b32); fails(e) {
23 | t.Error(e)
24 | t.FailNow()
25 | }
26 | if b32 != kk.ToBased32() {
27 | t.Error("failed to decode public key")
28 | t.FailNow()
29 | }
30 | var pk *Prv
31 | if pk, e = PrvFromBased32(pr32); fails(e) {
32 | t.Error(e)
33 | t.FailNow()
34 | }
35 | if pr32 != pk.ToBased32() {
36 | t.Error("failed to decode private key")
37 | t.FailNow()
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/crypto/sha256/sha256.go:
--------------------------------------------------------------------------------
1 | // Package sha256 provides a simple interface for single and double SHA256
2 | // hashes, used with secp256k1 signatures, message digest checksums, cloaked
3 | // public key "addresses" and so on.
4 | package sha256
5 |
6 | import (
7 | "encoding/base32"
8 | "encoding/hex"
9 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
10 | "git.indra-labs.org/dev/ind/pkg/util/b32"
11 | "github.com/minio/sha256-simd"
12 | )
13 |
14 | // Len is the number of bytes in a sha256 hash.
15 | const Len = 32
16 |
17 | var (
18 | // enc is a raw base32 encoder as 256-bit hashes have a consistent set of
19 | // extraneous characters after 52 digits from padding and do not need check
20 | // bytes as they are compact large numbers for logs and message digests for
21 | // other things.
22 | enc = base32.NewEncoding(b32.Based32Ciphers).EncodeToString
23 | log = log2.GetLogger()
24 | fails = log.E.Chk
25 | )
26 |
27 | // String returns the hex encoded form of a SHA256 hash.
28 | func (h Hash) String() string {
29 | return hex.EncodeToString(h[:])
30 | }
31 |
32 | // Based32String returns the Basde32 encoded form of a SHA256 hash.
33 | func (h Hash) Based32String() string {
34 | return enc(h[:])[:52]
35 | }
36 |
37 | // Hash is just a 256-bit hash.
38 | type Hash [32]byte
39 |
40 | // Double runs a standard double SHA256 hash and does all the slicing for you.
41 | func Double(b []byte) Hash {
42 | h := Single(b)
43 | return Single(h[:])
44 | }
45 |
46 | // New creates a correctly sized slice for a Hash.
47 | func New() Hash { return Hash{} }
48 |
49 | // Single runs a standard SHA256 hash.
50 | func Single(b []byte) Hash { return sha256.Sum256(b) }
51 |
52 | // Zero copies a cleanly initialised empty slice over top of the provided Hash.
53 | func Zero(h Hash) { copy(h[:], zero()) }
54 |
55 | // Zero out the values in the hash. Hashes can be used as secrets.
56 | func (h Hash) Zero() { Zero(h) }
57 |
58 | func zero() []byte { return make([]byte, Len) }
59 |
--------------------------------------------------------------------------------
/pkg/crypto/sha256/sha256_test.go:
--------------------------------------------------------------------------------
1 | package sha256
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestHash_Equals(t *testing.T) {
8 | var h1, h2 Hash
9 | if h1 != h2 {
10 | t.FailNow()
11 | }
12 | h2[0] = 1
13 | if h1 == h2 {
14 | t.FailNow()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/pkg/crypto/signature_test.go:
--------------------------------------------------------------------------------
1 | package crypto
2 |
3 | // commenting out with change to schnorr and non-key-embedded signatures
4 |
5 | //func TestSignRecover(t *testing.T) {
6 | // msgSize := mrand.Intn(3072) + 1024
7 | // payload := make([]byte, msgSize)
8 | // var e error
9 | // var n int
10 | // if n, e = rand.Read(payload); log.E.Chk(e) && n != msgSize {
11 | // t.Error(e)
12 | // }
13 | // var prv1 *Prv
14 | // var pub1, rec1 *Pub
15 | // if prv1, e = GeneratePrvKey(); fails(e) {
16 | // t.Error(e)
17 | // }
18 | // pub1 = DerivePub(prv1)
19 | // var s SigBytes
20 | // hash := sha256.Single(payload)
21 | // if s, e = Sign(prv1, hash); fails(e) {
22 | // t.Error(e)
23 | // }
24 | // if rec1, e = s.Recover(hash); fails(e) {
25 | // t.Error(e)
26 | // }
27 | // if !pub1.Equals(rec1) {
28 | // t.Error(errors.New("recovery did not extract same key"))
29 | // }
30 | //}
31 |
32 | //func TestSignRecoverFail(t *testing.T) {
33 | // msgSize := mrand.Intn(3072) + 1024
34 | // payload := make([]byte, msgSize)
35 | // var e error
36 | // var n int
37 | // if n, e = rand.Read(payload); log.E.Chk(e) && n != msgSize {
38 | // t.Error(e)
39 | // }
40 | // var prv1 *Prv
41 | // var pub1, rec1 *Pub
42 | // if prv1, e = GeneratePrvKey(); fails(e) {
43 | // t.Error(e)
44 | // }
45 | // pub1 = DerivePub(prv1)
46 | // var s SigBytes
47 | // hash := sha256.Single(payload)
48 | // if s, e = Sign(prv1, hash); fails(e) {
49 | // t.Error(e)
50 | // }
51 | // copy(payload, make([]byte, 10))
52 | // hash2 := sha256.Single(payload)
53 | // if rec1, e = s.Recover(hash2); fails(e) {
54 | // t.Error(e)
55 | // }
56 | // if pub1.Equals(rec1) {
57 | // t.Error(errors.New("recovery extracted the same key"))
58 | // }
59 | //}
60 |
--------------------------------------------------------------------------------
/pkg/crypto/signer_test.go:
--------------------------------------------------------------------------------
1 | package crypto
2 |
3 | import (
4 | "testing"
5 |
6 | "git.indra-labs.org/dev/ind/pkg/crypto/sha256"
7 | "git.indra-labs.org/dev/ind/pkg/util/tests"
8 | )
9 |
10 | // this just really demonstrates how the keys generated are not linkable.
11 | func TestKeySet_Next(t *testing.T) {
12 | var counter int
13 | const nRounds = 10000
14 | for rounds := 0; rounds < nRounds; rounds++ {
15 | key, ks, e := NewSigner()
16 | if fails(e) {
17 | t.FailNow()
18 | }
19 | var hx PubBytes
20 | if hx = DerivePub(key).ToBytes(); fails(e) {
21 | t.Error(e)
22 | }
23 | oddness := hx[0]
24 | // for i := 0; i < 100; i++ {
25 | key = ks.Next()
26 | if hx = DerivePub(key).ToBytes(); hx[0] == oddness {
27 | counter++
28 | }
29 | // }
30 | }
31 | if counter == nRounds || counter == 0 {
32 | t.Error("all keys same oddness", counter)
33 | }
34 | }
35 |
36 | func BenchmarkKeySet_Next(b *testing.B) {
37 | _, ks, e := NewSigner()
38 | if fails(e) {
39 | b.FailNow()
40 | }
41 | for n := 0; n < b.N; n++ {
42 | _ = ks.Next()
43 | }
44 | }
45 |
46 | func BenchmarkKeySet_Next_Derive(b *testing.B) {
47 | _, ks, e := NewSigner()
48 | if fails(e) {
49 | b.FailNow()
50 | }
51 | for n := 0; n < b.N; n++ {
52 | k := ks.Next()
53 | DerivePub(k)
54 | }
55 | }
56 |
57 | func BenchmarkKeySet_Next_Sign(b *testing.B) {
58 | _, ks, e := NewSigner()
59 | if fails(e) {
60 | b.FailNow()
61 | }
62 | var msg []byte
63 | const msgLen = 1382 - 4 - SigLen
64 | msg, _, e = tests.GenMessage(msgLen, "herpderp")
65 | for n := 0; n < b.N; n++ {
66 | k := ks.Next()
67 | hash := sha256.Single(msg)
68 | if _, e = Sign(k, hash); fails(e) {
69 | b.Error("failed to sign")
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/pkg/crypto/util.go:
--------------------------------------------------------------------------------
1 | package crypto
2 |
3 | // GenerateTestKeyPair generates a key pair.
4 | func GenerateTestKeyPair() (sp *Prv, sP *Pub, e error) {
5 | if sp, e = GeneratePrvKey(); fails(e) {
6 | return
7 | }
8 | sP = DerivePub(sp)
9 | return
10 | }
11 |
12 | // GenerateTestKeyPairs generates two public/private key pairs.
13 | func GenerateTestKeyPairs() (sp, rp *Prv, sP, rP *Pub, e error) {
14 | sp, sP, e = GenerateTestKeyPair()
15 | rp, rP, e = GenerateTestKeyPair()
16 | return
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/docker/config.go:
--------------------------------------------------------------------------------
1 | package docker
2 |
3 | import (
4 | "github.com/docker/docker/api/types"
5 | )
6 |
7 | type BuildConfiguration struct {
8 | Name string
9 | ContextFilePath string
10 | BuildOpts types.ImageBuildOptions
11 | PushOpts types.ImagePushOptions
12 | }
13 |
14 | // FixTagPrefix returns the full set of tags in the BuildConfiguration.
15 | func (bc *BuildConfiguration) FixTagPrefix() (fullTags []string) {
16 |
17 | for _, tag := range bc.BuildOpts.Tags {
18 |
19 | fullTags = append(fullTags, bc.Name+":"+tag)
20 | }
21 |
22 | return fullTags
23 | }
24 |
--------------------------------------------------------------------------------
/pkg/docker/doc.go:
--------------------------------------------------------------------------------
1 | // Package docker contains a library for building and pushing docker images for Indra to a configured docker repository.
2 | package docker
3 |
--------------------------------------------------------------------------------
/pkg/engine/acct.go:
--------------------------------------------------------------------------------
1 | package engine
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/onion/crypt"
6 | "git.indra-labs.org/dev/ind/pkg/codec/ont"
7 | "git.indra-labs.org/dev/ind/pkg/engine/sess"
8 | "git.indra-labs.org/dev/ind/pkg/engine/sessions"
9 | )
10 |
11 | // PostAcctOnion takes a slice of Skins and calculates their costs and
12 | // the list of sessions inside them and attaches accounting operations to
13 | // apply when the associated confirmation(s) or response hooks are executed.
14 | func PostAcctOnion(sm *sess.Manager, o Skins) (res *sess.Data) {
15 | res = &sess.Data{}
16 | assembled := ont.Assemble(o)
17 | sp := codec.Encode(assembled)
18 | res.B = sp.GetAll()
19 | // do client accounting
20 | skip := false
21 | var last bool
22 | for i := range o {
23 | if skip {
24 | skip = false
25 | continue
26 | }
27 | switch on := o[i].(type) {
28 | case *crypt.Crypt:
29 | if i == len(o)-1 {
30 | last = true
31 | }
32 | var s *sessions.Data
33 | skip, s = on.Account(res, sm, nil, last)
34 | if last {
35 | break
36 | }
37 | o[i+1].Account(res, sm, s, last)
38 | }
39 | }
40 | return
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/engine/consts/hiddenconst.go:
--------------------------------------------------------------------------------
1 | // Package consts is a series of constants common to several different onion message types.
2 | package consts
3 |
4 | import (
5 | "git.indra-labs.org/dev/ind/pkg/crypto"
6 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
7 | "git.indra-labs.org/dev/ind/pkg/engine/magic"
8 | "git.indra-labs.org/dev/ind/pkg/util/splice"
9 | )
10 |
11 | // ReverseCryptLen is
12 | //
13 | // Deprecated: this is now a variable length structure, Reverse is being
14 | // obsoleted in favour of Offset.
15 | const ReverseCryptLen = ReverseLen + CryptLen
16 |
17 | // RoutingHeaderLen is
18 | //
19 | // Deprecated: this is now a variable length structure.
20 | const RoutingHeaderLen = 3 * ReverseCryptLen
21 |
22 | const CryptLen = magic.Len +
23 | nonce.IVLen +
24 | crypto.CloakLen +
25 | crypto.PubKeyLen
26 |
27 | // ReverseLen is
28 | //
29 | // Deprecated: Reverse is being obsoleted in favour of Offset.
30 | const ReverseLen = magic.Len + 1 + splice.AddrLen
31 |
--------------------------------------------------------------------------------
/pkg/engine/dispatcher/doc.go:
--------------------------------------------------------------------------------
1 | // Package dispatcher is a network packet send/receive handler for peer to peer connections between relays.
2 | //
3 | // Messages between peers are usually somewhat large, multi-layered onion messages that contain forwarding instructions for sending, and the dispatcher breaks them down into uniform sized segments and randomises their order.
4 | //
5 | // On the receiving side, there is a buffer for incoming message segments, and when sufficient segments are received to enable reconstruction, reconstruction is attempted.
6 | //
7 | // Messages are broken up into pieces with additional segments added to ensure the receiver gets enough pieces to decode the message without a message retransmit request, using Reed Solomon encoding (accelerated by AVX).
8 | //
9 | // The dispatcher operates with reliable TCP connections, and does not directly influence retransmit but instead monitors the latency of the messages and identifies when there has been a retransmit and increases the redundant data added to the stream of message packet segments.
10 | //
11 | // In this way, the dispatcher aims to always see sufficient data arrive in one message cycle so to minimise the latency of connections between peers, and the subsequent latency of client's routed packets.
12 | //
13 | // Another feature of the dispatcher is key change processing - this is implemented as a concurrent update from the receiver specifying a new public key to use, it keeps the old key for a time to deal with in transit messages that were encrypted with the old key and the peer should update its key to use for all messages after the key has been received and updated.
14 | package dispatcher
15 |
--------------------------------------------------------------------------------
/pkg/engine/doc.go:
--------------------------------------------------------------------------------
1 | // Package engine is the implementation of the core Indra relay and client.
2 | //
3 | // Contains controlling code that interacts with the various subsystems of the engine such as the dispatcher, session manager, libp2p based peer to peer network transport and peer information gossip.
4 | package engine
5 |
--------------------------------------------------------------------------------
/pkg/engine/engine_test.go:
--------------------------------------------------------------------------------
1 | package engine
2 |
3 | // All broken currently because listeners don't have code to operate without a libp2p Host.
4 |
--------------------------------------------------------------------------------
/pkg/engine/magic/magic.go:
--------------------------------------------------------------------------------
1 | // Package magic is a simple specification and error helper for message identifying 4 byte strings that are used for the switching logic of a relay.
2 | package magic
3 |
4 | import "fmt"
5 |
6 | const (
7 | // Len is the length in bytes of the magic bytes that prefixes all Indra
8 | // messages.
9 | Len = 4
10 |
11 | // ErrTooShort is an error for codec.Codec implementations to signal a message
12 | // buffer is shorter than the minimum defined for the message type.
13 | ErrTooShort = "'%s' message minimum size: %d got: %d"
14 | )
15 |
16 | // TooShort is a helper function to return an error for a truncated packet.
17 | func TooShort(got, found int, magic string) (e error) {
18 | if got >= found {
19 | return
20 | }
21 | e = fmt.Errorf(ErrTooShort, magic, found, got)
22 | return
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/engine/packet/doc.go:
--------------------------------------------------------------------------------
1 | // Package packet handles segmenting messages into uniform sized packets and generating a stream of cipher halves and receiver cloaked addresses to encrypt them with, and reassembling the segments into the original messages.
2 | package packet
3 |
--------------------------------------------------------------------------------
/pkg/engine/packet/packet_test.go:
--------------------------------------------------------------------------------
1 | package packet
2 |
3 | import (
4 | "crypto/rand"
5 | "errors"
6 | "testing"
7 |
8 | "git.indra-labs.org/dev/ind/pkg/crypto"
9 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
10 | "git.indra-labs.org/dev/ind/pkg/crypto/sha256"
11 | )
12 |
13 | func TestEncode_Decode(t *testing.T) {
14 | msgSize := 1382
15 | payload := make([]byte, msgSize)
16 | var e error
17 | var n int
18 | if n, e = rand.Read(payload); fails(e) && n != msgSize {
19 | t.Error(e)
20 | }
21 | payload = append([]byte("payload"), payload...)
22 | pHash := sha256.Single(payload)
23 | var sp, rp *crypto.Prv
24 | var sP, rP *crypto.Pub
25 | if sp, rp, sP, rP, e = crypto.GenerateTestKeyPairs(); fails(e) {
26 | t.FailNow()
27 | }
28 | addr := rP
29 | var pkt []byte
30 | params := &PacketParams{
31 | To: addr,
32 | From: sp,
33 | Data: payload,
34 | Seq: 234,
35 | Parity: 64,
36 | Length: msgSize,
37 | }
38 | if pkt, e = EncodePacket(params); fails(e) {
39 | t.Error(e)
40 | }
41 | var from *crypto.Pub
42 | var to crypto.CloakedPubKey
43 | _ = to
44 | var iv nonce.IV
45 | if from, to, iv, e = GetKeysFromPacket(pkt); fails(e) {
46 | t.Error(e)
47 | }
48 | if !sP.ToBytes().Equals(from.ToBytes()) {
49 | t.Error(e)
50 | }
51 | var f *Packet
52 | if f, e = DecodePacket(pkt, from, rp, iv); fails(e) {
53 | t.Error(e)
54 | }
55 | dHash := sha256.Single(f.Data)
56 | if pHash != dHash {
57 | t.Error(errors.New("encode/decode unsuccessful"))
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/pkg/engine/packet/segcalc_test.go:
--------------------------------------------------------------------------------
1 | package packet
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | var Expected = []string{
9 | `
10 | Segments{
11 | Segment{ DStart: 0, DEnd: 192, PEnd: 256, SLen: 195, Last: 195},
12 | Segment{ DStart: 256, DEnd: 448, PEnd: 512, SLen: 195, Last: 195},
13 | Segment{ DStart: 512, DEnd: 704, PEnd: 768, SLen: 195, Last: 195},
14 | Segment{ DStart: 768, DEnd: 960, PEnd: 1024, SLen: 195, Last: 195},
15 | Segment{ DStart: 1024, DEnd: 1216, PEnd: 1280, SLen: 195, Last: 195},
16 | Segment{ DStart: 1280, DEnd: 1472, PEnd: 1536, SLen: 195, Last: 195},
17 | Segment{ DStart: 1536, DEnd: 1728, PEnd: 1792, SLen: 195, Last: 195},
18 | Segment{ DStart: 1792, DEnd: 1793, PEnd: 1794, SLen: 195, Last: 175},
19 | }
20 | `,
21 | `
22 | Segments{
23 | Segment{ DStart: 0, DEnd: 130, PEnd: 130, SLen: 4035, Last: 3773},
24 | }
25 | `,
26 | `
27 | Segments{
28 | Segment{ DStart: 0, DEnd: 128, PEnd: 256, SLen: 4035, Last: 4035},
29 | Segment{ DStart: 256, DEnd: 258, PEnd: 260, SLen: 4035, Last: 3773},
30 | }
31 | `,
32 | `
33 | Segments{
34 | Segment{ DStart: 0, DEnd: 65, PEnd: 65, SLen: 4035, Last: 3904},
35 | }
36 | `,
37 | }
38 |
39 | func TestNewSegments(t *testing.T) {
40 | msgSize := 2<<17 + 111
41 | segSize := 256
42 | s := NewSegments(msgSize, segSize, Overhead, 64)
43 | o := fmt.Sprint(s)
44 | if o != Expected[0] {
45 | t.Errorf(
46 | "Failed to correctly generate.\ngot:\n'%s'\nexpected:\n'%s'",
47 | o, Expected[0])
48 | }
49 | msgSize = 2 << 18
50 | segSize = 4096
51 | s = NewSegments(msgSize, segSize, Overhead, 0)
52 | o = fmt.Sprint(s)
53 | if o != Expected[1] {
54 | t.Errorf(
55 | "Failed to correctly generate.\ngot:\n%s\nexpected:\n%s",
56 | o, Expected[1])
57 | }
58 | s = NewSegments(msgSize, segSize, Overhead, 128)
59 | o = fmt.Sprint(s)
60 | if o != Expected[2] {
61 | t.Errorf(
62 | "Failed to correctly generate.\ngot:\n%s\nexpected:\n%s",
63 | o, Expected[2])
64 | }
65 | msgSize = 2 << 17
66 | segSize = 4096
67 | s = NewSegments(msgSize, segSize, Overhead, 0)
68 | o = fmt.Sprint(s)
69 | if o != Expected[3] {
70 | t.Errorf(
71 | "Failed to correctly generate.\ngot:\n%s\nexpected:\n%s",
72 | o, Expected[3])
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/pkg/engine/protocols/protocols.go:
--------------------------------------------------------------------------------
1 | package protocols
2 |
3 | type NetworkProtocols byte
4 |
5 | const (
6 | IP4 NetworkProtocols = 1
7 | IP6 NetworkProtocols = 1 << iota
8 | // add more here if any such thing of this kind can be used ???
9 | )
10 |
--------------------------------------------------------------------------------
/pkg/engine/reply.go:
--------------------------------------------------------------------------------
1 | package engine
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/codec"
5 | "git.indra-labs.org/dev/ind/pkg/codec/onion/exit"
6 | "git.indra-labs.org/dev/ind/pkg/codec/ont"
7 | "git.indra-labs.org/dev/ind/pkg/crypto"
8 | "git.indra-labs.org/dev/ind/pkg/engine/sessions"
9 | "git.indra-labs.org/dev/ind/pkg/hidden"
10 | )
11 |
12 | // MakeReplyHeader constructs a reply header for hidden service messages.
13 | func MakeReplyHeader(ng *Engine) (returnHeader *hidden.ReplyHeader) {
14 | n := crypto.GenNonces(3)
15 | rvKeys := ng.KeySet.Next3()
16 | hops := []byte{3, 4, 5}
17 | s := make(sessions.Sessions, len(hops))
18 | ng.Mgr().SelectHops(hops, s, "make message reply header")
19 | rt := &exit.Routing{
20 | Sessions: [3]*sessions.Data{s[0], s[1], s[2]},
21 | Keys: crypto.Privs{rvKeys[0], rvKeys[1], rvKeys[2]},
22 | Nonces: crypto.Nonces{n[0], n[1], n[2]},
23 | }
24 | rh := Skins{}.RoutingHeader(rt, ng.Mgr().Protocols)
25 | rHdr := codec.Encode(ont.Assemble(rh))
26 | rHdr.SetCursor(0)
27 | ep := exit.ExitPoint{
28 | Routing: rt,
29 | ReturnPubs: crypto.Pubs{
30 | crypto.DerivePub(s[0].Payload.Prv),
31 | crypto.DerivePub(s[1].Payload.Prv),
32 | crypto.DerivePub(s[2].Payload.Prv),
33 | },
34 | }
35 | returnHeader = &hidden.ReplyHeader{
36 | RoutingHeaderBytes: hidden.GetRoutingHeaderFromCursor(rHdr),
37 | Ciphers: crypto.GenCiphers(ep.Routing.Keys, ep.ReturnPubs),
38 | Nonces: ep.Routing.Nonces,
39 | }
40 | return
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/engine/sendgetbalance_test.go:
--------------------------------------------------------------------------------
1 | package engine
2 |
--------------------------------------------------------------------------------
/pkg/engine/services/services.go:
--------------------------------------------------------------------------------
1 | // Package services defines the base data structure for a service.
2 | //
3 | // This includes the port specification, the fee rate on the service, and the transport abstraction that opens a channel for messages to the service, or its listener depending on which side this structure is used.
4 | package services
5 |
6 | import "git.indra-labs.org/dev/ind/pkg/engine/tpt"
7 |
8 | type (
9 | // Service is a specification for a publicly accessible service available at a
10 | // relay.
11 | //
12 | // Through this mechanism relay operators can effectively create a paywall for a
13 | // service, or at least cover their operating costs. Hidden services can do this
14 | // also, with server side anonymity.
15 | //
16 | // todo: hidden services need a session type.
17 | Service struct {
18 |
19 | // Port specifies the type of service based on the well known port used by the
20 | // protocol. For bitcoin, for example, this would be 8333 for its peer to peer
21 | // listener, for SSH it would be 22, and so on.
22 | Port uint16
23 |
24 | // RelayRate is the fee in mSAT for megabytes forwarded to and returned from the
25 | // service.
26 | RelayRate uint32
27 |
28 | // Transport is a channel that will have a network handler at the other end to
29 | // dispatch and return replies to the Engine.
30 | tpt.Transport
31 | }
32 |
33 | // Services is a collection of services.
34 | Services []*Service
35 | )
36 |
--------------------------------------------------------------------------------
/pkg/engine/sess/data.go:
--------------------------------------------------------------------------------
1 | package sess
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/crypto"
5 | "git.indra-labs.org/dev/ind/pkg/crypto/nonce"
6 | "git.indra-labs.org/dev/ind/pkg/engine/sessions"
7 | "git.indra-labs.org/dev/ind/pkg/util/slice"
8 | )
9 |
10 | // Data is a data structure returned from engine.PostAcctOnion that tracks the
11 | // information related to the use of a session.
12 | type Data struct {
13 |
14 | // B is the bytes of data that were sent out.
15 | B slice.Bytes
16 |
17 | // Sessions are the list of sessions in the circuit.
18 | Sessions sessions.Sessions
19 |
20 | // Billable is the public keys of the sessions used in the circuit.
21 | //
22 | // todo: is this actually used???
23 | Billable []crypto.PubBytes
24 |
25 | // Ret is the return session, which isn't billable.
26 | Ret crypto.PubBytes
27 |
28 | // ID is the transmission nonce.ID, as found in PendingResponses.
29 | ID nonce.ID
30 |
31 | // Port is the well-known port designating the protocol of the message.
32 | Port uint16
33 |
34 | // PostAcct is a collection of hooks that are to be run on the successful
35 | // receiving of the response or confirmation and the completion of all relaying
36 | // from source back to source.
37 | PostAcct []func()
38 | }
39 |
--------------------------------------------------------------------------------
/pkg/engine/sess/doc.go:
--------------------------------------------------------------------------------
1 | // Package sess provides the Session Manager, which keeps track of a client's sessions.
2 | //
3 | // This package provides access to subsystems related to it such as pending payments, handles accounting to attempt to keep clients and relays session balances in sync without any unnecessary communication.
4 | package sess
5 |
--------------------------------------------------------------------------------
/pkg/engine/tpt/interfaces.go:
--------------------------------------------------------------------------------
1 | // Package tpt provides the definition of the interface Transport, which is an abstraction used for reading and writing to peers via transport.Transport.
2 | package tpt
3 |
4 | import "git.indra-labs.org/dev/ind/pkg/util/slice"
5 |
6 | // Transport is a generic interface for sending and receiving slices of bytes.
7 | type Transport interface {
8 |
9 | // Send delivers a byte buffer along the Transport.
10 | Send(b slice.Bytes) (e error)
11 |
12 | // Receive waits for incoming messages and delivers the byte buffer to the caller
13 | // via a channel.
14 | Receive() <-chan slice.Bytes
15 | }
16 |
--------------------------------------------------------------------------------
/pkg/engine/transport/doc.go:
--------------------------------------------------------------------------------
1 | // Package transport provides a set of definitions of abstractions that layer above the implementation enabling the use of simple functions that interact on channels to queue and receive messages from the tpt.Transport of which several variants are here implemented.
2 | package transport
3 |
--------------------------------------------------------------------------------
/pkg/engine/transport/pstoreds/cache.go:
--------------------------------------------------------------------------------
1 | package pstoreds
2 |
3 | // cache abstracts all methods we access from ARCCache, to enable alternate
4 | // implementations such as a no-op one.
5 | type cache[K comparable, V any] interface {
6 | Get(key K) (value V, ok bool)
7 | Add(key K, value V)
8 | Remove(key K)
9 | Contains(key K) bool
10 | Peek(key K) (value V, ok bool)
11 | Keys() []K
12 | }
13 |
14 | // noopCache is a dummy implementation that's used when the cache is disabled.
15 | type noopCache[K comparable, V any] struct {
16 | }
17 |
18 | var _ cache[int, int] = (*noopCache[int, int])(nil)
19 |
20 | func (*noopCache[K, V]) Get(key K) (value V, ok bool) {
21 | return *new(V), false
22 | }
23 |
24 | func (*noopCache[K, V]) Add(key K, value V) {
25 | }
26 |
27 | func (*noopCache[K, V]) Remove(key K) {
28 | }
29 |
30 | func (*noopCache[K, V]) Contains(key K) bool {
31 | return false
32 | }
33 |
34 | func (*noopCache[K, V]) Peek(key K) (value V, ok bool) {
35 | return *new(V), false
36 | }
37 |
38 | func (*noopCache[K, V]) Keys() (keys []K) {
39 | return keys
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/engine/transport/pstoreds/cyclic_batch.go:
--------------------------------------------------------------------------------
1 | package pstoreds
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "fmt"
7 |
8 | ds "github.com/ipfs/go-datastore"
9 | )
10 |
11 | // how many operations are queued in a cyclic batch before we flush it.
12 | var defaultOpsPerCyclicBatch = 20
13 |
14 | // cyclicBatch buffers ds write operations and automatically flushes them after
15 | // defaultOpsPerCyclicBatch (20) have been queued. An explicit `Commit()` closes
16 | // this cyclic batch, erroring all further operations.
17 | //
18 | // It is similar to go-ds autobatch, but it's driven by an actual Batch facility
19 | // offered by the ds.
20 | type cyclicBatch struct {
21 | threshold int
22 | ds.Batch
23 | ds ds.Batching
24 | pending int
25 | }
26 |
27 | func newCyclicBatch(ds ds.Batching, threshold int) (ds.Batch, error) {
28 | batch, err := ds.Batch(context.TODO())
29 | if err != nil {
30 | return nil, err
31 | }
32 | return &cyclicBatch{Batch: batch, ds: ds}, nil
33 | }
34 |
35 | func (cb *cyclicBatch) cycle() (err error) {
36 | if cb.Batch == nil {
37 | return errors.New("cyclic batch is closed")
38 | }
39 | if cb.pending < cb.threshold {
40 | // we haven't reached the threshold yet.
41 | return nil
42 | }
43 | // commit and renew the batch.
44 | if err = cb.Batch.Commit(context.TODO()); err != nil {
45 | return fmt.Errorf("failed while committing cyclic batch: %w", err)
46 | }
47 | if cb.Batch, err = cb.ds.Batch(context.TODO()); err != nil {
48 | return fmt.Errorf("failed while renewing cyclic batch: %w", err)
49 | }
50 | return nil
51 | }
52 |
53 | func (cb *cyclicBatch) Put(ctx context.Context, key ds.Key, val []byte) error {
54 | if err := cb.cycle(); err != nil {
55 | return err
56 | }
57 | cb.pending++
58 | return cb.Batch.Put(ctx, key, val)
59 | }
60 |
61 | func (cb *cyclicBatch) Delete(ctx context.Context, key ds.Key) error {
62 | if err := cb.cycle(); err != nil {
63 | return err
64 | }
65 | cb.pending++
66 | return cb.Batch.Delete(ctx, key)
67 | }
68 |
69 | func (cb *cyclicBatch) Commit(ctx context.Context) error {
70 | if cb.Batch == nil {
71 | return errors.New("cyclic batch is closed")
72 | }
73 | if err := cb.Batch.Commit(ctx); err != nil {
74 | return err
75 | }
76 | cb.pending = 0
77 | cb.Batch = nil
78 | return nil
79 | }
80 |
--------------------------------------------------------------------------------
/pkg/engine/transport/pstoreds/pb/pstore.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package pstore.pb;
3 |
4 | // AddrBookRecord represents a record for a peer in the address book.
5 | message AddrBookRecord {
6 | // The peer ID.
7 | bytes id = 1;
8 |
9 | // The multiaddresses. This is a sorted list where element 0 expires the soonest.
10 | repeated AddrEntry addrs = 2;
11 |
12 | // The most recently received signed PeerRecord.
13 | CertifiedRecord certified_record = 3;
14 |
15 | // AddrEntry represents a single multiaddress.
16 | message AddrEntry {
17 | bytes addr = 1;
18 |
19 | // The point in time when this address expires.
20 | int64 expiry = 2;
21 |
22 | // The original TTL of this address.
23 | int64 ttl = 3;
24 | }
25 |
26 | // CertifiedRecord contains a serialized signed PeerRecord used to
27 | // populate the signedAddrs list.
28 | message CertifiedRecord {
29 | // The Seq counter from the signed PeerRecord envelope
30 | uint64 seq = 1;
31 |
32 | // The serialized bytes of the SignedEnvelope containing the PeerRecord.
33 | bytes raw = 2;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/engine/transport/pstoremem/metadata.go:
--------------------------------------------------------------------------------
1 | package pstoremem
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/libp2p/go-libp2p/core/peer"
7 | pstore "github.com/libp2p/go-libp2p/core/peerstore"
8 | )
9 |
10 | type memoryPeerMetadata struct {
11 | // store other data, like versions
12 | ds map[peer.ID]map[string]interface{}
13 | dslock sync.RWMutex
14 | }
15 |
16 | var _ pstore.PeerMetadata = (*memoryPeerMetadata)(nil)
17 |
18 | func NewPeerMetadata() *memoryPeerMetadata {
19 | return &memoryPeerMetadata{
20 | ds: make(map[peer.ID]map[string]interface{}),
21 | }
22 | }
23 |
24 | func (ps *memoryPeerMetadata) Put(p peer.ID, key string,
25 | val interface{}) error {
26 |
27 | ps.dslock.Lock()
28 | defer ps.dslock.Unlock()
29 | m, ok := ps.ds[p]
30 | if !ok {
31 | m = make(map[string]interface{})
32 | ps.ds[p] = m
33 | }
34 | m[key] = val
35 | return nil
36 | }
37 |
38 | func (ps *memoryPeerMetadata) Get(p peer.ID,
39 | key string) (interface{}, error) {
40 |
41 | ps.dslock.RLock()
42 | defer ps.dslock.RUnlock()
43 | m, ok := ps.ds[p]
44 | if !ok {
45 | return nil, pstore.ErrNotFound
46 | }
47 | val, ok := m[key]
48 | if !ok {
49 | return nil, pstore.ErrNotFound
50 | }
51 | return val, nil
52 | }
53 |
54 | func (ps *memoryPeerMetadata) RemovePeer(p peer.ID) {
55 | ps.dslock.Lock()
56 | delete(ps.ds, p)
57 | ps.dslock.Unlock()
58 | }
59 |
--------------------------------------------------------------------------------
/pkg/engine/transport/pstoremem/sorting.go:
--------------------------------------------------------------------------------
1 | package pstoremem
2 |
3 | import (
4 | "bytes"
5 |
6 | ma "github.com/multiformats/go-multiaddr"
7 | mafmt "github.com/multiformats/go-multiaddr-fmt"
8 | manet "github.com/multiformats/go-multiaddr/net"
9 | )
10 |
11 | func isFDCostlyTransport(a ma.Multiaddr) bool {
12 | return mafmt.TCP.Matches(a)
13 | }
14 |
15 | type addrList []ma.Multiaddr
16 |
17 | func (al addrList) Len() int { return len(al) }
18 | func (al addrList) Swap(i, j int) { al[i], al[j] = al[j], al[i] }
19 |
20 | func (al addrList) Less(i, j int) bool {
21 | a := al[i]
22 | b := al[j]
23 |
24 | // dial localhost addresses next, they should fail immediately
25 | lba := manet.IsIPLoopback(a)
26 | lbb := manet.IsIPLoopback(b)
27 | if lba && !lbb {
28 | return true
29 | }
30 |
31 | // dial utp and similar 'non-fd-consuming' addresses first
32 | fda := isFDCostlyTransport(a)
33 | fdb := isFDCostlyTransport(b)
34 | if !fda {
35 | return fdb
36 | }
37 |
38 | // if 'b' doesnt take a file descriptor
39 | if !fdb {
40 | return false
41 | }
42 |
43 | // if 'b' is loopback and both take file descriptors
44 | if lbb {
45 | return false
46 | }
47 |
48 | // for the rest, just sort by bytes
49 | return bytes.Compare(a.Bytes(), b.Bytes()) > 0
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/engine/transport/pstoremem/sorting_test.go:
--------------------------------------------------------------------------------
1 | package pstoremem
2 |
3 | import (
4 | "sort"
5 | "testing"
6 |
7 | ma "github.com/multiformats/go-multiaddr"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestAddressSorting(t *testing.T) {
12 | u1 := ma.StringCast("/ip4/152.12.23.53/udp/1234/utp")
13 | u2l := ma.StringCast("/ip4/127.0.0.1/udp/1234/utp")
14 | local := ma.StringCast("/ip4/127.0.0.1/tcp/1234")
15 | norm := ma.StringCast("/ip4/6.5.4.3/tcp/1234")
16 |
17 | l := addrList{local, u1, u2l, norm}
18 | sort.Sort(l)
19 | require.Equal(t, l, addrList{u2l, u1, local, norm})
20 | }
21 |
--------------------------------------------------------------------------------
/pkg/engine/transport/readme.md:
--------------------------------------------------------------------------------
1 | # pkg/engine/transport
2 |
3 | This is an implementation of typical network handling features, a listener,
4 | which has an `Accept` method that returns a channel that will pick up a new
5 | inbound connection.
6 |
7 | ## Warning
8 |
9 | `pstoreds` and `pstoremem` both store the `libp2p.Host`'s private key in
10 | cleartext. Consequently it is necessary to ensure to use `options.Default()` and
11 | use an encryption key with it. The key has to be kept hot for ads, for finding
12 | the LN node being controlled by Indra, and sending/receiving payments.
13 |
14 | todo: need a key change protocol for this identity key that handles session
15 | migration correctly.
16 |
17 | ## License Notes
18 |
19 | `pstoreds` and `pstoremem` are under MIT license as seen at
20 | the [libp2p repository](https://github.com/libp2p/go-libp2p/LICENSE).
21 |
--------------------------------------------------------------------------------
/pkg/interrupt/LICENSE:
--------------------------------------------------------------------------------
1 | ISC License
2 |
3 | Copyright (c) 2013-2017 The btcsuite developers
4 | Copyright (c) 2015-2016 The Decred developers
5 |
6 | Permission to use, copy, modify, and distribute this software for any
7 | purpose with or without fee is hereby granted, provided that the above
8 | copyright notice and this permission notice appear in all copies.
9 |
10 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--------------------------------------------------------------------------------
/pkg/interrupt/README.md:
--------------------------------------------------------------------------------
1 | # interrupt
2 |
3 | Handle shutdowns cleanly and enable hot reload
4 |
5 | Based on the shutdown handling code in
6 | [btcwallet](https://github.com/btcsuite/btcwallet).
7 |
8 | As such the ISC license applies to this code.
--------------------------------------------------------------------------------
/pkg/interrupt/doc.go:
--------------------------------------------------------------------------------
1 | // Package interrupt provides a set of services for handling OS interrupt signals and in-place restarting of a server.
2 | package interrupt
3 |
--------------------------------------------------------------------------------
/pkg/interrupt/sigterm.go:
--------------------------------------------------------------------------------
1 | //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
2 |
3 | package interrupt
4 |
5 | import (
6 | "os"
7 | "syscall"
8 | )
9 |
10 | func init() {
11 | signals = []os.Signal{os.Interrupt, syscall.SIGTERM}
12 | }
13 |
--------------------------------------------------------------------------------
/pkg/node/protocol.go:
--------------------------------------------------------------------------------
1 | // Package node provides the magic keys that identify each network swarm in the Indra network - mainnet, testnet and simnet.
2 | package node
3 |
4 | // Swarm is an Indra network. Encodes a network identifier for mainnet, testnet and simnet.
5 | type Swarm uint32
6 |
7 | const (
8 | // MainNet represents the main indra network.
9 | MainNet Swarm = 0xd9b4bef9
10 |
11 | // TestNet represents the regression test network.
12 | TestNet Swarm = 0xdab5bffa
13 |
14 | // SimNet represents the simulation test network.
15 | SimNet Swarm = 0x12141c16
16 | )
17 |
--------------------------------------------------------------------------------
/pkg/p2p/config.go:
--------------------------------------------------------------------------------
1 | package p2p
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/cfg"
5 | "github.com/libp2p/go-libp2p/core/crypto"
6 | "github.com/multiformats/go-multiaddr"
7 | )
8 |
9 | func NewMultiAddr(addr string) (maddr multiaddr.Multiaddr) {
10 |
11 | var err error
12 |
13 | if maddr, err = multiaddr.NewMultiaddr(addr); check(err) {
14 | panic("Not a valid multiaddress.")
15 | }
16 |
17 | return
18 | }
19 |
20 | var DefaultConfig = &Config{
21 | ListenAddresses: []multiaddr.Multiaddr{},
22 | SeedAddresses: []multiaddr.Multiaddr{},
23 | ConnectAddresses: []multiaddr.Multiaddr{},
24 | }
25 |
26 | type Config struct {
27 | PrivKey crypto.PrivKey
28 |
29 | PublicAddress multiaddr.Multiaddr
30 | SeedAddresses []multiaddr.Multiaddr
31 | ConnectAddresses []multiaddr.Multiaddr
32 | ListenAddresses []multiaddr.Multiaddr
33 |
34 | Params *cfg.Params
35 | }
36 |
37 | func (c *Config) SetNetwork(network string) {
38 |
39 | c.Params = cfg.SelectNetworkParams(network)
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/p2p/doc.go:
--------------------------------------------------------------------------------
1 | // Package p2p provides the implementation for the p2p gossip and libp2p swarm membership used for a seed node, which is a non-relaying, non-client node only providing network metadata to new connections.
2 | package p2p
3 |
--------------------------------------------------------------------------------
/pkg/p2p/flags.go:
--------------------------------------------------------------------------------
1 | package p2p
2 |
3 | import (
4 | "github.com/spf13/cobra"
5 | "github.com/spf13/viper"
6 | )
7 |
8 | var (
9 | listenFlag = "p2p-listen"
10 | seedFlag = "p2p-seed"
11 | connectFlag = "p2p-connect"
12 | )
13 |
14 | var (
15 | listeners []string
16 | seeds []string
17 | connectors []string
18 | )
19 |
20 | func InitFlags(cmd *cobra.Command) {
21 |
22 | cmd.PersistentFlags().StringSliceVarP(&listeners, listenFlag, "",
23 | []string{
24 | "/ip4/0.0.0.0/tcp/8337",
25 | "/ip6/::/tcp/8337",
26 | },
27 | "binds to an interface",
28 | )
29 |
30 | viper.BindPFlag(listenFlag, cmd.PersistentFlags().Lookup(listenFlag))
31 |
32 | cmd.PersistentFlags().StringSliceVarP(&seeds, seedFlag, "",
33 | []string{},
34 | "adds an additional seed connection (e.g /dns4/seed0.indra.org/tcp/8337/p2p/)",
35 | )
36 |
37 | viper.BindPFlag(seedFlag, cmd.PersistentFlags().Lookup(seedFlag))
38 |
39 | cmd.PersistentFlags().StringSliceVarP(&connectors, connectFlag, "",
40 | []string{},
41 | "connects only to the seed multi-addresses specified",
42 | )
43 |
44 | viper.BindPFlag(connectFlag, cmd.PersistentFlags().Lookup(connectFlag))
45 | }
46 |
--------------------------------------------------------------------------------
/pkg/p2p/log.go:
--------------------------------------------------------------------------------
1 | package p2p
2 |
3 | import (
4 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
5 | )
6 |
7 | var (
8 | log = log2.GetLogger()
9 | check = log.E.Chk
10 | )
11 |
--------------------------------------------------------------------------------
/pkg/p2p/metrics/host.go:
--------------------------------------------------------------------------------
1 | // Package metrics provides a simple logging update of the status of a seed node and its peer and connection counts.
2 | package metrics
3 |
4 | import (
5 | "context"
6 | "sync"
7 | "time"
8 |
9 | "github.com/libp2p/go-libp2p/core/host"
10 |
11 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
12 | )
13 |
14 | var (
15 | log = log2.GetLogger()
16 | check = log.E.Chk
17 | )
18 |
19 | var (
20 | hostStatusInterval = 10 * time.Second
21 | )
22 |
23 | var (
24 | mutex sync.Mutex
25 | )
26 |
27 | func SetInterval(timeout time.Duration) {
28 | hostStatusInterval = timeout
29 | }
30 |
31 | func HostStatus(ctx context.Context, host host.Host) {
32 |
33 | log.I.Ln("starting [metrics.hoststatus]")
34 |
35 | // Guarding against multiple instantiations
36 | if !mutex.TryLock() {
37 | return
38 | }
39 |
40 | log.I.Ln("[metrics.hoststatus] is ready")
41 |
42 | go func() {
43 | for {
44 | select {
45 | case <-time.After(hostStatusInterval):
46 |
47 | log.I.Ln()
48 | log.I.Ln("---- host status ----")
49 | log.I.Ln("-- peers:", len(host.Network().Peers()))
50 | log.I.Ln("-- connections:", len(host.Network().Conns()))
51 | log.I.Ln("---- ---- ------ ----")
52 |
53 | case <-ctx.Done():
54 |
55 | log.I.Ln("shutting down [metrics.hoststatus]")
56 |
57 | return
58 | }
59 | }
60 | }()
61 | }
62 |
--------------------------------------------------------------------------------
/pkg/p2p/signals.go:
--------------------------------------------------------------------------------
1 | package p2p
2 |
3 | var (
4 | startupErrors = make(chan error, 32)
5 | isReadyChan = make(chan bool, 1)
6 | isShutdownChan = make(chan bool, 1)
7 | )
8 |
9 | func WhenStartFailed() chan error {
10 | return startupErrors
11 | }
12 |
13 | func WhenReady() chan bool {
14 | return isReadyChan
15 | }
16 |
17 | func WhenShutdown() chan bool {
18 | return isShutdownChan
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/p2p/util.go:
--------------------------------------------------------------------------------
1 | package p2p
2 |
3 | import (
4 | "github.com/btcsuite/btcd/btcutil/base58"
5 | "github.com/libp2p/go-libp2p/core/crypto"
6 | )
7 |
8 | func Base58Encode(priv crypto.PrivKey) (key string, err error) {
9 |
10 | var raw []byte
11 |
12 | raw, err = priv.Raw()
13 |
14 | key = base58.Encode(raw)
15 |
16 | return
17 | }
18 |
19 | func Base58Decode(key string) (priv crypto.PrivKey, err error) {
20 |
21 | var raw []byte
22 |
23 | raw = base58.Decode(key)
24 |
25 | if priv, _ = crypto.UnmarshalSecp256k1PrivateKey(raw); check(err) {
26 | return
27 | }
28 |
29 | return
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/p2p/util_test.go:
--------------------------------------------------------------------------------
1 | package p2p
2 |
3 | import (
4 | "crypto/rand"
5 | "github.com/libp2p/go-libp2p/core/crypto"
6 | "testing"
7 | )
8 |
9 | func TestBase58(t *testing.T) {
10 |
11 | var err error
12 | var priv1, priv2 crypto.PrivKey
13 | var keyStr1, keyStr2 string
14 |
15 | // Generate priv
16 | priv1, _, err = crypto.GenerateSecp256k1Key(rand.Reader)
17 |
18 | if keyStr1, err = Base58Encode(priv1); err != nil {
19 | t.Error("base58encode error: ", err)
20 | }
21 |
22 | if priv2, err = Base58Decode(keyStr1); err != nil {
23 | t.Error("base58decode error: ", err)
24 | }
25 |
26 | if !priv1.Equals(priv2) {
27 | t.Error("Keys are not equal!")
28 | }
29 |
30 | if keyStr2, err = Base58Encode(priv2); err != nil {
31 | t.Error("base58encode error: ", err)
32 | }
33 |
34 | if keyStr1 != keyStr2 {
35 | t.Error("Keys are not equal!")
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/pkg/proc/app/app.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | cmds2 "git.indra-labs.org/dev/ind/pkg/proc/cmds"
5 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
6 | )
7 |
8 | var (
9 | log = log2.GetLogger()
10 | check = log.E.Chk
11 | )
12 |
13 | type App struct {
14 | *cmds2.Command
15 | launch *cmds2.Command
16 | runArgs []string
17 | cmds2.Envs
18 | }
19 |
20 | func New(c *cmds2.Command, args []string) (a *App, e error) {
21 | log2.App.Store(c.Name)
22 | // AddIntro the default configuration items for datadir/configfile
23 | log.T.Ln("test")
24 | cmds2.GetConfigBase(c.Configs, c.Name, false)
25 | log.T.Ln("test")
26 | // AddIntro the help function
27 | c.AddCommand(cmds2.Help())
28 | a = &App{Command: c}
29 | log.T.Ln("test")
30 | if a.Command, e = cmds2.Init(c, nil); check(e) {
31 | return
32 | }
33 | log.T.Ln("test")
34 | // We first parse the CLI args, in case config file location has been
35 | // specified
36 | if a.launch, _, e = a.Command.ParseCLIArgs(args); check(e) {
37 | return
38 | }
39 | if e = c.LoadConfig(); log.E.Chk(e) {
40 | return
41 | }
42 | a.Envs = c.GetEnvs()
43 | if e = a.Envs.LoadFromEnvironment(); check(e) {
44 | return
45 | }
46 | // This is done again, to ensure the effect of CLI args take precedence
47 | if a.launch, a.runArgs, e = a.Command.ParseCLIArgs(args); check(e) {
48 | return
49 | }
50 | return
51 | }
52 |
53 | func (a *App) Launch() (e error) {
54 | e = a.launch.Entrypoint(a.launch, a.runArgs)
55 | log.E.Chk(e)
56 | return
57 | }
58 |
--------------------------------------------------------------------------------
/pkg/proc/app/app_test.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/util/ci"
5 | "os"
6 | "strings"
7 | "testing"
8 |
9 | "git.indra-labs.org/dev/ind/pkg/proc/cmds"
10 | )
11 |
12 | func TestNew(t *testing.T) {
13 | ci.TraceIfNot()
14 | args1 := "/random/path/to/server_binary --cafile ~/some/cafile --LC=cn node -addrindex --BD 48h30s"
15 | args1s := strings.Split(args1, " ")
16 | var a *App
17 | var e error
18 | if a, e = New(cmds.GetExampleCommands(), args1s); log.E.Chk(e) {
19 | t.FailNow()
20 | }
21 | if e = a.Launch(); check(e) {
22 | t.FailNow()
23 | }
24 | if e = os.RemoveAll(a.Command.Configs["DataDir"].
25 | Expanded()); check(e) {
26 |
27 | t.FailNow()
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/proc/cmds/args_test.go:
--------------------------------------------------------------------------------
1 | package cmds
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/util/ci"
5 | "strings"
6 | "testing"
7 | )
8 |
9 | func TestCommand_ParseCLIArgs(t *testing.T) {
10 | ci.TraceIfNot()
11 | ec := GetExampleCommands()
12 | o, _ := Init(ec, nil)
13 | args6 := "/random/path/to/server_binary --cafile ~/some/cafile --LC=cn " +
14 | "node -addrindex false --blocksonly"
15 | args6s := strings.Split(args6, " ")
16 | run, _, e := o.ParseCLIArgs(args6s)
17 | if log.E.Chk(e) {
18 | t.Error(e)
19 | t.FailNow()
20 | }
21 | args1 := "/random/path/to/server_binary --cafile ~/some/cafile --LC=cn " +
22 | "node -addrindex --BD=5m"
23 | args1s := strings.Split(args1, " ")
24 | run, _, e = o.ParseCLIArgs(args1s)
25 | if log.E.Chk(e) {
26 | t.Error(e)
27 | t.FailNow()
28 | }
29 | _, _ = run, e
30 | args3 := "node -addrindex --BD 48h30s dropaddrindex somegarbage " +
31 | "--autoports"
32 | args3s := strings.Split(args3, " ")
33 | run, _, e = o.ParseCLIArgs(args3s)
34 | // This one must fail, 'somegarbage' is not a command and has no -/-- prefix
35 | if e == nil {
36 | t.Error(e)
37 | t.FailNow()
38 | }
39 | args5 := "/random/path/to/server_binary --cafile ~/some/cafile --LC=cn "
40 | args5s := strings.Split(args5, " ")
41 | run, _, e = o.ParseCLIArgs(args5s)
42 | if log.E.Chk(e) {
43 | t.Error(e)
44 | t.FailNow()
45 | }
46 | args2 := "/random/path/to/server_binary node -addrindex --BD=48h30s " +
47 | "-RPCMaxConcurrentReqs -16 dropaddrindex"
48 | args2s := strings.Split(args2, " ")
49 | run, _, e = o.ParseCLIArgs(args2s)
50 | if log.E.Chk(e) {
51 | t.Error(e)
52 | t.FailNow()
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/pkg/proc/log/length.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | const maxLen = 44
4 |
5 |
--------------------------------------------------------------------------------
/pkg/proc/log/log_test.go:
--------------------------------------------------------------------------------
1 | package log_test
2 |
3 | import (
4 | "errors"
5 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
6 | "testing"
7 | )
8 |
9 | var (
10 | log = log2.GetLogger()
11 | fails = log.E.Chk
12 | )
13 |
14 | func TestGetLogger(t *testing.T) {
15 | log.I.Ln("info")
16 | fails(errors.New("dummy error"))
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/proc/log/maxlen/maxlen.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "io/fs"
6 | "os"
7 | "path/filepath"
8 | "strings"
9 | )
10 |
11 | func main() {
12 | var max int
13 | var longest string
14 | filepath.Walk(os.Args[1], func(path string, info fs.FileInfo, err error) error {
15 | if strings.HasPrefix(path, ".") ||
16 | !strings.HasSuffix(path, ".go") ||
17 | strings.HasSuffix(path, "_test.go") { // doesn't matter as much if test logs rel path grow initially
18 | return nil
19 | }
20 | if len(path) > max {
21 | max = len(path)
22 | longest = path
23 | }
24 | return nil
25 | })
26 | if e := os.WriteFile("pkg/proc/log/length.go", []byte(fmt.Sprintf("package log\n\nconst maxLen = %d\n\n", max)), 0600); e != nil {
27 | fmt.Println(e)
28 | }
29 | fmt.Println(longest)
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/proc/opts/config/interface.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/util/path"
5 | "time"
6 |
7 | "git.indra-labs.org/dev/ind/pkg/proc/opts/meta"
8 | )
9 |
10 | // Concrete is a struct of functions that return the concrete values. Only the
11 | // intended type will return a value, the rest always return zero.
12 | type Concrete struct {
13 | Bool func() bool
14 | Duration func() time.Duration
15 | Float func() float64
16 | Integer func() int64
17 | List func() []string
18 | Text func() string
19 | }
20 |
21 | // NewConcrete provides a Concrete with all functions returning zero values
22 | func NewConcrete() Concrete {
23 | return Concrete{
24 | func() bool { return false },
25 | func() time.Duration { return 0 },
26 | func() float64 { return 0 },
27 | func() int64 { return 0 },
28 | func() []string { return nil },
29 | func() string { return "" },
30 | }
31 | }
32 |
33 | // Option interface reads and writes string formats for options and returns a
34 | // Concrete value to the appropriate concrete value, with the type indicated.
35 | type Option interface {
36 | FromString(s string) (e error)
37 | String() (s string)
38 | Expanded() (s string)
39 | SetExpanded(s string)
40 | Value() (c Concrete)
41 | Type() (t meta.Type)
42 | Meta() (md meta.Metadata)
43 | RunHooks() (err error)
44 | Path() (p path.Path)
45 | SetPath(p path.Path)
46 | }
47 |
48 | type Opts map[string]Option
49 |
--------------------------------------------------------------------------------
/pkg/proc/opts/duration/spec.go:
--------------------------------------------------------------------------------
1 | package duration
2 |
3 | import (
4 | "fmt"
5 | "git.indra-labs.org/dev/ind/pkg/util/path"
6 | "strings"
7 | "time"
8 |
9 | "go.uber.org/atomic"
10 |
11 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
12 | "git.indra-labs.org/dev/ind/pkg/proc/opts/config"
13 | "git.indra-labs.org/dev/ind/pkg/proc/opts/meta"
14 | )
15 |
16 | var (
17 | log = log2.GetLogger()
18 | check = log.E.Chk
19 | )
20 |
21 | type Opt struct {
22 | p path.Path
23 | m meta.Metadata
24 | v atomic.Duration
25 | h []Hook
26 | }
27 |
28 | func (o *Opt) Path() (p path.Path) { return o.p }
29 |
30 | func (o *Opt) SetPath(p path.Path) { o.p = p }
31 |
32 | var _ config.Option = &Opt{}
33 |
34 | type Hook func(*Opt)
35 |
36 | func New(m meta.Data, h ...Hook) (o *Opt) {
37 | o = &Opt{m: meta.New(m, meta.Duration), h: h}
38 | _ = o.FromString(m.Default)
39 | return
40 | }
41 |
42 | func (o *Opt) Meta() meta.Metadata { return o.m }
43 | func (o *Opt) Type() meta.Type { return o.m.Typ }
44 | func (o *Opt) ToOption() config.Option { return o }
45 |
46 | func (o *Opt) RunHooks() (e error) {
47 | for i := range o.h {
48 | o.h[i](o)
49 | }
50 | return
51 | }
52 |
53 | func (o *Opt) FromValue(v time.Duration) *Opt {
54 | o.v.Store(v)
55 | return o
56 | }
57 |
58 | func (o *Opt) FromString(s string) (e error) {
59 | s = strings.TrimSpace(s)
60 | var d time.Duration
61 | d, e = time.ParseDuration(s)
62 | if e != nil {
63 | return e
64 | }
65 | o.v.Store(d)
66 | e = o.RunHooks()
67 | return
68 | }
69 |
70 | func (o *Opt) String() (s string) {
71 | return fmt.Sprint(o.v.Load())
72 | }
73 |
74 | func (o *Opt) Expanded() (s string) { return o.String() }
75 |
76 | func (o *Opt) SetExpanded(s string) {
77 | if err := o.FromString(s); log.E.Chk(err) {
78 | }
79 | }
80 |
81 | func (o *Opt) Value() (c config.Concrete) {
82 | c = config.NewConcrete()
83 | c.Duration = func() time.Duration { return o.v.Load() }
84 | return
85 | }
86 |
87 | func Clamp(o *Opt, min, max time.Duration) func(*Opt) {
88 | return func(o *Opt) {
89 | v := o.v.Load()
90 | if v < min {
91 | o.v.Store(min)
92 | } else if v > max {
93 | o.v.Store(max)
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/pkg/proc/opts/float/spec.go:
--------------------------------------------------------------------------------
1 | package float
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/util/path"
5 | "strconv"
6 | "strings"
7 |
8 | "go.uber.org/atomic"
9 |
10 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
11 | "git.indra-labs.org/dev/ind/pkg/proc/opts/config"
12 | "git.indra-labs.org/dev/ind/pkg/proc/opts/meta"
13 | )
14 |
15 | var (
16 | log = log2.GetLogger()
17 | check = log.E.Chk
18 | )
19 |
20 | type Opt struct {
21 | p path.Path
22 | m meta.Metadata
23 | v atomic.Float64
24 | h []Hook
25 | }
26 |
27 | func (o *Opt) Path() (p path.Path) { return o.p }
28 |
29 | func (o *Opt) SetPath(p path.Path) { o.p = p }
30 |
31 | var _ config.Option = &Opt{}
32 |
33 | type Hook func(*Opt) error
34 |
35 | func New(m meta.Data, h ...Hook) (o *Opt) {
36 | o = &Opt{m: meta.New(m, meta.Float), h: h}
37 | _ = o.FromString(m.Default)
38 | return
39 | }
40 |
41 | func (o *Opt) Meta() meta.Metadata { return o.m }
42 | func (o *Opt) Type() meta.Type { return o.m.Typ }
43 | func (o *Opt) ToOption() config.Option { return o }
44 |
45 | func (o *Opt) RunHooks() (e error) {
46 | for i := range o.h {
47 | e = o.h[i](o)
48 | if e != nil {
49 | return
50 | }
51 | }
52 | return
53 | }
54 |
55 | func (o *Opt) FromValue(v float64) *Opt {
56 | o.v.Store(v)
57 | return o
58 | }
59 |
60 | func (o *Opt) FromString(s string) (e error) {
61 | s = strings.TrimSpace(s)
62 | var p float64
63 | p, e = strconv.ParseFloat(s, 64)
64 | if e != nil {
65 | return e
66 | }
67 | o.v.Store(p)
68 | e = o.RunHooks()
69 | return
70 | }
71 |
72 | func (o *Opt) String() (s string) {
73 | return strconv.FormatFloat(o.v.Load(), 'f', -1, 64)
74 | }
75 |
76 | func (o *Opt) Expanded() (s string) { return o.String() }
77 |
78 | func (o *Opt) SetExpanded(s string) {
79 | err := o.FromString(s)
80 | log.E.Chk(err)
81 | }
82 |
83 | func (o *Opt) Value() (c config.Concrete) {
84 | c = config.NewConcrete()
85 | c.Float = func() float64 { return o.v.Load() }
86 | return
87 | }
88 |
89 | func Clamp(o *Opt, min, max float64) func(*Opt) {
90 | return func(o *Opt) {
91 | v := o.v.Load()
92 | if v < min {
93 | o.v.Store(min)
94 | } else if v > max {
95 | o.v.Store(max)
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/pkg/proc/opts/integer/spec.go:
--------------------------------------------------------------------------------
1 | package integer
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/util/path"
5 | "strconv"
6 | "strings"
7 |
8 | "go.uber.org/atomic"
9 |
10 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
11 | "git.indra-labs.org/dev/ind/pkg/proc/opts/config"
12 | "git.indra-labs.org/dev/ind/pkg/proc/opts/meta"
13 | )
14 |
15 | var (
16 | log = log2.GetLogger()
17 | check = log.E.Chk
18 | )
19 |
20 | type Opt struct {
21 | p path.Path
22 | m meta.Metadata
23 | v atomic.Int64
24 | h []Hook
25 | }
26 |
27 | func (o *Opt) Path() (p path.Path) { return o.p }
28 |
29 | func (o *Opt) SetPath(p path.Path) { o.p = p }
30 |
31 | var _ config.Option = &Opt{}
32 |
33 | type Hook func(*Opt) error
34 |
35 | func New(m meta.Data, h ...Hook) (o *Opt) {
36 | o = &Opt{m: meta.New(m, meta.Integer), h: h}
37 | _ = o.FromString(m.Default)
38 | return
39 | }
40 |
41 | func (o *Opt) Meta() meta.Metadata { return o.m }
42 | func (o *Opt) Type() meta.Type { return o.m.Typ }
43 | func (o *Opt) ToOption() config.Option { return o }
44 |
45 | func (o *Opt) RunHooks() (e error) {
46 | for i := range o.h {
47 | e = o.h[i](o)
48 | if e != nil {
49 | return
50 | }
51 | }
52 | return
53 | }
54 |
55 | func (o *Opt) FromValue(v int64) *Opt {
56 | o.v.Store(v)
57 | return o
58 | }
59 |
60 | func (o *Opt) FromString(s string) (e error) {
61 | s = strings.TrimSpace(s)
62 | var p int64
63 | if p, e = strconv.ParseInt(s, 10, 64); check(e) {
64 | return e
65 | }
66 | o.v.Store(p)
67 | e = o.RunHooks()
68 | return
69 | }
70 |
71 | func (o *Opt) String() (s string) {
72 | return strconv.FormatInt(o.v.Load(), 10)
73 | }
74 |
75 | func (o *Opt) Expanded() (s string) { return o.String() }
76 |
77 | func (o *Opt) SetExpanded(s string) {
78 | err := o.FromString(s)
79 | check(err)
80 | }
81 |
82 | func (o *Opt) Value() (c config.Concrete) {
83 | c = config.NewConcrete()
84 | c.Integer = func() int64 { return o.v.Load() }
85 | return
86 | }
87 |
88 | func Clamp(o *Opt, min, max int64) func(*Opt) {
89 | return func(o *Opt) {
90 | v := o.v.Load()
91 | if v < min {
92 | o.v.Store(min)
93 | } else if v > max {
94 | o.v.Store(max)
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/pkg/proc/opts/meta/metadata.go:
--------------------------------------------------------------------------------
1 | package meta
2 |
3 | type Type string
4 |
5 | // Type has same name as string for neater comparisons.
6 | const (
7 | Bool Type = "Bool"
8 | Duration Type = "Duration"
9 | Float Type = "Float"
10 | Integer Type = "Integer"
11 | List Type = "List"
12 | Text Type = "Text"
13 | )
14 |
15 | // Data is the specification for a Metadata
16 | type Data struct {
17 | Aliases []string
18 | Tags []string
19 | Label string
20 | Description string
21 | Documentation string
22 | Default string
23 | Options []string
24 | }
25 |
26 | // Metadata is a set of accessor functions that never write to the store and
27 | // thus do not create race conditions.
28 | type Metadata struct {
29 | Aliases func() []string
30 | Tags func() []string
31 | Label func() string
32 | Description func() string
33 | Documentation func() string
34 | Default func() string
35 | Options func() []string
36 | Typ Type
37 | }
38 |
39 | // New loads Data into a Metadata.
40 | func New(d Data, t Type) Metadata {
41 | return Metadata{
42 | func() []string { return d.Aliases },
43 | func() []string { return d.Tags },
44 | func() string { return d.Label },
45 | func() string { return d.Description },
46 | func() string { return d.Documentation },
47 | func() string { return d.Default },
48 | func() []string { return d.Options },
49 | t,
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/pkg/proc/opts/normalize/addresses.go:
--------------------------------------------------------------------------------
1 | package normalize
2 |
3 | import (
4 | "net"
5 | "strconv"
6 |
7 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
8 | )
9 |
10 | var (
11 | log = log2.GetLogger()
12 | check = log.E.Chk
13 | )
14 |
15 | // Address returns addr with the passed default port appended if there is not
16 | // already a port specified.
17 | func Address(addr, defaultPort string, userOnly bool) (a string, e error) {
18 | var p string
19 | a, p, e = net.SplitHostPort(addr)
20 | if log.E.Chk(e) || p == "" {
21 | return net.JoinHostPort(a, defaultPort), e
22 | }
23 | if userOnly {
24 | p = ClampPortRange(p, defaultPort, 1024, 65535)
25 | } else {
26 | p = ClampPortRange(p, defaultPort, 1, 65535)
27 | }
28 | return net.JoinHostPort(a, p), e
29 | }
30 |
31 | // Addresses returns a new slice with all the passed peer addresses normalized
32 | // with the given default port, and all duplicates removed.
33 | func Addresses(addrs []string, defaultPort string, userOnly bool) (a []string,
34 | e error) {
35 |
36 | for i := range addrs {
37 | addrs[i], e = Address(addrs[i], defaultPort, userOnly)
38 | }
39 | a = RemoveDuplicateAddresses(addrs)
40 | return
41 | }
42 |
43 | // RemoveDuplicateAddresses returns a new slice with all duplicate entries in
44 | // addrs removed.
45 | func RemoveDuplicateAddresses(addrs []string) (result []string) {
46 | result = make([]string, 0, len(addrs))
47 | seen := map[string]struct{}{}
48 | for _, val := range addrs {
49 | if _, ok := seen[val]; !ok {
50 | result = append(result, val)
51 | seen[val] = struct{}{}
52 | }
53 | }
54 | return result
55 | }
56 |
57 | func ClampPortRange(port, defaultPort string, min, max int) string {
58 | p, err := strconv.Atoi(port)
59 | if err != nil {
60 | return defaultPort
61 | }
62 | if p < min {
63 | port = strconv.FormatInt(int64(min), 10)
64 | } else if p > max {
65 | port = strconv.FormatInt(int64(max), 10)
66 | }
67 | return port
68 | }
69 |
--------------------------------------------------------------------------------
/pkg/proc/opts/normalize/paths.go:
--------------------------------------------------------------------------------
1 | package normalize
2 |
3 | import (
4 | "os"
5 | "os/user"
6 | "path/filepath"
7 | "strings"
8 |
9 | "git.indra-labs.org/dev/ind/pkg/util/appdata"
10 | )
11 |
12 | func ResolvePath(input, appName string, abs bool) (cleaned string, e error) {
13 | if strings.HasPrefix(input, "~") {
14 | homeDir := getHomeDir()
15 | input = strings.Replace(input, "~", homeDir, 1)
16 | cleaned = filepath.Clean(input)
17 | } else {
18 | if abs {
19 | if cleaned, e = filepath.Abs(cleaned); log.E.Chk(e) {
20 | return
21 | }
22 | // if the path is relative, either ./ or not starting
23 | // with a / then we assume the path is relative to the
24 | // app data directory
25 | } else if !strings.HasPrefix(string(os.PathSeparator), cleaned) ||
26 | strings.HasPrefix("."+string(os.PathSeparator), cleaned) {
27 |
28 | cleaned = filepath.Join(appdata.Dir(appName, false), cleaned)
29 | }
30 | }
31 | return
32 | }
33 |
34 | func getHomeDir() (homeDir string) {
35 | var usr *user.User
36 | var e error
37 | if usr, e = user.Current(); !log.E.Chk(e) {
38 | homeDir = usr.HomeDir
39 | }
40 | // Fall back to standard HOME environment variable that works for most
41 | // POSIX OSes if the directory from the Go standard lib failed.
42 | if e != nil || homeDir == "" {
43 | homeDir = os.Getenv("HOME")
44 | }
45 | return homeDir
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/proc/opts/toggle/spec.go:
--------------------------------------------------------------------------------
1 | package toggle
2 |
3 | import (
4 | "fmt"
5 | "git.indra-labs.org/dev/ind/pkg/util/path"
6 | "strconv"
7 | "strings"
8 |
9 | "go.uber.org/atomic"
10 |
11 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
12 | "git.indra-labs.org/dev/ind/pkg/proc/opts/config"
13 | "git.indra-labs.org/dev/ind/pkg/proc/opts/meta"
14 | )
15 |
16 | var (
17 | log = log2.GetLogger()
18 | check = log.E.Chk
19 | )
20 |
21 | type Opt struct {
22 | p path.Path
23 | m meta.Metadata
24 | v atomic.Bool
25 | h []Hook
26 | }
27 |
28 | func (o *Opt) Path() (p path.Path) { return o.p }
29 |
30 | func (o *Opt) SetPath(p path.Path) { o.p = p }
31 |
32 | var _ config.Option = &Opt{}
33 |
34 | type Hook func(*Opt) error
35 |
36 | func New(m meta.Data, h ...Hook) (o *Opt) {
37 |
38 | if m.Default == "" {
39 | m.Default = "false"
40 | }
41 |
42 | o = &Opt{m: meta.New(m, meta.Bool), h: h}
43 |
44 | return
45 | }
46 |
47 | func (o *Opt) Meta() meta.Metadata { return o.m }
48 | func (o *Opt) Type() meta.Type { return o.m.Typ }
49 | func (o *Opt) ToOption() config.Option { return o }
50 |
51 | func (o *Opt) RunHooks() (e error) {
52 | for i := range o.h {
53 | e = o.h[i](o)
54 | if e != nil {
55 | return
56 | }
57 | }
58 | return
59 | }
60 |
61 | func (o *Opt) FromValue(v bool) *Opt {
62 | o.v.Store(v)
63 | return o
64 | }
65 |
66 | func (o *Opt) FromString(s string) (e error) {
67 | s = strings.TrimSpace(s)
68 | switch s {
69 | case "f", "false", "off", "-":
70 | o.v.Store(false)
71 | case "t", "true", "on", "+":
72 | o.v.Store(true)
73 | default:
74 | return fmt.Errorf("string '%s' does not parse to boolean", s)
75 | }
76 | e = o.RunHooks()
77 | return
78 | }
79 |
80 | func (o *Opt) String() (s string) {
81 | return strconv.FormatBool(o.v.Load())
82 | }
83 |
84 | func (o *Opt) Expanded() (s string) { return o.String() }
85 |
86 | func (o *Opt) SetExpanded(s string) {
87 | err := o.FromString(s)
88 | log.E.Chk(err)
89 | }
90 |
91 | func (o *Opt) Value() (c config.Concrete) {
92 | c = config.NewConcrete()
93 | c.Bool = func() bool { return o.v.Load() }
94 | return
95 | }
96 |
--------------------------------------------------------------------------------
/pkg/rpc/auth.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import (
4 | "github.com/lightningnetwork/lnd/macaroons"
5 | "gopkg.in/macaroon.v2"
6 | )
7 |
8 | type MacaroonCredential struct{ macaroons.MacaroonCredential }
9 |
10 | // RequireTransportSecurity implements the PerRPCCredentials interface.
11 | func (m MacaroonCredential) RequireTransportSecurity() bool {
12 | return false
13 | }
14 |
15 | // NewMacaroonCredential returns a copy of the passed macaroon wrapped in a
16 | // MacaroonCredential struct which implements PerRPCCredentials.
17 | func NewMacaroonCredential(m *macaroon.Macaroon) (MacaroonCredential, error) {
18 | ms := MacaroonCredential{}
19 |
20 | // The macaroon library's Clone() method has a subtle bug that doesn't
21 | // correctly clone all caveats. We need to use our own, safe clone
22 | // function instead.
23 | var err error
24 | ms.Macaroon, err = macaroons.SafeCopyMacaroon(m)
25 | if err != nil {
26 | return ms, err
27 | }
28 |
29 | return ms, nil
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/rpc/client.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import (
4 | "golang.zx2c4.com/wireguard/conn"
5 | "golang.zx2c4.com/wireguard/device"
6 | "golang.zx2c4.com/wireguard/tun"
7 | "golang.zx2c4.com/wireguard/tun/netstack"
8 | "net/netip"
9 | "strconv"
10 | )
11 |
12 | func getNetworkInstance(opts *dialOptions) (net *netstack.Net, err error) {
13 |
14 | var tunnel tun.Device
15 |
16 | if tunnel, net, err = netstack.CreateNetTUN([]netip.Addr{netip.MustParseAddr(opts.peerRPCIP)}, []netip.Addr{}, opts.mtu); check(err) {
17 | return nil, err
18 | }
19 |
20 | dev := device.NewDevice(tunnel, conn.NewDefaultBind(), device.NewLogger(device.LogLevelError, "client "))
21 |
22 | dev.SetPrivateKey(opts.key.AsDeviceKey())
23 |
24 | deviceConf := "" +
25 | "public_key=" + opts.peerPubKey.HexString() + "\n" +
26 | "endpoint=" + opts.endpoint.String() + "\n" +
27 | "allowed_ip=" + opts.rpcEndpoint.Address() + "/32\n" +
28 | "persistent_keepalive_interval=" + strconv.Itoa(opts.keepAliveInterval) + "\n"
29 |
30 | if err = dev.IpcSet(deviceConf); check(err) {
31 | return
32 | }
33 |
34 | return net, nil
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/rpc/device.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import (
4 | "golang.zx2c4.com/wireguard/device"
5 | "net/netip"
6 | "strconv"
7 | )
8 |
9 | var (
10 | dev *device.Device
11 | deviceRPCIP netip.Addr = netip.MustParseAddr("192.168.37.1")
12 | deviceRPCPort uint16 = 80
13 | )
14 |
15 | func configureDevice() {
16 |
17 | var err error
18 |
19 | dev.SetPrivateKey(tunKey.AsDeviceKey())
20 | dev.IpcSet("listen_port=" + strconv.Itoa(int(o.tunPort)))
21 |
22 | for _, peer_whitelist := range tunWhitelist {
23 |
24 | deviceConf := "" +
25 | "public_key=" + peer_whitelist.HexString() + "\n" +
26 | "allowed_ip=192.168.37.2/32\n"
27 |
28 | if err = dev.IpcSet(deviceConf); check(err) {
29 | startupErrors <- err
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/rpc/dialer.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "golang.zx2c4.com/wireguard/tun/netstack"
7 | "google.golang.org/grpc"
8 | "google.golang.org/grpc/credentials/insecure"
9 | "net"
10 | "strings"
11 | )
12 |
13 | var (
14 | rpcEndpointIp string = "192.168.37.1"
15 | rpcEndpointPort string = "80"
16 | )
17 |
18 | func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *grpc.ClientConn, err error) {
19 |
20 | if strings.HasPrefix(target, "unix://") {
21 | return grpc.Dial(
22 | target,
23 | grpc.WithTransportCredentials(insecure.NewCredentials()),
24 | )
25 | }
26 |
27 | if !strings.HasPrefix(target, "noise://") {
28 | return nil, errors.New("Unsupported protocol. Only unix:// or noise://")
29 | }
30 |
31 | dialOpts := &dialOptions{
32 | endpoint: EndpointString(target),
33 | rpcEndpoint: EndpointString("192.168.37.1:80"),
34 | peerRPCIP: "192.168.37.2",
35 | mtu: 1420,
36 | }
37 |
38 | for _, opt := range opts {
39 | opt.apply(dialOpts)
40 | }
41 |
42 | var network *netstack.Net
43 |
44 | if network, err = getNetworkInstance(dialOpts); check(err) {
45 | return
46 | }
47 |
48 | return grpc.DialContext(ctx,
49 | dialOpts.rpcEndpoint.String(),
50 | grpc.WithTransportCredentials(insecure.NewCredentials()),
51 | grpc.WithContextDialer(func(ctx context.Context, address string) (net.Conn, error) {
52 | return network.DialContext(ctx, "tcp4", address)
53 | }))
54 | }
55 |
56 | func Dial(target string, opts ...DialOption) (conn *grpc.ClientConn, err error) {
57 | return DialContext(context.Background(), target, opts...)
58 | }
59 |
--------------------------------------------------------------------------------
/pkg/rpc/dialer_options.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | // dialOptions configure a Dial call. dialOptions are set by the DialOption
4 | // values passed to Dial.
5 | type dialOptions struct {
6 | endpoint Endpoint
7 | rpcEndpoint Endpoint
8 | key PrivateKey
9 | peerPubKey PublicKey
10 | peerRPCIP string
11 | keepAliveInterval int
12 | mtu int
13 | }
14 |
15 | // DialOption configures how we set up the connection.
16 | type DialOption interface {
17 | apply(*dialOptions)
18 | }
19 |
20 | // funcDialOption wraps a function that modifies dialOptions into an
21 | // implementation of the DialOption interface.
22 | type funcDialOption struct {
23 | f func(*dialOptions)
24 | }
25 |
26 | func (fdo *funcDialOption) apply(do *dialOptions) {
27 | fdo.f(do)
28 | }
29 |
30 | func newFuncDialOption(f func(*dialOptions)) *funcDialOption {
31 | return &funcDialOption{
32 | f: f,
33 | }
34 | }
35 |
36 | type joinDialOption struct {
37 | opts []DialOption
38 | }
39 |
40 | func (jdo *joinDialOption) apply(do *dialOptions) {
41 | for _, opt := range jdo.opts {
42 | opt.apply(do)
43 | }
44 | }
45 |
46 | func newJoinDialOption(opts ...DialOption) DialOption {
47 | return &joinDialOption{opts: opts}
48 | }
49 |
50 | func WithKeepAliveInterval(seconds int) DialOption {
51 | return newFuncDialOption(func(o *dialOptions) {
52 | o.keepAliveInterval = seconds
53 | })
54 | }
55 |
56 | func WithPeer(pubKey string) DialOption {
57 | return newFuncDialOption(func(o *dialOptions) {
58 | o.peerPubKey = DecodePublicKey(pubKey)
59 | })
60 | }
61 |
62 | func WithPrivateKey(key string) DialOption {
63 | return newFuncDialOption(func(o *dialOptions) {
64 | o.key = DecodePrivateKey(key)
65 | })
66 | }
67 |
--------------------------------------------------------------------------------
/pkg/rpc/doc.go:
--------------------------------------------------------------------------------
1 | // Package rpc provides an RPC server for use in remote control and external application integration.
2 | package rpc
3 |
--------------------------------------------------------------------------------
/pkg/rpc/endpoint.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import "strings"
4 |
5 | type Endpoint string
6 |
7 | func (e Endpoint) Address() string {
8 |
9 | before, _, found := strings.Cut(string(e), ":")
10 |
11 | if !found {
12 | return ""
13 | }
14 |
15 | return before
16 | }
17 |
18 | func (e Endpoint) Port() string {
19 |
20 | _, after, found := strings.Cut(string(e), ":")
21 |
22 | if !found {
23 | return ""
24 | }
25 |
26 | return after
27 | }
28 |
29 | func (e Endpoint) String() string {
30 | return string(e)
31 | }
32 |
33 | func EndpointString(endpoint string) (ep Endpoint) {
34 |
35 | _, after, found := strings.Cut(string(endpoint), "//")
36 |
37 | if !found {
38 | ep = Endpoint(endpoint)
39 |
40 | return
41 | }
42 |
43 | ep = Endpoint(after)
44 |
45 | return
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/rpc/examples/log.go:
--------------------------------------------------------------------------------
1 | package examples
2 |
3 | import (
4 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
5 | )
6 |
7 | var (
8 | log = log2.GetLogger()
9 | check = log.E.Chk
10 | )
11 |
--------------------------------------------------------------------------------
/pkg/rpc/examples/tunnel_hello.go:
--------------------------------------------------------------------------------
1 | package examples
2 |
3 | import (
4 | "context"
5 | "os"
6 |
7 | "github.com/tutorialedge/go-grpc-tutorial/chat"
8 | "google.golang.org/grpc"
9 |
10 | "git.indra-labs.org/dev/ind/pkg/rpc"
11 | )
12 |
13 | func TunnelHello(ctx context.Context) {
14 |
15 | var err error
16 | var conn *grpc.ClientConn
17 |
18 | conn, err = rpc.DialContext(ctx,
19 | "noise://[::1]:18222",
20 | rpc.WithPrivateKey("Aj9CfbE1pXEVxPfjSaTwdY3B4kYHbwsTSyT3nrc34ATN"),
21 | rpc.WithPeer("G52UmsQpUmN2zFMkJaP9rwCvqQJzi1yHKA9RTrLJTk9f"),
22 | rpc.WithKeepAliveInterval(5),
23 | )
24 |
25 | if err != nil {
26 | check(err)
27 | os.Exit(1)
28 | }
29 |
30 | c := chat.NewChatServiceClient(conn)
31 |
32 | response, err := c.SayHello(context.Background(), &chat.Message{Body: "Hello From Alice!"})
33 |
34 | if err != nil {
35 | check(err)
36 | return
37 | }
38 |
39 | log.I.F(response.Body)
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/rpc/examples/unix_hello.go:
--------------------------------------------------------------------------------
1 | package examples
2 |
3 | import (
4 | "context"
5 | "os"
6 |
7 | "github.com/tutorialedge/go-grpc-tutorial/chat"
8 | "google.golang.org/grpc"
9 |
10 | "git.indra-labs.org/dev/ind/pkg/rpc"
11 | )
12 |
13 | func UnixHello(ctx context.Context) {
14 |
15 | var err error
16 | var conn *grpc.ClientConn
17 |
18 | conn, err = rpc.Dial("unix:///tmp/indra.sock")
19 |
20 | if err != nil {
21 | check(err)
22 | os.Exit(1)
23 | }
24 |
25 | c := chat.NewChatServiceClient(conn)
26 |
27 | response, err := c.SayHello(context.Background(), &chat.Message{Body: "Hello From Alice!"})
28 |
29 | if err != nil {
30 | check(err)
31 | return
32 | }
33 |
34 | log.I.F(response.Body)
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/rpc/examples/unix_unlock.go:
--------------------------------------------------------------------------------
1 | package examples
2 |
3 | import (
4 | "context"
5 | "git.indra-labs.org/dev/ind/pkg/rpc"
6 | "git.indra-labs.org/dev/ind/pkg/storage"
7 | "google.golang.org/grpc"
8 | "os"
9 | )
10 |
11 | func UnixUnlock(ctx context.Context) {
12 |
13 | var err error
14 | var conn *grpc.ClientConn
15 |
16 | conn, err = rpc.Dial("unix:///tmp/indra.sock")
17 |
18 | if err != nil {
19 | check(err)
20 | os.Exit(1)
21 | }
22 |
23 | u := storage.NewUnlockServiceClient(conn)
24 |
25 | _, err = u.Unlock(ctx, &storage.UnlockRequest{
26 | Key: "979nrx9ry9Re6UqWXYaGqLEne8NS7TzgHFiS8KARABV8",
27 | })
28 |
29 | if err != nil {
30 | check(err)
31 | return
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/pkg/rpc/flags.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import (
4 | "github.com/spf13/cobra"
5 | "github.com/spf13/viper"
6 | )
7 |
8 | var (
9 | UnixPathFlag = "rpc-unix-listen"
10 | TunEnableFlag = "rpc-tun-enable"
11 | TunPortFlag = "rpc-tun-port"
12 | TunPeersFlag = "rpc-tun-peer"
13 | )
14 | var (
15 | unixPath string
16 | tunEnabled bool = false
17 | tunPort int = 0
18 | tunPeersRaw = []string{}
19 | )
20 |
21 | func InitFlags(cmd *cobra.Command) {
22 |
23 | cmd.PersistentFlags().StringVarP(&unixPath, UnixPathFlag, "",
24 | "",
25 | "binds to a unix socket with path (default is $HOME/.indra/indra.sock)",
26 | )
27 |
28 | viper.BindPFlag(UnixPathFlag, cmd.PersistentFlags().Lookup(UnixPathFlag))
29 |
30 | cmd.PersistentFlags().BoolVarP(&tunEnabled, TunEnableFlag, "",
31 | false,
32 | "enables the rpc server tunnel (default false)",
33 | )
34 |
35 | viper.BindPFlag(TunEnableFlag, cmd.PersistentFlags().Lookup(TunEnableFlag))
36 |
37 | cmd.PersistentFlags().IntVarP(&tunPort, TunPortFlag, "",
38 | tunPort,
39 | "binds the udp server to port (random if not selected)",
40 | )
41 |
42 | viper.BindPFlag(TunPortFlag, cmd.PersistentFlags().Lookup(TunPortFlag))
43 |
44 | cmd.PersistentFlags().StringSliceVarP(&tunPeersRaw, TunPeersFlag, "",
45 | tunPeersRaw,
46 | "adds a peer id to the whitelist for access",
47 | )
48 |
49 | viper.BindPFlag(TunPeersFlag, cmd.PersistentFlags().Lookup(TunPeersFlag))
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/rpc/log.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import (
4 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
5 | )
6 |
7 | var (
8 | log = log2.GetLogger()
9 | check = log.E.Chk
10 | )
11 |
--------------------------------------------------------------------------------
/pkg/rpc/server.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import (
4 | "google.golang.org/grpc"
5 | "sync"
6 | )
7 |
8 | var (
9 | server *grpc.Server
10 | o *ServerOptions
11 | )
12 |
13 | var (
14 | inUse sync.Mutex
15 | isRunning bool
16 | )
17 |
18 | func RunWith(r func(srv *grpc.Server), opts ...ServerOption) {
19 |
20 | if !inUse.TryLock() {
21 | log.E.Ln("rpc server is in use.")
22 | return
23 | }
24 |
25 | log.I.Ln("initializing the rpc server")
26 |
27 | o = &ServerOptions{
28 | &storeMem{},
29 | unixPathDefault,
30 | false,
31 | NullPort,
32 | []string{},
33 | }
34 |
35 | for _, opt := range opts {
36 | opt.apply(o)
37 | }
38 |
39 | if o.unixPath != "" {
40 | log.I.Ln("enabling rpc unix listener:")
41 | log.I.F("- [/unix%s]", o.unixPath)
42 |
43 | isUnixSockEnabled = true
44 | }
45 |
46 | if o.tunEnable {
47 | configureTunnel()
48 | }
49 |
50 | isConfigured <- true
51 |
52 | server = grpc.NewServer(
53 | //grpc.WithPerRPCCredentials(),
54 | )
55 | r(server)
56 |
57 | go start()
58 | }
59 |
60 | func Options() *ServerOptions {
61 | return o
62 | }
63 |
64 | func start() {
65 |
66 | log.I.Ln("starting rpc server")
67 |
68 | var err error
69 |
70 | createTunnel()
71 |
72 | if err = startTunnel(server); check(err) {
73 | startupErrors <- err
74 | return
75 | }
76 |
77 | if err = startUnixSocket(server); check(err) {
78 | startupErrors <- err
79 | return
80 | }
81 |
82 | isRunning = true
83 |
84 | log.I.Ln("rpc server is ready")
85 | isReady <- true
86 | }
87 |
88 | func Shutdown() {
89 |
90 | if !isRunning {
91 | return
92 | }
93 |
94 | log.I.Ln("shutting down rpc server")
95 |
96 | server.GracefulStop()
97 |
98 | var err error
99 |
100 | //err = stopUnixSocket()
101 | //
102 | //check(err)
103 |
104 | err = stopTunnel()
105 |
106 | check(err)
107 |
108 | isRunning = false
109 |
110 | inUse.Unlock()
111 |
112 | log.I.Ln("- rpc server shutdown completed")
113 | }
114 |
--------------------------------------------------------------------------------
/pkg/rpc/server_options.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | type ServerOptions struct {
4 | store Store
5 | unixPath string
6 | tunEnable bool
7 | tunPort uint16
8 | tunPeers []string
9 | }
10 |
11 | func (s *ServerOptions) GetTunPort() uint16 { return s.tunPort }
12 |
13 | type ServerOption interface {
14 | apply(*ServerOptions)
15 | }
16 |
17 | type funcServerOption struct {
18 | f func(*ServerOptions)
19 | }
20 |
21 | func (fdo *funcServerOption) apply(do *ServerOptions) {
22 | fdo.f(do)
23 | }
24 |
25 | func newFuncServerOption(f func(*ServerOptions)) *funcServerOption {
26 | return &funcServerOption{
27 | f: f,
28 | }
29 | }
30 |
31 | func WithDisableTunnel() ServerOption {
32 | return newFuncServerOption(func(o *ServerOptions) {
33 | o.tunEnable = false
34 | })
35 | }
36 |
37 | func WithStore(store Store) ServerOption {
38 | return newFuncServerOption(func(o *ServerOptions) {
39 | o.store = store
40 | })
41 | }
42 |
43 | func WithUnixPath(path string) ServerOption {
44 | return newFuncServerOption(func(o *ServerOptions) {
45 | o.unixPath = path
46 | })
47 | }
48 |
49 | func WithTunOptions(port uint16, peers []string) ServerOption {
50 | return newFuncServerOption(func(o *ServerOptions) {
51 | o.tunEnable = true
52 | o.tunPort = port
53 | o.tunPeers = peers
54 | })
55 | }
56 |
--------------------------------------------------------------------------------
/pkg/rpc/signals.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | var (
4 | startupErrors = make(chan error, 128)
5 | isConfigured = make(chan bool, 1)
6 | isReady = make(chan bool, 1)
7 | )
8 |
9 | func WhenStartFailed() chan error {
10 | return startupErrors
11 | }
12 |
13 | func IsConfigured() chan bool {
14 | return isConfigured
15 | }
16 |
17 | func IsReady() chan bool {
18 | return isReady
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/rpc/socket_unix.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import (
4 | "google.golang.org/grpc"
5 | "net"
6 | "os"
7 | )
8 |
9 | const unixPathDefault = "/tmp/indra.sock"
10 |
11 | var (
12 | isUnixSockEnabled bool = false
13 | unixSock net.Listener
14 | )
15 |
16 | func startUnixSocket(srv *grpc.Server) (err error) {
17 |
18 | if !isUnixSockEnabled {
19 | return
20 | }
21 |
22 | if unixSock, err = net.Listen("unix", o.unixPath); err != nil {
23 | return
24 | }
25 |
26 | go srv.Serve(unixSock)
27 |
28 | return
29 | }
30 |
31 | func stopUnixSocket() (err error) {
32 |
33 | if !isUnixSockEnabled {
34 | return
35 | }
36 |
37 | if unixSock != nil {
38 | if err = unixSock.Close(); err != nil {
39 | // continue
40 | }
41 | }
42 |
43 | os.Remove(o.unixPath)
44 |
45 | return
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/rpc/store.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import (
4 | "errors"
5 | "github.com/dgraph-io/badger/v3"
6 | )
7 |
8 | var (
9 | ErrKeyNotExists error = errors.New("key not found")
10 | )
11 |
12 | var (
13 | tunKeyKey = "rpc-tun-key"
14 | )
15 |
16 | type Store interface {
17 | Reset()
18 |
19 | SetKey(key *PrivateKey) error
20 |
21 | GetKey() (*PrivateKey, error)
22 | }
23 |
24 | type storeMem struct {
25 | key *PrivateKey
26 | }
27 |
28 | func (s *storeMem) Reset() {
29 | s.key = nil
30 | }
31 |
32 | func (s *storeMem) SetKey(key *PrivateKey) error {
33 | s.key = key
34 | return nil
35 | }
36 |
37 | func (s *storeMem) GetKey() (*PrivateKey, error) {
38 |
39 | if s.key == nil {
40 | return nil, ErrKeyNotExists
41 | }
42 |
43 | if s.key.IsZero() {
44 | return nil, ErrKeyNotExists
45 | }
46 |
47 | return s.key, nil
48 | }
49 |
50 | type BadgerStore struct {
51 | *badger.DB
52 | }
53 |
54 | func (s *BadgerStore) Reset() {
55 |
56 | s.Update(func(txn *badger.Txn) error {
57 | txn.Delete([]byte(tunKeyKey))
58 |
59 | return nil
60 | })
61 | }
62 |
63 | func (s *BadgerStore) SetKey(key *PrivateKey) error {
64 |
65 | s.Update(func(txn *badger.Txn) error {
66 | err := txn.Set([]byte(tunKeyKey), key.Bytes())
67 | return err
68 | })
69 |
70 | return nil
71 | }
72 |
73 | func (s *BadgerStore) GetKey() (*PrivateKey, error) {
74 |
75 | var err error
76 | var item *badger.Item
77 |
78 | err = s.View(func(txn *badger.Txn) error {
79 | item, err = txn.Get([]byte(tunKeyKey))
80 | return err
81 | })
82 |
83 | if err == badger.ErrKeyNotFound {
84 | return nil, ErrKeyNotExists
85 | }
86 |
87 | var key PrivateKey
88 |
89 | err = item.Value(func(val []byte) error {
90 | key.DecodeBytes(val)
91 | return nil
92 | })
93 |
94 | return &key, err
95 | }
96 |
--------------------------------------------------------------------------------
/pkg/rpc/tunnel.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import (
4 | "golang.zx2c4.com/wireguard/conn"
5 | "golang.zx2c4.com/wireguard/device"
6 | "golang.zx2c4.com/wireguard/tun"
7 | "golang.zx2c4.com/wireguard/tun/netstack"
8 | "google.golang.org/grpc"
9 | "net"
10 | "net/netip"
11 | )
12 |
13 | const NullPort = 0
14 |
15 | var (
16 | network *netstack.Net
17 | tunnel tun.Device
18 | tcpSock net.Listener
19 | )
20 |
21 | var (
22 | tunKey *PrivateKey
23 | tunWhitelist []PublicKey
24 | tunnelMTU int = 1420
25 | )
26 |
27 | func createTunnel() {
28 |
29 | var err error
30 |
31 | if tunnel, network, err = netstack.CreateNetTUN([]netip.Addr{deviceRPCIP}, []netip.Addr{}, tunnelMTU); check(err) {
32 | startupErrors <- err
33 | return
34 | }
35 |
36 | dev = device.NewDevice(tunnel, conn.NewDefaultBind(), device.NewLogger(device.LogLevelError, "server "))
37 | }
38 |
39 | func startTunnel(srv *grpc.Server) (err error) {
40 |
41 | if !o.tunEnable {
42 | return
43 | }
44 |
45 | configureDevice()
46 |
47 | if err = dev.Up(); check(err) {
48 | startupErrors <- err
49 | return
50 | }
51 |
52 | if tcpSock, err = network.ListenTCPAddrPort(netip.AddrPortFrom(deviceRPCIP, deviceRPCPort)); check(err) {
53 | startupErrors <- err
54 | return
55 | }
56 |
57 | go srv.Serve(tcpSock)
58 |
59 | return
60 | }
61 |
62 | func stopTunnel() (err error) {
63 |
64 | if !o.tunEnable {
65 | return
66 | }
67 |
68 | if err = tcpSock.Close(); check(err) {
69 | // continue
70 | }
71 |
72 | dev.Close()
73 |
74 | return
75 | }
76 |
--------------------------------------------------------------------------------
/pkg/rpc/tunnel_config.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import "errors"
4 |
5 | func configureTunnel() {
6 |
7 | if !o.tunEnable {
8 | return
9 | }
10 |
11 | log.I.Ln("enabling rpc tunnel")
12 |
13 | configureTunnelPort()
14 |
15 | log.I.Ln("rpc tunnel listeners:")
16 | log.I.F("- [/ip4/0.0.0.0/udp/%d /ip6/:::/udp/%d]", o.tunPort, o.tunPort)
17 |
18 | configureTunnelKey()
19 | configurePeerWhitelist()
20 | }
21 |
22 | func configureTunnelKey() {
23 |
24 | log.I.Ln("looking for key in storage")
25 |
26 | var err error
27 |
28 | tunKey, err = o.store.GetKey()
29 |
30 | if err == nil {
31 |
32 | log.I.Ln("rpc tunnel public key:")
33 | log.I.Ln("-", tunKey.PubKey().Encode())
34 |
35 | return
36 | }
37 |
38 | if !errors.Is(err, ErrKeyNotExists) {
39 | return
40 | }
41 |
42 | log.I.Ln("key not provided, generating a new one.")
43 |
44 | tunKey, _ = NewPrivateKey()
45 |
46 | o.store.SetKey(tunKey)
47 |
48 | log.I.Ln("rpc tunnel public key:")
49 | log.I.Ln("-", tunKey.PubKey().Encode())
50 | }
51 |
52 | func configureTunnelPort() {
53 |
54 | if o.tunPort != NullPort {
55 | return
56 | }
57 |
58 | log.I.Ln("rpc tunnel port not provided, generating a random one.")
59 |
60 | o.tunPort = genRandomPort(10000) // no paricular reason why 10000 minimum, would be better to just use 0 bind?
61 | }
62 |
63 | func configurePeerWhitelist() {
64 |
65 | if len(o.tunPeers) == 0 {
66 | return
67 | }
68 |
69 | log.I.Ln("rpc tunnel whitelisted peers:")
70 |
71 | for _, peer := range o.tunPeers {
72 |
73 | var pubKey PublicKey
74 |
75 | pubKey.Decode(peer)
76 |
77 | log.I.Ln("-", pubKey.Encode())
78 |
79 | tunWhitelist = append(tunWhitelist, pubKey)
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/pkg/rpc/util.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import (
4 | "math/rand"
5 | "time"
6 | )
7 |
8 | func genRandomPort(offset int) uint16 {
9 |
10 | rand.Seed(time.Now().Unix())
11 |
12 | return uint16(rand.Intn(65534-offset) + offset)
13 | }
14 |
--------------------------------------------------------------------------------
/pkg/seed/log.go:
--------------------------------------------------------------------------------
1 | package seed
2 |
3 | import (
4 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
5 | )
6 |
7 | var (
8 | log = log2.GetLogger()
9 | check = log.E.Chk
10 | )
11 |
--------------------------------------------------------------------------------
/pkg/seed/signals.go:
--------------------------------------------------------------------------------
1 | package seed
2 |
3 | var (
4 | startupErrors = make(chan error, 32)
5 | isReadyChan = make(chan bool, 1)
6 | isShutdownChan = make(chan bool, 1)
7 | )
8 |
9 | func WhenStartFailed() chan error {
10 | return startupErrors
11 | }
12 |
13 | func WhenReady() chan bool {
14 | return isReadyChan
15 | }
16 |
17 | func WhenShutdown() chan bool {
18 | return isShutdownChan
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/splicer/i32/int32.go:
--------------------------------------------------------------------------------
1 | package i32
2 |
3 | import "encoding/binary"
4 |
5 | const Len = 4
6 |
7 | // S is a 4 byte value that stores an int32. S here to signify it is signed.
8 | type S struct {
9 | b []byte
10 | }
11 |
12 | // New allocates bytes to store a new i32.S in. Note that this allocates memory.
13 | func New() *S { return &S{b: make([]byte, Len)} }
14 |
15 | // NewFrom creates a 32-bit integer from raw bytes, if the slice is at least Len
16 | // bytes long. This can be used to snip out an encoded segment which should
17 | // return a value from a call to Get.
18 | //
19 | // The remaining bytes, if any, are returned for further processing.
20 | func NewFrom(b []byte) (s *S, rem []byte) {
21 | // If the bytes are less than Len the input is invalid and nil will be
22 | // returned.
23 | if len(b) < Len {
24 | return
25 | }
26 | // This slices the input, meaning no copy is required, only allocating the
27 | // slice pointer.
28 | s = &S{b: b[:Len]}
29 | if len(b) > Len {
30 | rem = b[Len:]
31 | }
32 | return
33 | }
34 |
35 | func (s *S) Read() (out []byte) {
36 | if len(s.b) >= Len {
37 | out = s.b[:Len]
38 | }
39 | return
40 | }
41 |
42 | func (s *S) Write(by []byte) (out []byte) {
43 | if len(by) >= Len {
44 | s.b = []byte{by[0], by[1], by[2], by[3]}
45 | if len(by) > Len {
46 | out = by[Len:]
47 | }
48 | }
49 | return
50 | }
51 |
52 | func (s *S) Len() int { return len(s.b) }
53 |
54 | func (s *S) Get() (v interface{}) {
55 | if len(s.b) >= Len {
56 | val := int32(binary.BigEndian.Uint32(s.b))
57 | return &val
58 | }
59 | return
60 | }
61 |
62 | func (s *S) Put(v interface{}) interface{} {
63 | if len(s.b) < Len {
64 | s.b = make([]byte, Len)
65 | }
66 | var tv *int32
67 | var ok bool
68 | if tv, ok = v.(*int32); ok {
69 | binary.BigEndian.PutUint32(s.b[:Len], uint32(*tv))
70 | }
71 | return s
72 | }
73 |
74 | // Assert takes an interface and if it is a t64.Time, returns the time.Time
75 | // value. If it is not the expected type, nil is returned.
76 | func Assert(v interface{}) (t *int32) {
77 | var tv *S
78 | var ok bool
79 | if tv, ok = v.(*S); ok {
80 | tt := tv.Get()
81 | // If this fails the return is nil, indicating failure.
82 | t, _ = tt.(*int32)
83 | }
84 | return
85 | }
86 |
--------------------------------------------------------------------------------
/pkg/splicer/i32/int32_test.go:
--------------------------------------------------------------------------------
1 | package i32
2 |
3 | import (
4 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
5 | "git.indra-labs.org/dev/ind/pkg/util/ci"
6 | "testing"
7 | )
8 |
9 | var (
10 | log = log2.GetLogger()
11 | fails = log.E.Chk
12 | )
13 |
14 | func TestS(t *testing.T) {
15 | ci.TraceIfNot()
16 |
17 | t1, t2 := New(), New()
18 |
19 | var val int32 = 234234
20 |
21 | // Encode in the value.
22 | t1.Put(&val)
23 |
24 | // Copy to the other.
25 | t2.Write(t1.Read())
26 |
27 | // Verify accessors work.
28 | var ta1, ta2 *int32
29 | if ta1 = Assert(t1); ta1 == nil {
30 | log.E.Ln("did not get expected time value")
31 | t.FailNow()
32 | }
33 | if ta2 = Assert(t2); ta2 == nil {
34 | log.E.Ln("did not get expected time value")
35 | t.FailNow()
36 | }
37 |
38 | // Verify the value survived the encode/decode.
39 | if *ta1 != *ta2 {
40 | t.FailNow()
41 | }
42 |
43 | // Test NewFrom correctly decodes and returns the trimmings.
44 | b1 := t1.Read()
45 | nb1, rem := NewFrom(append(b1, make([]byte, 5)...))
46 | if len(rem) != 5 || rem == nil {
47 | t.FailNow()
48 | }
49 | v := Assert(nb1)
50 | if *v != *ta1 {
51 | t.FailNow()
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/pkg/splicer/magic/magic.go:
--------------------------------------------------------------------------------
1 | package magic
2 |
3 | const Len = 4
4 |
5 | type Bytes struct {
6 | bytes []byte
7 | }
8 |
9 | // New allocates bytes to store a new magic.Bytes in. Note that this allocates
10 | // memory.
11 | func New() *Bytes { return &Bytes{bytes: make([]byte, Len)} }
12 |
13 | // NewFrom creates a 32-bit integer from raw bytes, if the slice is at least Len
14 | // bytes long. This can be used to snip out an encoded segment which should
15 | // return a value from a call to Get.
16 | //
17 | // The remaining bytes, if any, are returned for further processing.
18 | func NewFrom(b []byte) (s *Bytes, rem []byte) {
19 | if len(b) < Len {
20 | return
21 | }
22 | // This slices the input, meaning no copy is required, only allocating the
23 | // slice pointer.
24 | s = &Bytes{bytes: b[:Len]}
25 | if len(b) > Len {
26 | rem = b[Len:]
27 | }
28 | return
29 | }
30 |
31 | func (m Bytes) Len() (l int) { return len(m.bytes) }
32 |
33 | func (m Bytes) Read() (o []byte) {
34 | if len(m.bytes) >= Len {
35 | o = m.bytes[:Len]
36 | }
37 | return
38 | }
39 |
40 | func (m Bytes) Write(b []byte) (o []byte) {
41 | if len(b) >= Len {
42 | m.bytes = b[:3]
43 | // If there is more, return the excess.
44 | if len(b) > Len {
45 | o = b[Len:]
46 | }
47 | }
48 | return
49 | }
50 |
51 | func (m Bytes) Get() (v interface{}) {
52 | if len(m.bytes) >= Len {
53 | val := string(m.bytes[:Len])
54 | v = &val
55 | }
56 | return
57 | }
58 |
59 | func (m Bytes) Put(v interface{}) (o interface{}) {
60 | var tv *string
61 | var ok bool
62 | if tv, ok = v.(*string); ok {
63 | bytes := []byte(*tv)
64 | if len(bytes) == Len {
65 | m.bytes = bytes
66 | }
67 | }
68 | return
69 | }
70 |
71 | // Assert takes an interface and if it is a duration.Time, returns the time.Time
72 | // value. If it is not the expected type, nil is returned.
73 | func Assert(v interface{}) (t *string) {
74 | var tv *Bytes
75 | var ok bool
76 | if tv, ok = v.(*Bytes); ok {
77 | tt := tv.Get()
78 | // If this fails the return is nil, indicating failure.
79 | t, _ = tt.(*string)
80 | }
81 | return
82 | }
83 |
--------------------------------------------------------------------------------
/pkg/splicer/magic/magic_test.go:
--------------------------------------------------------------------------------
1 | package magic
2 |
--------------------------------------------------------------------------------
/pkg/splicer/splicer_test.go:
--------------------------------------------------------------------------------
1 | package splicer
2 |
3 | // todo: a test is a good idea
4 |
--------------------------------------------------------------------------------
/pkg/splicer/t64/time_test.go:
--------------------------------------------------------------------------------
1 | package t64
2 |
3 | import (
4 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
5 | "git.indra-labs.org/dev/ind/pkg/util/ci"
6 | "testing"
7 | "time"
8 | )
9 |
10 | var (
11 | log = log2.GetLogger()
12 | fails = log.E.Chk
13 | )
14 |
15 | func TestNew(t *testing.T) {
16 | ci.TraceIfNot()
17 |
18 | t1, t2 := New(), New()
19 | nao := time.Now()
20 |
21 | // Encode in the time value.
22 | t1.Put(&nao)
23 |
24 | // Copy to other Time.
25 | t2.Write(t1.Read())
26 |
27 | // Verify accessors work.
28 | var ta1, ta2 *time.Time
29 | if ta1 = Assert(t1); ta1 == nil {
30 | log.E.Ln("did not get expected time value")
31 | t.FailNow()
32 | }
33 | if ta2 = Assert(t2); ta2 == nil {
34 | log.E.Ln("did not get expected time value")
35 | t.FailNow()
36 | }
37 |
38 | // Verify the value survived the encode/decode.
39 | if !(*ta1).Equal(*ta2) {
40 | t.FailNow()
41 | }
42 |
43 | // Test NewFrom correctly decodes and returns the trimmings.
44 | b1 := t1.Read()
45 | nb1, rem := NewFrom(append(b1, make([]byte, 5)...))
46 | if rem == nil || len(rem) != 5 {
47 | t.FailNow()
48 | }
49 | val := Assert(nb1)
50 | if !(*val).Equal(*ta1) {
51 | t.FailNow()
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/pkg/storage/doc.go:
--------------------------------------------------------------------------------
1 | // Package storage provides an encrypted key value store and an RPC service for remote unlocking to prevent secrets being stored on remote nonvolatile storage.
2 | package storage
3 |
--------------------------------------------------------------------------------
/pkg/storage/flags.go:
--------------------------------------------------------------------------------
1 | package storage
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/util/appdata"
5 | "github.com/spf13/cobra"
6 | "github.com/spf13/viper"
7 | "path/filepath"
8 | )
9 |
10 | var (
11 | storeKeyFlag = "store-key"
12 | storeKeyFileFlag = "store-keyfile"
13 | //storeKeyRPCFlag = "store-key-rpc"
14 | storeFilePathFlag = "store-path"
15 | //storeAskPassFlag = "store-ask-pass"
16 | )
17 |
18 | var (
19 | storeEncryptionKey string
20 | storeEncryptionKeyFile string
21 | //storeEncryptionKeyRPC bool
22 | storeFilePath string
23 | //storeAskPass bool
24 | )
25 |
26 | func InitFlags(cmd *cobra.Command) {
27 |
28 | cmd.Flags().StringVarP(&storeEncryptionKey, storeKeyFlag, "",
29 | "",
30 | "the key required to unlock storage (NOT recommended)",
31 | )
32 |
33 | viper.BindPFlag(storeKeyFlag, cmd.Flags().Lookup(storeKeyFlag))
34 |
35 | cmd.PersistentFlags().StringVarP(&storeEncryptionKeyFile, storeKeyFileFlag, "",
36 | "",
37 | "the path of the keyfile required to unlock storage",
38 | )
39 |
40 | viper.BindPFlag(storeKeyFileFlag, cmd.PersistentFlags().Lookup(storeKeyFileFlag))
41 |
42 | cmd.PersistentFlags().StringVarP(&storeFilePath, storeFilePathFlag, "",
43 | filepath.Join(appdata.Dir("indra", false), "indra.db"),
44 | "the path of the database (default is /indra.db)",
45 | )
46 |
47 | viper.BindPFlag(storeFilePathFlag, cmd.PersistentFlags().Lookup(storeFilePathFlag))
48 |
49 | //cmd.PersistentFlags().BoolVarP(&storeEncryptionKeyRPC, storeKeyRPCFlag, "",
50 | // false,
51 | // "looks for the encryption key via RPC",
52 | //)
53 | //
54 | //viper.BindPFlag(storeKeyRPCFlag, cmd.PersistentFlags().Lookup(storeKeyRPCFlag))
55 |
56 | //cmd.PersistentFlags().BoolVarP(&storeAskPass, storeAskPassFlag, "",
57 | // false,
58 | // "prompts the user for a password to unlock storage",
59 | //)
60 | //
61 | //viper.BindPFlag(storeAskPassFlag, cmd.PersistentFlags().Lookup(storeAskPassFlag))
62 | }
63 |
--------------------------------------------------------------------------------
/pkg/storage/key.go:
--------------------------------------------------------------------------------
1 | package storage
2 |
3 | import (
4 | "crypto/rand"
5 | "github.com/btcsuite/btcd/btcutil/base58"
6 | "strings"
7 | )
8 |
9 | type Key [32]byte
10 |
11 | func (k Key) Bytes() []byte {
12 | return k[:]
13 | }
14 |
15 | func (k Key) Encode() string {
16 | return base58.Encode(k[:])
17 | }
18 |
19 | func (k *Key) Decode(key string) {
20 |
21 | key = strings.TrimSpace(key)
22 |
23 | copy(k[:], base58.Decode(key))
24 | }
25 |
26 | func KeyGen() (Key, error) {
27 |
28 | var err error
29 | var sk [32]byte
30 | var key Key
31 |
32 | _, err = rand.Read(sk[:])
33 |
34 | sk[0] &= 248
35 | sk[31] = (sk[31] & 127) | 64
36 |
37 | key = sk
38 |
39 | return key, err
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/storage/log.go:
--------------------------------------------------------------------------------
1 | package storage
2 |
3 | import (
4 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
5 | )
6 |
7 | var (
8 | log = log2.GetLogger()
9 | check = log.E.Chk
10 | )
11 |
--------------------------------------------------------------------------------
/pkg/storage/service_unlock.go:
--------------------------------------------------------------------------------
1 | package storage
2 |
3 | import (
4 | "context"
5 | )
6 |
7 | type Service struct{}
8 |
9 | func (s *Service) Unlock(ctx context.Context, req *UnlockRequest) (res *UnlockResponse, err error) {
10 |
11 | log.I.Ln("attempting to unlock database")
12 |
13 | key.Decode(req.Key)
14 |
15 | isUnlocked, err := attempt_unlock()
16 |
17 | if !isUnlocked {
18 |
19 | log.I.Ln("unlock attempt failed:", err)
20 |
21 | return &UnlockResponse{Success: false}, err
22 | }
23 |
24 | log.I.Ln("successfully unlocked database")
25 | isUnlockedChan <- true
26 |
27 | return &UnlockResponse{Success: true}, nil
28 | }
29 |
30 | func (s *Service) mustEmbedUnimplementedUnlockServiceServer() {}
31 |
32 | func NewUnlockService() *Service { return &Service{} }
33 |
--------------------------------------------------------------------------------
/pkg/storage/signals.go:
--------------------------------------------------------------------------------
1 | package storage
2 |
3 | var (
4 | startupErrors = make(chan error, 128)
5 | isLockedChan = make(chan bool, 1)
6 | isUnlockedChan = make(chan bool, 1)
7 | isReadyChan = make(chan bool, 1)
8 | )
9 |
10 | var (
11 | isReady bool
12 | )
13 |
14 | func WhenStartFailed() chan error {
15 | return startupErrors
16 | }
17 |
18 | func WhenIsLocked() chan bool {
19 | return isLockedChan
20 | }
21 |
22 | func WhenIsUnlocked() chan bool {
23 | return isUnlockedChan
24 | }
25 |
26 | func WhenReady() chan bool {
27 | return isReadyChan
28 | }
29 |
--------------------------------------------------------------------------------
/pkg/storage/unlock.go:
--------------------------------------------------------------------------------
1 | package storage
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/util/options"
5 | "github.com/dgraph-io/badger/v3"
6 | "github.com/spf13/viper"
7 | )
8 |
9 | func attempt_unlock() (isUnlocked bool, err error) {
10 |
11 | opts = options.Default(viper.GetString(storeFilePathFlag), key[:])
12 |
13 | if db, err = badger.Open(*opts); err != nil {
14 |
15 | db = nil
16 |
17 | return false, err
18 | }
19 |
20 | return true, nil
21 | }
22 |
--------------------------------------------------------------------------------
/pkg/storage/unlock.proto:
--------------------------------------------------------------------------------
1 |
2 | syntax = "proto3";
3 |
4 | option go_package = ".";
5 |
6 | package rpc;
7 |
8 | message UnlockRequest {
9 | string key = 1;
10 | }
11 |
12 | message UnlockResponse {
13 | bool success = 1;
14 | optional string message = 2;
15 | }
16 |
17 | service UnlockService {
18 | rpc Unlock(UnlockRequest) returns (UnlockResponse) {}
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/util/b32/constant.go:
--------------------------------------------------------------------------------
1 | // Package b32 is an isolated package for storing the based32 cipher set.
2 | package b32
3 |
4 | // Based32Ciphers is the list of symbols forming the digits for Indra's
5 | // distinctive Based32 encoding. It is base 32, but has all lower case letters
6 | // so that it is readily sensible for use in "vanity" mining for public keys and
7 | // other types of very large numbers.
8 | const Based32Ciphers = "abcdefghijklmnopqrstuvwxyz234679"
9 |
--------------------------------------------------------------------------------
/pkg/util/ci/trace.go:
--------------------------------------------------------------------------------
1 | package ci
2 |
3 | import (
4 | indra "git.indra-labs.org/dev/ind"
5 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
6 | )
7 |
8 | func TraceIfNot() {
9 | if indra.CI == "false" {
10 | log2.SetLogLevel(log2.Trace)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/pkg/util/cryptorand/cryptorand.go:
--------------------------------------------------------------------------------
1 | // Package cryptorand augments the standard math/rand library with cryptographic entropy seeding.
2 | package cryptorand
3 |
4 | import (
5 | rand2 "crypto/rand"
6 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
7 | "git.indra-labs.org/dev/ind/pkg/util/slice"
8 | "math/rand"
9 | )
10 |
11 | var (
12 | log = log2.GetLogger()
13 | check = log.E.Chk
14 | )
15 |
16 | func GetSeed() int64 {
17 | rBytes := make([]byte, 8)
18 | if n, e := rand2.Read(rBytes); n != 8 && check(e) {
19 | return 0
20 | }
21 | return int64(slice.DecodeUint64(rBytes))
22 | }
23 |
24 | func IntN(n int) int {
25 | rand.Seed(GetSeed())
26 | return rand.Intn(n)
27 | }
28 |
29 | func Shuffle(l int, fn func(i, j int)) {
30 | rand.Seed(GetSeed())
31 | rand.Shuffle(l, fn)
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/util/file/file.go:
--------------------------------------------------------------------------------
1 | // Package file provides some helpers for working with files and folders, specifically making possibly multi-level deep new directories based on a pathspec and testing whether a file exists.
2 | package file
3 |
4 | import (
5 | "os"
6 | "path/filepath"
7 | )
8 |
9 | // EnsureDir checks a file could be written to a path, creates the directories as needed
10 | func EnsureDir(fileName string) {
11 | dirName := filepath.Dir(fileName)
12 | if _, serr := os.Stat(dirName); serr != nil {
13 | merr := os.MkdirAll(dirName, os.ModePerm)
14 | if merr != nil {
15 | panic(merr)
16 | }
17 | }
18 | }
19 |
20 | // FileExists reports whether the named file or directory exists.
21 | func FileExists(filePath string) bool {
22 | _, e := os.Stat(filePath)
23 | return e == nil
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/util/math/math.go:
--------------------------------------------------------------------------------
1 | // Package math provides a simple 32 bit unsigned integer minimum function.
2 | package math
3 |
4 | // MinUint32 is a helper function to return the minimum of two uint32s. This avoids a math import and the need to cast
5 | // to floats.
6 | func MinUint32(a, b uint32) uint32 {
7 | if a < b {
8 | return a
9 | }
10 | return b
11 | }
12 |
--------------------------------------------------------------------------------
/pkg/util/multikey/multikey.go:
--------------------------------------------------------------------------------
1 | package multikey
2 |
3 | import (
4 | "git.indra-labs.org/dev/ind/pkg/crypto"
5 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
6 | "github.com/libp2p/go-libp2p/core/peer"
7 | "github.com/multiformats/go-multiaddr"
8 | )
9 |
10 | var (
11 | log = log2.GetLogger()
12 | fails = log.E.Chk
13 | )
14 |
15 | func AddKeyToMultiaddr(in multiaddr.Multiaddr, pub *crypto.Pub) (ma multiaddr.Multiaddr) {
16 | var pid peer.ID
17 | var e error
18 | if pid, e = peer.IDFromPublicKey(pub); fails(e) {
19 | return
20 | }
21 | var k multiaddr.Multiaddr
22 | if k, e = multiaddr.NewMultiaddr("/p2p/" + pid.String()); fails(e) {
23 | return
24 | }
25 | ma = in.Encapsulate(k)
26 | return
27 | }
28 |
--------------------------------------------------------------------------------
/pkg/util/norm/norm.go:
--------------------------------------------------------------------------------
1 | // Package norm is a string comparison library that makes everything lowercase before comparison for case insensitive equality testing.
2 | package norm
3 |
4 | import (
5 | "strings"
6 | )
7 |
8 | func Eq(a, b string) bool {
9 | an, bn := Norm(a), Norm(b)
10 | return an == bn
11 | }
12 |
13 | func Norm(s string) string { return strings.ToLower(s) }
14 |
--------------------------------------------------------------------------------
/pkg/util/options/default.go:
--------------------------------------------------------------------------------
1 | package options
2 |
3 | import "github.com/dgraph-io/badger/v3"
4 |
5 | // Default returns a pointer to badger.Options to be used to open
6 | // Indra's main data store.
7 | //
8 | // This is separated from the seed's usage of it in order to make test data
9 | // stores without duplicating this common configuration setting.
10 | func Default(filePath string, key []byte) *badger.Options {
11 |
12 | o := badger.DefaultOptions(filePath)
13 |
14 | // If log level is above info maybe we do want this enabled?
15 | o.Logger = nil
16 |
17 | // This works out as 1 << 27, ie 256kb. Should it be 1<<30 1Mb?
18 | o.IndexCacheSize = 128 << 20
19 |
20 | o.EncryptionKey = key[:]
21 |
22 | return &o
23 | }
24 |
--------------------------------------------------------------------------------
/pkg/util/path/path.go:
--------------------------------------------------------------------------------
1 | // Package path provides a simple string slice representation for paths, equally usable for filesystems or HD keychain schemes.
2 | package path
3 |
4 | import (
5 | "strings"
6 |
7 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
8 | "git.indra-labs.org/dev/ind/pkg/util/norm"
9 | )
10 |
11 | type (
12 | Path []string
13 | )
14 |
15 | var (
16 | log = log2.GetLogger()
17 | check = log.E.Chk
18 | )
19 |
20 | func (p Path) Child(child string) (p1 Path) { return append(p, child) }
21 |
22 | func (p Path) Common(p2 Path) (o Path) {
23 | for i := range p {
24 | if len(p2) < i {
25 | if p[i] == p2[i] {
26 | o = append(o, p[i])
27 | }
28 | }
29 | }
30 | return
31 | }
32 |
33 | func (p Path) Equal(p2 Path) bool {
34 | if len(p) == len(p2) {
35 | for i := range p {
36 | if norm.Norm(p[i]) !=
37 | norm.Norm(p2[i]) {
38 | return false
39 | }
40 | }
41 | return true
42 | }
43 | return false
44 | }
45 |
46 | func From(s string) (p Path) { return strings.Split(s, " ") }
47 |
48 | func GetIndent(d int) string { return strings.Repeat("\t", d) }
49 |
50 | func (p Path) Parent() (p1 Path) {
51 | if len(p) > 0 {
52 | p1 = p[:len(p)-1]
53 | }
54 | return
55 | }
56 |
57 | func (p Path) String() string { return strings.Join(p, " ") }
58 |
59 | func (p Path) TrimPrefix() Path {
60 | if len(p) > 1 {
61 | return p[1:]
62 | }
63 | return p[:0]
64 | }
65 |
--------------------------------------------------------------------------------
/pkg/util/slice/interfaces_test.go:
--------------------------------------------------------------------------------
1 | package slice
2 |
3 | import (
4 | "bytes"
5 | "git.indra-labs.org/dev/ind/pkg/crypto/sha256"
6 | "testing"
7 | )
8 |
9 | func TestMessage_ToU64Slice(t *testing.T) {
10 | var e error
11 | var msg1 Bytes
12 | if msg1, _, e = GenMessage(33, ""); check(e) {
13 | t.Error(e)
14 | t.FailNow()
15 | }
16 | uMsg1 := msg1.ToU64Slice()
17 | umsg1 := uMsg1.ToMessage()
18 | if bytes.Compare(msg1, umsg1) != 0 {
19 | t.Error("conversion to U64Slice and back to []byte failed")
20 | t.FailNow()
21 | }
22 | }
23 |
24 | func TestU64Slice_XOR(t *testing.T) {
25 | const ml = 1024
26 | var e error
27 | var msg1 Bytes
28 | if msg1, _, e = GenMessage(ml, ""); check(e) {
29 | t.Error(e)
30 | t.FailNow()
31 | }
32 | hash1 := sha256.Single(msg1)
33 | uMsg1 := msg1.ToU64Slice()
34 | var msg2 Bytes
35 | if msg2, _, e = GenMessage(ml, ""); check(e) {
36 | t.Error(e)
37 | t.FailNow()
38 | }
39 | // log.I.S(msg2)
40 | uMsg2 := msg2.ToU64Slice()
41 | var msg3 Bytes
42 | if msg3, _, e = GenMessage(ml, ""); check(e) {
43 | t.Error(e)
44 | t.FailNow()
45 | }
46 | // log.I.S(msg3)
47 | uMsg3 := msg3.ToU64Slice()
48 | uMsg1.XOR(uMsg2)
49 | uMsg1.XOR(uMsg3)
50 | uMsg1.XOR(uMsg2)
51 | uMsg1.XOR(uMsg3)
52 | hash2 := sha256.Single(uMsg1.ToMessage())
53 | if hash1 != hash2 {
54 | t.Error("XOR failed")
55 | t.FailNow()
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/pkg/util/slice/slice_test.go:
--------------------------------------------------------------------------------
1 | package slice
2 |
3 | import (
4 | "crypto/rand"
5 | "errors"
6 | "git.indra-labs.org/dev/ind/pkg/crypto/sha256"
7 | "testing"
8 | )
9 |
10 | func GenMessage(msgSize int, hrp string) (msg []byte, hash sha256.Hash, e error) {
11 | msg = make([]byte, msgSize)
12 | var n int
13 | if n, e = rand.Read(msg); check(e) && n != msgSize {
14 | return
15 | }
16 | if hrp == "" {
17 | hrp = "payload"
18 | }
19 | copy(msg, hrp)
20 | hash = sha256.Single(msg)
21 | return
22 | }
23 |
24 | func TestSegment(t *testing.T) {
25 | msgSize := 2 << 17
26 | segSize := 1382
27 | var msg []byte
28 | var hash sha256.Hash
29 | var e error
30 | if msg, hash, e = GenMessage(msgSize, ""); check(e) {
31 | t.Error(e)
32 | }
33 | segs := Segment(msg, segSize)
34 | pkt := Cat(segs...)[:len(msg)]
35 | hash2 := sha256.Single(pkt)
36 | if hash != hash2 {
37 | t.Error(errors.New("message did not decode" +
38 | " correctly"))
39 | }
40 | }
41 |
42 | func TestSize24(t *testing.T) {
43 | n := 1<<24 - 1
44 | u := NewUint24()
45 | EncodeUint24(u, n)
46 | u2 := DecodeUint24(u)
47 | if n != u2 {
48 | t.Error("failed to encode/decode")
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/util/tests/testutils.go:
--------------------------------------------------------------------------------
1 | // Package tests provides some helpers for tests.
2 | package tests
3 |
4 | import (
5 | "crypto/rand"
6 |
7 | "git.indra-labs.org/dev/ind/pkg/crypto/sha256"
8 | log2 "git.indra-labs.org/dev/ind/pkg/proc/log"
9 | )
10 |
11 | var (
12 | log = log2.GetLogger()
13 | fails = log.E.Chk
14 | )
15 |
16 | func GenMessage(msgSize int, hrp string) (msg []byte, hash sha256.Hash, e error) {
17 | msg = make([]byte, msgSize)
18 | var n int
19 | if n, e = rand.Read(msg); fails(e) && n != msgSize {
20 | return
21 | }
22 | if hrp == "" {
23 | hrp = "payload"
24 | }
25 | copy(msg, hrp)
26 | hash = sha256.Single(msg)
27 | return
28 | }
29 |
--------------------------------------------------------------------------------
/pkg/util/windows/windows.go:
--------------------------------------------------------------------------------
1 | // Package windows provides some tools for handling launching subprocesses on windows using cmd.exe.
2 | package windows
3 |
4 | import (
5 | "runtime"
6 | )
7 |
8 | // PrependForWindows runs a command with a terminal
9 | func PrependForWindows(args []string) []string {
10 | if runtime.GOOS == "windows" {
11 | args = append(
12 | []string{
13 | "cmd.exe",
14 | "/C",
15 | },
16 | args...,
17 | )
18 | }
19 | return args
20 | }
21 |
22 | // PrependForWindowsWithStart runs a process independently
23 | func PrependForWindowsWithStart(args []string) []string {
24 | if runtime.GOOS == "windows" {
25 | args = append(
26 | []string{
27 | "cmd.exe",
28 | "/C",
29 | "start",
30 | },
31 | args...,
32 | )
33 | }
34 | return args
35 | }
36 |
--------------------------------------------------------------------------------
/release/.gitignore:
--------------------------------------------------------------------------------
1 | scratch-*
2 | btcd-*
3 | lnd-*
4 | indra-*
5 | btcwallet-*
6 |
--------------------------------------------------------------------------------
/scripts/cdwork.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash
2 | # populate ~/.workpath thus: `cd path/to/repo/root; pwd>~/.workpath
3 | export INDRAROOT=$(cat ~/.workpath)
4 | export PATH=$INDRAROOT/scripts:$PATH
5 | # put the path of the root of the repository in ./scripts/path
6 | cd $INDRAROOT
7 |
--------------------------------------------------------------------------------
/scripts/readme.md:
--------------------------------------------------------------------------------
1 | # scripts
2 |
3 | populate ~/.workpath thus: `cd path/to/repo/root; pwd>~/.workpath`
4 |
5 | add this to your `~/.bashrc` or `~/.zshrc`:
6 |
7 | export PATH=$(cat ~/.workpath)/scripts:$HOME/sdk/go1.19.10/bin:$PATH
8 | export GOBIN=$HOME/.local/bin
9 |
10 | `source` the `rc` file or open a new terminal session and type `cdwork.sh` and you will have a number of useful commands
11 | that handle paths and special build parameters to make the code locations work without hard coding them anywhere.
--------------------------------------------------------------------------------
/scripts/run.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | reset
3 | go run -tags local -gcflags "all=-trimpath=$INDRAROOT" $1 $2 $3 $4 $5
--------------------------------------------------------------------------------
/scripts/runci.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | reset
3 | go run -gcflags "all=-trimpath=$INDRAROOT" $1 $2 $3 $4 $5
--------------------------------------------------------------------------------
/scripts/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | reset
3 | go test -v -tags local -gcflags "all=-trimpath=$INDRAROOT" $1 $2 $3 $4 $5
--------------------------------------------------------------------------------
/scripts/testci.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | reset
3 | go test -v -gcflags "all=-trimpath=$INDRAROOT" $1 $2 $3 $4 $5
--------------------------------------------------------------------------------
/scripts/testpkg.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | cd pkg
3 | go test -v -tags local -gcflags "all=-trimpath=$INDRAROOT" ./...
--------------------------------------------------------------------------------
/scripts/trace.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | reset
3 | go run -tags local -gcflags "all=-trimpath=$INDRAROOT" $1 --logs-level=trace $2 $3 $4 $5
--------------------------------------------------------------------------------
/version.go:
--------------------------------------------------------------------------------
1 | //go:build !local
2 |
3 | // Package indra is the root of the repository for the Indra distributed VPN, containing mainly the version information for included executables to use for information and identification on the network.
4 | //
5 | // See [pkg/git.indra-labs.org/dev/ind/cmd/indra] for the main server executable.
6 | //
7 | // Put invocations to run all the generators in here check [cmd/bumper] to add them, and they will automatically run with:
8 | //
9 | // $ go generate .
10 | //
11 | // which will run all these generators below and finish with a go install.
12 | //
13 | //go:generate go install ./...
14 | package indra
15 |
16 | import "fmt"
17 |
18 | const (
19 | // URL is the git URL for the repository.
20 | URL = "git.indra-labs.org/dev/ind"
21 | // GitRef is the gitref, as in refs/heads/branchname.
22 | GitRef = "refs/heads/15"
23 | // ParentGitCommit is the commit hash of the parent HEAD.
24 | ParentGitCommit = "742a44445cc6862042a76fdb02e64236fd4340bb"
25 | // BuildTime stores the time when the current binary was built.
26 | BuildTime = "2023-08-09T21:04:58+01:00"
27 | // SemVer lists the (latest) git tag on the release.
28 | SemVer = "v0.1.20"
29 | // Major is the major number from the tag.
30 | Major = 0
31 | // Minor is the minor number from the tag.
32 | Minor = 1
33 | // Patch is the patch version number from the tag.
34 | Patch = 20
35 | )
36 |
37 | var CI = "false"
38 |
39 | // Version returns a pretty printed version information string.
40 | func Version() string {
41 | return fmt.Sprint(
42 | "\nRepository Information\n",
43 | "\tGit repository: "+URL+"\n",
44 | "\tBranch: "+GitRef+"\n",
45 | "\tParentGitCommit: "+ParentGitCommit+"\n",
46 | "\tBuilt: "+BuildTime+"\n",
47 | "\tSemVer: "+SemVer+"\n",
48 | )
49 | }
50 |
--------------------------------------------------------------------------------