Fix merge conflict

This commit is contained in:
eyedeekay
2024-11-08 15:03:32 -05:00
7 changed files with 600 additions and 30 deletions

View File

@ -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,54 +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 {
return false, err
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 {
fi, err := os.Open(r)
if !exists {
// 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
}
defer fi.Close()
return LoadKeysIncompat(fi)
// 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
}
return I2PKeys{}, err
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) (err error) {
_, err = io.WriteString(w, k.Address.Base64()+"\n"+k.Both)
return
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()
@ -101,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()
@ -121,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
@ -143,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
@ -173,7 +223,8 @@ 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 {
return "", err
log.WithError(err).Error("Error signing hostname")
return "", fmt.Errorf("error signing hostname: %w", err)
}
return string(sig), nil
}
@ -189,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
}
@ -255,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
@ -267,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"
@ -287,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)))
@ -335,6 +401,11 @@ HELLO VERSION MIN=3.1 MAX=3.1
DEST GENERATE SIGNATURE_TYPE=7
*/
func NewDestination() (*I2PKeys, error) {
removeNewlines := func(s string) string {
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
@ -342,30 +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.
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),
@ -373,5 +463,6 @@ func NewDestination() (*I2PKeys, error) {
}, nil
}
log.Error("No RESULT=OK received from SAM bridge")
return nil, fmt.Errorf("no result received")
}

View File

