Compare commits
30 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
edace64685 | ||
![]() |
1712957252 | ||
![]() |
eb51810ddd | ||
![]() |
c4cbd6e041 | ||
![]() |
84d1ec1a12 | ||
![]() |
43fb66564b | ||
![]() |
2e82fab112 | ||
![]() |
daa08faa71 | ||
![]() |
a05ca99118 | ||
![]() |
b99e77153e | ||
![]() |
b56afeb346 | ||
![]() |
890d71f974 | ||
![]() |
bfcde005b3 | ||
![]() |
a9a4310a04 | ||
![]() |
4cba6e2edd | ||
![]() |
25eedfeed8 | ||
![]() |
8632c8275d | ||
![]() |
9e61a8e00f | ||
![]() |
fb2ca1a92c | ||
![]() |
1bf0437e54 | ||
![]() |
0af72cba75 | ||
![]() |
a4a38460e3 | ||
![]() |
75a7b2aec9 | ||
![]() |
43a6a0e07f | ||
![]() |
936c39746c | ||
![]() |
8df0f31a4d | ||
![]() |
c1b05d6ede | ||
![]() |
0ef26b9207 | ||
![]() |
8eee571a7b | ||
![]() |
95744f9498 |
105
I2PAddr.go
105
I2PAddr.go
@@ -10,6 +10,7 @@ import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/sirupsen/logrus"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
@@ -37,6 +38,7 @@ type I2PKeys struct {
|
||||
// Creates I2PKeys from an I2PAddr and a public/private keypair string (as
|
||||
// generated by String().)
|
||||
func NewKeys(addr I2PAddr, both string) I2PKeys {
|
||||
log.WithField("addr", addr).Debug("Creating new I2PKeys")
|
||||
return I2PKeys{addr, both}
|
||||
}
|
||||
|
||||
@@ -45,56 +47,98 @@ func NewKeys(addr I2PAddr, both string) I2PKeys {
|
||||
func fileExists(filename string) (bool, error) {
|
||||
info, err := os.Stat(filename)
|
||||
if os.IsNotExist(err) {
|
||||
log.WithField("filename", filename).Debug("File does not exist")
|
||||
return false, nil
|
||||
} else if err != nil {
|
||||
log.WithError(err).WithField("filename", filename).Error("Error checking file existence")
|
||||
return false, fmt.Errorf("error checking file existence: %w", err)
|
||||
}
|
||||
exists := !info.IsDir()
|
||||
if exists {
|
||||
log.WithField("filename", filename).Debug("File exists")
|
||||
} else {
|
||||
log.WithField("filename", filename).Debug("File is a directory")
|
||||
}
|
||||
return !info.IsDir(), nil
|
||||
}
|
||||
|
||||
// load keys from non standard format
|
||||
func LoadKeysIncompat(r io.Reader) (k I2PKeys, err error) {
|
||||
// LoadKeysIncompat loads keys from a non-standard format
|
||||
func LoadKeysIncompat(r io.Reader) (I2PKeys, error) {
|
||||
log.Debug("Loading keys from reader")
|
||||
var buff bytes.Buffer
|
||||
_, err = io.Copy(&buff, r)
|
||||
if err == nil {
|
||||
parts := strings.Split(buff.String(), "\n")
|
||||
k = I2PKeys{I2PAddr(parts[0]), parts[1]}
|
||||
_, err := io.Copy(&buff, r)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error copying from reader, did not load keys")
|
||||
return I2PKeys{}, fmt.Errorf("error copying from reader: %w", err)
|
||||
}
|
||||
return
|
||||
|
||||
parts := strings.Split(buff.String(), "\n")
|
||||
if len(parts) < 2 {
|
||||
err := errors.New("invalid key format: not enough data")
|
||||
log.WithError(err).Error("Error parsing keys")
|
||||
return I2PKeys{}, err
|
||||
}
|
||||
|
||||
k := I2PKeys{I2PAddr(parts[0]), parts[1]}
|
||||
log.WithField("keys", k).Debug("Loaded keys")
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// load keys from non-standard format by specifying a text file.
|
||||
// If the file does not exist, generate keys, otherwise, fail
|
||||
// closed.
|
||||
func LoadKeys(r string) (I2PKeys, error) {
|
||||
log.WithField("filename", r).Debug("Loading keys from file")
|
||||
exists, err := fileExists(r)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error checking if file exists")
|
||||
return I2PKeys{}, err
|
||||
}
|
||||
if !exists {
|
||||
return I2PKeys{}, fmt.Errorf("file does not exist: %s", r)
|
||||
// File doesn't exist so we'll generate new keys
|
||||
log.WithError(err).Debug("File does not exist, attempting to generate new keys")
|
||||
k, err := NewDestination()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error generating new keys")
|
||||
return I2PKeys{}, err
|
||||
}
|
||||
// Save the new keys to the file
|
||||
err = StoreKeys(*k, r)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error saving new keys to file")
|
||||
return I2PKeys{}, err
|
||||
}
|
||||
return *k, nil
|
||||
}
|
||||
fi, err := os.Open(r)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("filename", r).Error("Error opening file")
|
||||
return I2PKeys{}, fmt.Errorf("error opening file: %w", err)
|
||||
}
|
||||
defer fi.Close()
|
||||
log.WithField("filename", r).Debug("File opened successfully")
|
||||
return LoadKeysIncompat(fi)
|
||||
}
|
||||
|
||||
// store keys in non standard format
|
||||
func StoreKeysIncompat(k I2PKeys, w io.Writer) error {
|
||||
log.Debug("Storing keys")
|
||||
_, err := io.WriteString(w, k.Address.Base64()+"\n"+k.Both)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error writing keys")
|
||||
return fmt.Errorf("error writing keys: %w", err)
|
||||
}
|
||||
log.WithField("keys", k).Debug("Keys stored successfully")
|
||||
return nil
|
||||
}
|
||||
func StoreKeys(k I2PKeys, r string) error {
|
||||
log.WithField("filename", r).Debug("Storing keys to file")
|
||||
if _, err := os.Stat(r); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
log.WithField("filename", r).Debug("File does not exist, creating new file")
|
||||
fi, err := os.Create(r)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error creating file")
|
||||
return err
|
||||
}
|
||||
defer fi.Close()
|
||||
@@ -103,6 +147,7 @@ func StoreKeys(k I2PKeys, r string) error {
|
||||
}
|
||||
fi, err := os.Open(r)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error opening file")
|
||||
return err
|
||||
}
|
||||
defer fi.Close()
|
||||
@@ -123,10 +168,12 @@ func (k I2PKeys) Public() crypto.PublicKey {
|
||||
}
|
||||
|
||||
func (k I2PKeys) Private() []byte {
|
||||
log.Debug("Extracting private key")
|
||||
src := strings.Split(k.String(), k.Addr().String())[0]
|
||||
var dest []byte
|
||||
_, err := i2pB64enc.Decode(dest, []byte(src))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error decoding private key")
|
||||
panic(err)
|
||||
}
|
||||
return dest
|
||||
@@ -145,6 +192,7 @@ func (k I2PKeys) PrivateKey() crypto.PrivateKey {
|
||||
var pk ed25519.PrivateKey = k.Private()
|
||||
_, err := pk.Sign(rand.Reader, []byte("nonsense"), crypto.Hash(0))
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("Error in private key signature")
|
||||
//TODO: Elgamal, P256, P384, P512, GOST? keys?
|
||||
}
|
||||
return pk
|
||||
@@ -175,6 +223,7 @@ func (k I2PKeys) String() string {
|
||||
func (k I2PKeys) HostnameEntry(hostname string, opts crypto.SignerOpts) (string, error) {
|
||||
sig, err := k.Sign(rand.Reader, []byte(hostname), opts)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error signing hostname")
|
||||
return "", fmt.Errorf("error signing hostname: %w", err)
|
||||
}
|
||||
return string(sig), nil
|
||||
@@ -191,25 +240,33 @@ type I2PDestHash [32]byte
|
||||
|
||||
// create a desthash from a string b32.i2p address
|
||||
func DestHashFromString(str string) (dhash I2PDestHash, err error) {
|
||||
log.WithField("address", str).Debug("Creating desthash from string")
|
||||
if strings.HasSuffix(str, ".b32.i2p") && len(str) == 60 {
|
||||
// valid
|
||||
_, err = i2pB32enc.Decode(dhash[:], []byte(str[:52]+"===="))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error decoding base32 address")
|
||||
}
|
||||
} else {
|
||||
// invalid
|
||||
err = errors.New("invalid desthash format")
|
||||
log.WithError(err).Error("Invalid desthash format")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// create a desthash from a []byte array
|
||||
func DestHashFromBytes(str []byte) (dhash I2PDestHash, err error) {
|
||||
log.Debug("Creating DestHash from bytes")
|
||||
if len(str) == 32 {
|
||||
// valid
|
||||
//_, err = i2pB32enc.Decode(dhash[:], []byte(str[:52]+"===="))
|
||||
log.WithField("str", str).Debug("Copying str to desthash")
|
||||
copy(dhash[:], str)
|
||||
} else {
|
||||
// invalid
|
||||
err = errors.New("invalid desthash format")
|
||||
log.WithField("str", str).Error("Invalid desthash format")
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -257,10 +314,11 @@ func (a I2PAddr) Network() string {
|
||||
// Creates a new I2P address from a base64-encoded string. Checks if the address
|
||||
// addr is in correct format. (If you know for sure it is, use I2PAddr(addr).)
|
||||
func NewI2PAddrFromString(addr string) (I2PAddr, error) {
|
||||
log.WithField("addr", addr).Debug("Creating new I2PAddr from string")
|
||||
if strings.HasSuffix(addr, ".i2p") {
|
||||
if strings.HasSuffix(addr, ".b32.i2p") {
|
||||
// do a lookup of the b32
|
||||
|
||||
log.Warn("Cannot convert .b32.i2p to full destination")
|
||||
return I2PAddr(""), errors.New("cannot convert .b32.i2p to full destination")
|
||||
}
|
||||
// strip off .i2p if it's there
|
||||
@@ -269,16 +327,20 @@ func NewI2PAddrFromString(addr string) (I2PAddr, error) {
|
||||
addr = strings.Trim(addr, "\t\n\r\f ")
|
||||
// very basic check
|
||||
if len(addr) > 4096 || len(addr) < 516 {
|
||||
log.Error("Invalid I2P address length")
|
||||
return I2PAddr(""), errors.New(addr + " is not an I2P address")
|
||||
}
|
||||
buf := make([]byte, i2pB64enc.DecodedLen(len(addr)))
|
||||
if _, err := i2pB64enc.Decode(buf, []byte(addr)); err != nil {
|
||||
log.Error("Address is not base64-encoded")
|
||||
return I2PAddr(""), errors.New("Address is not base64-encoded")
|
||||
}
|
||||
log.Debug("Successfully created I2PAddr from string")
|
||||
return I2PAddr(addr), nil
|
||||
}
|
||||
|
||||
func FiveHundredAs() I2PAddr {
|
||||
log.Debug("Generating I2PAddr with 500 'A's")
|
||||
s := ""
|
||||
for x := 0; x < 517; x++ {
|
||||
s += "A"
|
||||
@@ -289,7 +351,9 @@ func FiveHundredAs() I2PAddr {
|
||||
|
||||
// Creates a new I2P address from a byte array. The inverse of ToBytes().
|
||||
func NewI2PAddrFromBytes(addr []byte) (I2PAddr, error) {
|
||||
log.Debug("Creating I2PAddr from bytes")
|
||||
if len(addr) > 4096 || len(addr) < 384 {
|
||||
log.Error("Invalid I2P address length")
|
||||
return I2PAddr(""), errors.New("Not an I2P address")
|
||||
}
|
||||
buf := make([]byte, i2pB64enc.EncodedLen(len(addr)))
|
||||
@@ -341,6 +405,7 @@ func NewDestination() (*I2PKeys, error) {
|
||||
return strings.ReplaceAll(strings.ReplaceAll(s, "\r\n", ""), "\n", "")
|
||||
}
|
||||
//
|
||||
log.Debug("Creating new destination via SAM")
|
||||
conn, err := net.Dial("tcp", "127.0.0.1:7656")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -348,32 +413,49 @@ func NewDestination() (*I2PKeys, error) {
|
||||
defer conn.Close()
|
||||
_, err = conn.Write([]byte("HELLO VERSION MIN=3.1 MAX=3.1\n"))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error writing to SAM bridge")
|
||||
return nil, err
|
||||
}
|
||||
buf := make([]byte, 4096)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error reading from SAM bridge")
|
||||
return nil, err
|
||||
}
|
||||
if n < 1 {
|
||||
log.Error("No data received from SAM bridge")
|
||||
return nil, fmt.Errorf("no data received")
|
||||
}
|
||||
|
||||
response := string(buf[:n])
|
||||
log.WithField("response", response).Debug("Received response from SAM bridge")
|
||||
|
||||
if strings.Contains(string(buf[:n]), "RESULT=OK") {
|
||||
_, err = conn.Write([]byte("DEST GENERATE SIGNATURE_TYPE=7\n"))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error writing DEST GENERATE to SAM bridge")
|
||||
return nil, err
|
||||
}
|
||||
n, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error reading destination from SAM bridge")
|
||||
return nil, err
|
||||
}
|
||||
if n < 1 {
|
||||
log.Error("No destination data received from SAM bridge")
|
||||
return nil, fmt.Errorf("no destination data received")
|
||||
}
|
||||
pub := strings.Split(strings.Split(string(buf[:n]), "PRIV=")[0], "PUB=")[1]
|
||||
priv := strings.Split(string(buf[:n]), "PRIV=")[1]
|
||||
_priv := strings.Split(string(buf[:n]), "PRIV=")[1]
|
||||
|
||||
priv = removeNewlines(priv) //There is an extraneous newline in the private key, so we'll remove it.
|
||||
priv := removeNewlines(_priv) //There is an extraneous newline in the private key, so we'll remove it.
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"_priv(pre-newline removal)": _priv,
|
||||
"priv": priv,
|
||||
}).Debug("Removed newline")
|
||||
|
||||
log.Debug("Successfully created new destination")
|
||||
|
||||
return &I2PKeys{
|
||||
Address: I2PAddr(pub),
|
||||
@@ -381,5 +463,6 @@ func NewDestination() (*I2PKeys, error) {
|
||||
}, nil
|
||||
|
||||
}
|
||||
log.Error("No RESULT=OK received from SAM bridge")
|
||||
return nil, fmt.Errorf("no result received")
|
||||
}
|
||||
|
@@ -238,3 +238,91 @@ func Test_KeyGenerationAndHandling(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_KeyStorageAndLoading(t *testing.T) {
|
||||
// Generate initial keys
|
||||
keys, err := NewDestination()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate new I2P keys: %v", err)
|
||||
}
|
||||
|
||||
t.Run("StoreAndLoadFile", func(t *testing.T) {
|
||||
// Create temporary directory for test
|
||||
tmpDir, err := ioutil.TempDir("", "test_keys_")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp directory: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
tmpFilePath := filepath.Join(tmpDir, "test_keys.txt")
|
||||
|
||||
// Store keys to file
|
||||
err = StoreKeys(*keys, tmpFilePath)
|
||||
if err != nil {
|
||||
t.Fatalf("StoreKeys failed: %v", err)
|
||||
}
|
||||
|
||||
// Load keys from file
|
||||
loadedKeys, err := LoadKeys(tmpFilePath)
|
||||
if err != nil {
|
||||
t.Fatalf("LoadKeys failed: %v", err)
|
||||
}
|
||||
|
||||
// Verify loaded keys match original
|
||||
if loadedKeys.Address != keys.Address {
|
||||
t.Errorf("Loaded address does not match original. Got %s, want %s",
|
||||
loadedKeys.Address, keys.Address)
|
||||
}
|
||||
if loadedKeys.Both != keys.Both {
|
||||
t.Errorf("Loaded keypair does not match original. Got %s, want %s",
|
||||
loadedKeys.Both, keys.Both)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("StoreAndLoadIncompat", func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
// Store keys to buffer
|
||||
err := StoreKeysIncompat(*keys, &buf)
|
||||
if err != nil {
|
||||
t.Fatalf("StoreKeysIncompat failed: %v", err)
|
||||
}
|
||||
|
||||
// Create new reader from buffer content
|
||||
reader := strings.NewReader(buf.String())
|
||||
|
||||
// Load keys from reader
|
||||
loadedKeys, err := LoadKeysIncompat(reader)
|
||||
if err != nil {
|
||||
t.Fatalf("LoadKeysIncompat failed: %v", err)
|
||||
}
|
||||
|
||||
// Verify loaded keys match original
|
||||
if loadedKeys.Address != keys.Address {
|
||||
t.Errorf("Loaded address does not match original. Got %s, want %s",
|
||||
loadedKeys.Address, keys.Address)
|
||||
}
|
||||
if loadedKeys.Both != keys.Both {
|
||||
t.Errorf("Loaded keypair does not match original. Got %s, want %s",
|
||||
loadedKeys.Both, keys.Both)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("LoadNonexistentFile", func(t *testing.T) {
|
||||
nonexistentPath := filepath.Join(os.TempDir(), "nonexistent_keys.txt")
|
||||
|
||||
_, err := LoadKeys(nonexistentPath)
|
||||
if err != os.ErrNotExist {
|
||||
t.Errorf("Expected ErrNotExist for nonexistent file, got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_BasicInvalidAddress(t *testing.T) {
|
||||
invalidAddr := strings.Repeat("x", 60)
|
||||
invalidAddr += ".b32.i2p"
|
||||
_, err := Lookup(invalidAddr)
|
||||
if err == nil {
|
||||
t.Fatal("Expected error for nonexistent address")
|
||||
}
|
||||
}
|
||||
|
21
Lookup.go
21
Lookup.go
@@ -7,41 +7,60 @@ import (
|
||||
)
|
||||
|
||||
func Lookup(addr string) (*I2PAddr, error) {
|
||||
log.WithField("addr", addr).Debug("Starting Lookup")
|
||||
conn, err := net.Dial("tcp", "127.0.0.1:7656")
|
||||
if err != nil {
|
||||
log.Error("Failed to connect to SAM bridge")
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
_, err = conn.Write([]byte("HELLO VERSION MIN=3.1 MAX=3.1\n"))
|
||||
if err != nil {
|
||||
log.Error("Failed to write HELLO VERSION")
|
||||
return nil, err
|
||||
}
|
||||
buf := make([]byte, 4096)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
log.Error("Failed to read HELLO VERSION response")
|
||||
return nil, err
|
||||
}
|
||||
if n < 1 {
|
||||
log.Error("no data received")
|
||||
return nil, fmt.Errorf("no data received")
|
||||
}
|
||||
|
||||
response := string(buf[:n])
|
||||
log.WithField("response", response).Debug("Received HELLO response")
|
||||
|
||||
if strings.Contains(string(buf[:n]), "RESULT=OK") {
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("NAMING LOOKUP NAME=%s\n", addr)))
|
||||
if err != nil {
|
||||
log.Error("Failed to write NAMING LOOKUP command")
|
||||
return nil, err
|
||||
}
|
||||
n, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
log.Error("Failed to read NAMING LOOKUP response")
|
||||
return nil, err
|
||||
}
|
||||
if n < 1 {
|
||||
return nil, fmt.Errorf("no destination data received")
|
||||
}
|
||||
value := strings.Split(string(buf[:n]), "VALUE=")[1]
|
||||
parts := strings.Split(string(buf[:n]), "VALUE=")
|
||||
if len(parts) < 2 {
|
||||
log.Error("Could not find VALUE=, maybe we couldn't find the destination?")
|
||||
return nil, fmt.Errorf("could not find VALUE=")
|
||||
}
|
||||
value := parts[1]
|
||||
addr, err := NewI2PAddrFromString(value)
|
||||
if err != nil {
|
||||
log.Error("Failed to parse I2P address from lookup response")
|
||||
return nil, err
|
||||
}
|
||||
log.WithField("addr", addr).Debug("Successfully resolved I2P address")
|
||||
return &addr, err
|
||||
}
|
||||
log.Error("no RESULT=OK received in HELLO response")
|
||||
return nil, fmt.Errorf("no result received")
|
||||
}
|
||||
|
92
Makefile
92
Makefile
@@ -1,6 +1,6 @@
|
||||
|
||||
USER_GH=eyedeekay
|
||||
VERSION=0.33.7
|
||||
VERSION=0.33.8
|
||||
packagename=i2pkeys
|
||||
|
||||
echo:
|
||||
@@ -29,3 +29,93 @@ fmt:
|
||||
upload-linux:
|
||||
github-release upload -R -u $(USER_GH) -r "$(packagename)" -t $(VERSION) -l `sha256sum ` -n "$(packagename)" -f "$(packagename)"
|
||||
|
||||
test-basic:
|
||||
go test -v -run Test_Basic
|
||||
|
||||
test-basic-lookup:
|
||||
go test -v -run Test_Basic_Lookup
|
||||
|
||||
test-newi2paddrfromstring:
|
||||
go test -v -run Test_NewI2PAddrFromString
|
||||
|
||||
test-i2paddr:
|
||||
go test -v -run Test_I2PAddr
|
||||
|
||||
test-desthashfromstring:
|
||||
go test -v -run Test_DestHashFromString
|
||||
|
||||
test-i2paddr-to-bytes:
|
||||
go test -v -run Test_I2PAddrToBytes
|
||||
|
||||
test-key-generation-and-handling:
|
||||
go test -v -run Test_KeyGenerationAndHandling
|
||||
|
||||
# Subtest targets
|
||||
test-newi2paddrfromstring-valid:
|
||||
go test -v -run Test_NewI2PAddrFromString/Valid_base64_address
|
||||
|
||||
test-newi2paddrfromstring-invalid:
|
||||
go test -v -run Test_NewI2PAddrFromString/Invalid_address
|
||||
|
||||
test-newi2paddrfromstring-base32:
|
||||
go test -v -run Test_NewI2PAddrFromString/Base32_address
|
||||
|
||||
test-newi2paddrfromstring-empty:
|
||||
go test -v -run Test_NewI2PAddrFromString/Empty_address
|
||||
|
||||
test-newi2paddrfromstring-i2p-suffix:
|
||||
go test -v -run Test_NewI2PAddrFromString/Address_with_.i2p_suffix
|
||||
|
||||
test-i2paddr-base32-suffix:
|
||||
go test -v -run Test_I2PAddr/Base32_suffix
|
||||
|
||||
test-i2paddr-base32-length:
|
||||
go test -v -run Test_I2PAddr/Base32_length
|
||||
|
||||
test-desthashfromstring-valid:
|
||||
go test -v -run Test_DestHashFromString/Valid_hash
|
||||
|
||||
test-desthashfromstring-invalid:
|
||||
go test -v -run Test_DestHashFromString/Invalid_hash
|
||||
|
||||
test-desthashfromstring-empty:
|
||||
go test -v -run Test_DestHashFromString/Empty_hash
|
||||
|
||||
test-i2paddr-to-bytes-roundtrip:
|
||||
go test -v -run Test_I2PAddrToBytes/ToBytes_and_back
|
||||
|
||||
test-i2paddr-to-bytes-comparison:
|
||||
go test -v -run Test_I2PAddrToBytes/Direct_decoding_comparison
|
||||
|
||||
test-key-generation-and-handling-loadkeys:
|
||||
go test -v -run Test_KeyGenerationAndHandling/LoadKeysIncompat
|
||||
|
||||
test-key-generation-and-handling-storekeys-incompat:
|
||||
go test -v -run Test_KeyGenerationAndHandling/StoreKeysIncompat
|
||||
|
||||
test-key-generation-and-handling-storekeys:
|
||||
go test -v -run Test_KeyGenerationAndHandling/StoreKeys
|
||||
|
||||
test-key-storage:
|
||||
go test -v -run Test_KeyStorageAndLoading
|
||||
|
||||
# Individual key storage subtests
|
||||
test-key-storage-file:
|
||||
go test -v -run Test_KeyStorageAndLoading/StoreAndLoadFile
|
||||
|
||||
test-key-storage-incompat:
|
||||
go test -v -run Test_KeyStorageAndLoading/StoreAndLoadIncompat
|
||||
|
||||
test-key-storage-nonexistent:
|
||||
go test -v -run Test_KeyStorageAndLoading/LoadNonexistentFile
|
||||
|
||||
test-basic-invalid-address:
|
||||
go test -v -run Test_BasicInvalidAddress
|
||||
|
||||
# Aggregate targets
|
||||
test-all:
|
||||
go test -v ./...
|
||||
|
||||
test-subtests: test-newi2paddrfromstring-valid test-newi2paddrfromstring-invalid test-newi2paddrfromstring-base32 test-newi2paddrfromstring-empty test-newi2paddrfromstring-i2p-suffix test-i2paddr-base32-suffix test-i2paddr-base32-length test-desthashfromstring-valid test-desthashfromstring-invalid test-desthashfromstring-empty test-i2paddr-to-bytes-roundtrip test-i2paddr-to-bytes-comparison test-key-generation-and-handling-loadkeys test-key-generation-and-handling-storekeys-incompat test-key-generation-and-handling-storekeys test-key-storage-file test-key-storage-incompat test-key-storage-nonexistent
|
||||
|
||||
test: test-basic test-basic-lookup test-newi2paddrfromstring test-i2paddr test-desthashfromstring test-i2paddr-to-bytes test-key-generation-and-handling test-key-storage test-basic-invalid-address test-subtests test-all
|
20
README.md
20
README.md
@@ -3,3 +3,23 @@ i2pkeys
|
||||
|
||||
Generates and displays the contents of files that are storing i2p keys in the
|
||||
incompatible format used for sam3
|
||||
|
||||
## Verbosity ##
|
||||
Logging can be enabled and configured using the DEBUG_I2P environment variable. By default, logging is disabled.
|
||||
|
||||
There are three available log levels:
|
||||
|
||||
- Debug
|
||||
```shell
|
||||
export DEBUG_I2P=debug
|
||||
```
|
||||
- Warn
|
||||
```shell
|
||||
export DEBUG_I2P=warn
|
||||
```
|
||||
- Error
|
||||
```shell
|
||||
export DEBUG_I2P=error
|
||||
```
|
||||
|
||||
If DEBUG_I2P is set to an unrecognized variable, it will fall back to "debug".
|
5
go.mod
5
go.mod
@@ -1,3 +1,8 @@
|
||||
module github.com/eyedeekay/i2pkeys
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
||||
)
|
||||
|
50
log.go
Normal file
50
log.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package i2pkeys
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
log *logrus.Logger
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
func InitializeI2PKeysLogger() {
|
||||
once.Do(func() {
|
||||
log = logrus.New()
|
||||
// We do not want to log by default
|
||||
log.SetOutput(ioutil.Discard)
|
||||
log.SetLevel(logrus.PanicLevel)
|
||||
// Check if DEBUG_I2P is set
|
||||
if logLevel := os.Getenv("DEBUG_I2P"); logLevel != "" {
|
||||
log.SetOutput(os.Stdout)
|
||||
switch strings.ToLower(logLevel) {
|
||||
case "debug":
|
||||
log.SetLevel(logrus.DebugLevel)
|
||||
case "warn":
|
||||
log.SetLevel(logrus.WarnLevel)
|
||||
case "error":
|
||||
log.SetLevel(logrus.ErrorLevel)
|
||||
default:
|
||||
log.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
log.WithField("level", log.GetLevel()).Debug("Logging enabled.")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// GetI2PKeysLogger returns the initialized logger
|
||||
func GetI2PKeysLogger() *logrus.Logger {
|
||||
if log == nil {
|
||||
InitializeI2PKeysLogger()
|
||||
}
|
||||
return log
|
||||
}
|
||||
|
||||
func init() {
|
||||
InitializeI2PKeysLogger()
|
||||
}
|
Reference in New Issue
Block a user