@ -1,21 +1,28 @@
package i2pkeys
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
// "time"
)
const yoursam = "127.0.0.1:7656"
const (
yoursam = "127.0.0.1:7656"
validShortenedI2PAddr = "idk.i2p"
validI2PAddrB32 = "b2o47zwxqjbn7jj37yqkmvbmci7kqubwgxu3umqid7cexmc7xudq.b32.i2p"
validI2PAddrB64 = "spHxea2xhPjKH9yyEeFJ96aqtvKidH-GiWxs8dH6RWS2FrDoWFhuEkfw77pF~Hv57lLhMaMB3qqWjCtYXOjL48Q1zYbr3MAcTO44wwVPjOU1hU77vbJcUuwBeRvaSr2dZx-FiTSOdQuhPD1EozYNRIMFwZ0fZwKf~3Gj4dEWccOLKs~NbiPsj-~tc5tmhAs8yBeoZEqEBe40X75SfSHY-EnstcZevVAwIXYk3zX3KF0mji3bo2QXuTFcMZHHLiLd2AHLRANzWyvQ9DC1rnCsHJM4xxV4dVp0pHkP1hwBo7E0NJvN4nFkQcj-FI2RJ~cFUCk7qc86PRHwvKCjzSlrgjtDsMUwd83Dz1PfpzCqHNLUFWI7uPKbKcJZhasFm4kEhUyupd85q75Ch2IZE9J2JXodSxmseO5ZKcHK6pFtfR-HbzKjIe92TWHsNkmvtoHiUaOVrWnk-cmo2I1W1VxfL08teDxQ13P80uFaMcameRzuFM2F8pSOpoyEJUDRGLEeBQAEAAcAAA=="
)
func Test_Basic(t *testing.T) {
fmt.Println("Test_Basic")
fmt.Println("\tAttaching to SAM at " + yoursam)
keys, err := NewDestination()
if err != nil {
fmt.Println(err.Error())
t.Fail()
return
t.Fatal(err.Error())
}
fmt.Println(keys.String())
}
@ -23,11 +30,299 @@ func Test_Basic(t *testing.T) {
func Test_Basic_Lookup(t *testing.T) {
fmt.Println("Test_Basic")
fmt.Println("\tAttaching to SAM at " + yoursam)
keys, err := Lookup("idk.i2p")
keys, err := Lookup(validShortenedI2PAddr)
if err != nil {
fmt.Println(err.Error())
t.Fail()
return
t.Fatal(err.Error())
}
fmt.Println(keys.String())
}
func Test_NewI2PAddrFromString(t *testing.T) {
t.Run("Valid base64 address", func(t *testing.T) {
addr, err := NewI2PAddrFromString(validI2PAddrB64)
if err != nil {
t.Fatalf("NewI2PAddrFromString failed for valid address: '%v'", err)
}
if addr.Base64() != validI2PAddrB64 {
t.Errorf("NewI2PAddrFromString returned incorrect address. Got '%s', want '%s'", addr.Base64(), validI2PAddrB64)
}
})
t.Run("Invalid address", func(t *testing.T) {
invalidAddr := "not-a-valid-address"
_, err := NewI2PAddrFromString(invalidAddr)
if err == nil {
t.Error("NewI2PAddrFromString should have failed for invalid address")
}
})
t.Run("Base32 address", func(t *testing.T) {
_, err := NewI2PAddrFromString(validI2PAddrB32)
if err == nil {
t.Error("NewI2PAddrFromString should have failed for base32 address")
}
})
t.Run("Empty address", func(t *testing.T) {
_, err := NewI2PAddrFromString("")
if err == nil {
t.Error("NewI2PAddrFromString should have failed for empty address")
}
})
t.Run("Address with .i2p suffix", func(t *testing.T) { //CHECK
addr, err := NewI2PAddrFromString(validI2PAddrB64 + ".i2p")
if err != nil {
t.Fatalf("NewI2PAddrFromString failed for address with .i2p suffix: '%v'", err)
}
if addr.Base64() != validI2PAddrB64 {
t.Errorf("NewI2PAddrFromString returned incorrect address. Got '%s', want '%s'", addr.Base64(), validI2PAddrB64)
}
})
}
func Test_I2PAddr(t *testing.T) {
addr := I2PAddr(validI2PAddrB64)
base32 := addr.Base32()
t.Run("Base32 suffix", func(t *testing.T) {
if !strings.HasSuffix(base32, ".b32.i2p") {
t.Errorf("Base32 address should end with .b32.i2p, got %s", base32)
}
})
t.Run("Base32 length", func(t *testing.T) {
if len(base32) != 60 {
t.Errorf("Base32 address should be 60 characters long, got %d", len(base32))
}
})
}
func Test_DestHashFromString(t *testing.T) {
t.Run("Valid hash", func(t *testing.T) {
hash, err := DestHashFromString(validI2PAddrB32)
if err != nil {
t.Fatalf("DestHashFromString failed for valid hash: '%v'", err)
}
if hash.String() != validI2PAddrB32 {
t.Errorf("DestHashFromString returned incorrect hash. Got '%s', want '%s'", hash.String(), validI2PAddrB32)
}
})
t.Run("Invalid hash", func(t *testing.T) {
invalidHash := "not-a-valid-hash"
_, err := DestHashFromString(invalidHash)
if err == nil {
t.Error("DestHashFromString should have failed for invalid hash")
}
})
t.Run("Empty hash", func(t *testing.T) {
_, err := DestHashFromString("")
if err == nil {
t.Error("DestHashFromString should have failed for empty hash")
}
})
}
func Test_I2PAddrToBytes(t *testing.T) {
addr := I2PAddr(validI2PAddrB64)
t.Run("ToBytes and back", func(t *testing.T) {
decodedBytes, err := addr.ToBytes()
if err != nil {
t.Fatalf("ToBytes failed: '%v'", err)
}
encodedString := i2pB64enc.EncodeToString(decodedBytes)
if encodedString != validI2PAddrB64 {
t.Errorf("Round-trip encoding/decoding failed. Got '%s', want '%s'", encodedString, validI2PAddrB64)
}
})
t.Run("Direct decoding comparison", func(t *testing.T) {
decodedBytes, err := addr.ToBytes()
if err != nil {
t.Fatalf("ToBytes failed: '%v'", err)
}
directlyDecoded, err := i2pB64enc.DecodeString(validI2PAddrB64)
if err != nil {
t.Fatalf("Failed to decode test string using i2pB64enc: '%v'", err)
}
if !bytes.Equal(decodedBytes, directlyDecoded) {
t.Errorf("Mismatch between ToBytes result and direct decoding. ToBytes len: '%d', Direct decoding len: '%d'", len(decodedBytes), len(directlyDecoded))
}
})
}
/*
func removeNewlines(s string) string {
return strings.ReplaceAll(strings.ReplaceAll(s, "\r\n", ""), "\n", "")
}
*/
func Test_KeyGenerationAndHandling(t *testing.T) {
// Generate new keys
keys, err := NewDestination()
if err != nil {
t.Fatalf("Failed to generate new I2P keys: %v", err)
}
t.Run("LoadKeysIncompat", func(t *testing.T) {
//extract keys
addr := keys.Address
fmt.Println(addr)
//both := removeNewlines(keys.Both)
both := keys.Both
fmt.Println(both)
//FORMAT TO LOAD: (Address, Both)
addrload := addr.Base64() + "\n" + both
r := strings.NewReader(addrload)
loadedKeys, err := LoadKeysIncompat(r)
if err != nil {
t.Fatalf("LoadKeysIncompat failed: %v", err)
}
if loadedKeys.Address != keys.Address {
//fmt.Printf("loadedKeys.Address md5hash: '%s'\n keys.Address md5hash: '%s'\n", getMD5Hash(string(loadedKeys.Address)), getMD5Hash(string(keys.Address)))
t.Errorf("LoadKeysIncompat returned incorrect address. Got '%s', want '%s'", loadedKeys.Address, keys.Address)
}
if loadedKeys.Both != keys.Both {
t.Errorf("LoadKeysIncompat returned incorrect pair. Got '%s'\nwant '%s'\n", loadedKeys.Both, keys.Both)
/*
if loadedKeys.Both == removeNewlines(keys.Both) {
fmt.Println("However, both pairs are correct if newline is removed in generated keys.")
}
*/
}
})
expected := keys.Address.Base64() + "\n" + keys.Both
t.Run("StoreKeysIncompat", func(t *testing.T) {
var buf bytes.Buffer
err := StoreKeysIncompat(*keys, &buf)
if err != nil {
t.Fatalf("StoreKeysIncompat failed: '%v'", err)
}
if buf.String() != expected {
t.Errorf("StoreKeysIncompat wrote incorrect data. Got '%s', want '%s'", buf.String(), expected)
}
})
t.Run("StoreKeys", func(t *testing.T) {
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")
err = StoreKeys(*keys, tmpFilePath)
if err != nil {
t.Fatalf("StoreKeys failed: '%v'", err)
}
content, err := ioutil.ReadFile(tmpFilePath)
if err != nil {
t.Fatalf("Failed to read temp file: '%v'", err)
}
if string(content) != expected {
t.Errorf("StoreKeys wrote incorrect data. Got '%s', want '%s'", string(content), expected)
}
})
}
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")
}
}

View File

@ -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")
}

View File

@ -30,3 +30,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

View File

@ -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
View File

@ -1,3 +1,8 @@
module github.com/go-i2p/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
View 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()
}