Fix merge conflict
This commit is contained in:
129
I2PAddr.go
129
I2PAddr.go
@ -10,6 +10,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@ -37,6 +38,7 @@ type I2PKeys struct {
|
|||||||
// Creates I2PKeys from an I2PAddr and a public/private keypair string (as
|
// Creates I2PKeys from an I2PAddr and a public/private keypair string (as
|
||||||
// generated by String().)
|
// generated by String().)
|
||||||
func NewKeys(addr I2PAddr, both string) I2PKeys {
|
func NewKeys(addr I2PAddr, both string) I2PKeys {
|
||||||
|
log.WithField("addr", addr).Debug("Creating new I2PKeys")
|
||||||
return I2PKeys{addr, both}
|
return I2PKeys{addr, both}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,54 +47,98 @@ func NewKeys(addr I2PAddr, both string) I2PKeys {
|
|||||||
func fileExists(filename string) (bool, error) {
|
func fileExists(filename string) (bool, error) {
|
||||||
info, err := os.Stat(filename)
|
info, err := os.Stat(filename)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
log.WithField("filename", filename).Debug("File does not exist")
|
||||||
return false, nil
|
return false, nil
|
||||||
} else if err != 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
|
return !info.IsDir(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// load keys from non standard format
|
// LoadKeysIncompat loads keys from a non-standard format
|
||||||
func LoadKeysIncompat(r io.Reader) (k I2PKeys, err error) {
|
func LoadKeysIncompat(r io.Reader) (I2PKeys, error) {
|
||||||
|
log.Debug("Loading keys from reader")
|
||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
_, err = io.Copy(&buff, r)
|
_, err := io.Copy(&buff, r)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
parts := strings.Split(buff.String(), "\n")
|
log.WithError(err).Error("Error copying from reader, did not load keys")
|
||||||
k = I2PKeys{I2PAddr(parts[0]), parts[1]}
|
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.
|
// load keys from non-standard format by specifying a text file.
|
||||||
// If the file does not exist, generate keys, otherwise, fail
|
// If the file does not exist, generate keys, otherwise, fail
|
||||||
// closed.
|
// closed.
|
||||||
func LoadKeys(r string) (I2PKeys, error) {
|
func LoadKeys(r string) (I2PKeys, error) {
|
||||||
|
log.WithField("filename", r).Debug("Loading keys from file")
|
||||||
exists, err := fileExists(r)
|
exists, err := fileExists(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Error checking if file exists")
|
||||||
return I2PKeys{}, err
|
return I2PKeys{}, err
|
||||||
}
|
}
|
||||||
if exists {
|
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
|
||||||
|
}
|
||||||
|
// 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)
|
fi, err := os.Open(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return I2PKeys{}, err
|
log.WithError(err).WithField("filename", r).Error("Error opening file")
|
||||||
|
return I2PKeys{}, fmt.Errorf("error opening file: %w", err)
|
||||||
}
|
}
|
||||||
defer fi.Close()
|
defer fi.Close()
|
||||||
|
log.WithField("filename", r).Debug("File opened successfully")
|
||||||
return LoadKeysIncompat(fi)
|
return LoadKeysIncompat(fi)
|
||||||
}
|
|
||||||
return I2PKeys{}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// store keys in non standard format
|
// store keys in non standard format
|
||||||
func StoreKeysIncompat(k I2PKeys, w io.Writer) (err error) {
|
func StoreKeysIncompat(k I2PKeys, w io.Writer) error {
|
||||||
_, err = io.WriteString(w, k.Address.Base64()+"\n"+k.Both)
|
log.Debug("Storing keys")
|
||||||
return
|
_, 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 {
|
func StoreKeys(k I2PKeys, r string) error {
|
||||||
|
log.WithField("filename", r).Debug("Storing keys to file")
|
||||||
if _, err := os.Stat(r); err != nil {
|
if _, err := os.Stat(r); err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
log.WithField("filename", r).Debug("File does not exist, creating new file")
|
||||||
fi, err := os.Create(r)
|
fi, err := os.Create(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Error creating file")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer fi.Close()
|
defer fi.Close()
|
||||||
@ -101,6 +147,7 @@ func StoreKeys(k I2PKeys, r string) error {
|
|||||||
}
|
}
|
||||||
fi, err := os.Open(r)
|
fi, err := os.Open(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Error opening file")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer fi.Close()
|
defer fi.Close()
|
||||||
@ -121,10 +168,12 @@ func (k I2PKeys) Public() crypto.PublicKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (k I2PKeys) Private() []byte {
|
func (k I2PKeys) Private() []byte {
|
||||||
|
log.Debug("Extracting private key")
|
||||||
src := strings.Split(k.String(), k.Addr().String())[0]
|
src := strings.Split(k.String(), k.Addr().String())[0]
|
||||||
var dest []byte
|
var dest []byte
|
||||||
_, err := i2pB64enc.Decode(dest, []byte(src))
|
_, err := i2pB64enc.Decode(dest, []byte(src))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Error decoding private key")
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return dest
|
return dest
|
||||||
@ -143,6 +192,7 @@ func (k I2PKeys) PrivateKey() crypto.PrivateKey {
|
|||||||
var pk ed25519.PrivateKey = k.Private()
|
var pk ed25519.PrivateKey = k.Private()
|
||||||
_, err := pk.Sign(rand.Reader, []byte("nonsense"), crypto.Hash(0))
|
_, err := pk.Sign(rand.Reader, []byte("nonsense"), crypto.Hash(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Warn("Error in private key signature")
|
||||||
//TODO: Elgamal, P256, P384, P512, GOST? keys?
|
//TODO: Elgamal, P256, P384, P512, GOST? keys?
|
||||||
}
|
}
|
||||||
return pk
|
return pk
|
||||||
@ -173,7 +223,8 @@ func (k I2PKeys) String() string {
|
|||||||
func (k I2PKeys) HostnameEntry(hostname string, opts crypto.SignerOpts) (string, error) {
|
func (k I2PKeys) HostnameEntry(hostname string, opts crypto.SignerOpts) (string, error) {
|
||||||
sig, err := k.Sign(rand.Reader, []byte(hostname), opts)
|
sig, err := k.Sign(rand.Reader, []byte(hostname), opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
log.WithError(err).Error("Error signing hostname")
|
||||||
|
return "", fmt.Errorf("error signing hostname: %w", err)
|
||||||
}
|
}
|
||||||
return string(sig), nil
|
return string(sig), nil
|
||||||
}
|
}
|
||||||
@ -189,25 +240,33 @@ type I2PDestHash [32]byte
|
|||||||
|
|
||||||
// create a desthash from a string b32.i2p address
|
// create a desthash from a string b32.i2p address
|
||||||
func DestHashFromString(str string) (dhash I2PDestHash, err error) {
|
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 {
|
if strings.HasSuffix(str, ".b32.i2p") && len(str) == 60 {
|
||||||
// valid
|
// valid
|
||||||
_, err = i2pB32enc.Decode(dhash[:], []byte(str[:52]+"===="))
|
_, err = i2pB32enc.Decode(dhash[:], []byte(str[:52]+"===="))
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Error decoding base32 address")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// invalid
|
// invalid
|
||||||
err = errors.New("invalid desthash format")
|
err = errors.New("invalid desthash format")
|
||||||
|
log.WithError(err).Error("Invalid desthash format")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a desthash from a []byte array
|
// create a desthash from a []byte array
|
||||||
func DestHashFromBytes(str []byte) (dhash I2PDestHash, err error) {
|
func DestHashFromBytes(str []byte) (dhash I2PDestHash, err error) {
|
||||||
|
log.Debug("Creating DestHash from bytes")
|
||||||
if len(str) == 32 {
|
if len(str) == 32 {
|
||||||
// valid
|
// valid
|
||||||
//_, err = i2pB32enc.Decode(dhash[:], []byte(str[:52]+"===="))
|
//_, err = i2pB32enc.Decode(dhash[:], []byte(str[:52]+"===="))
|
||||||
|
log.WithField("str", str).Debug("Copying str to desthash")
|
||||||
copy(dhash[:], str)
|
copy(dhash[:], str)
|
||||||
} else {
|
} else {
|
||||||
// invalid
|
// invalid
|
||||||
err = errors.New("invalid desthash format")
|
err = errors.New("invalid desthash format")
|
||||||
|
log.WithField("str", str).Error("Invalid desthash format")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -255,10 +314,11 @@ func (a I2PAddr) Network() string {
|
|||||||
// Creates a new I2P address from a base64-encoded string. Checks if the address
|
// 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).)
|
// addr is in correct format. (If you know for sure it is, use I2PAddr(addr).)
|
||||||
func NewI2PAddrFromString(addr string) (I2PAddr, error) {
|
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, ".i2p") {
|
||||||
if strings.HasSuffix(addr, ".b32.i2p") {
|
if strings.HasSuffix(addr, ".b32.i2p") {
|
||||||
// do a lookup of the b32
|
// 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")
|
return I2PAddr(""), errors.New("cannot convert .b32.i2p to full destination")
|
||||||
}
|
}
|
||||||
// strip off .i2p if it's there
|
// 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 ")
|
addr = strings.Trim(addr, "\t\n\r\f ")
|
||||||
// very basic check
|
// very basic check
|
||||||
if len(addr) > 4096 || len(addr) < 516 {
|
if len(addr) > 4096 || len(addr) < 516 {
|
||||||
|
log.Error("Invalid I2P address length")
|
||||||
return I2PAddr(""), errors.New(addr + " is not an I2P address")
|
return I2PAddr(""), errors.New(addr + " is not an I2P address")
|
||||||
}
|
}
|
||||||
buf := make([]byte, i2pB64enc.DecodedLen(len(addr)))
|
buf := make([]byte, i2pB64enc.DecodedLen(len(addr)))
|
||||||
if _, err := i2pB64enc.Decode(buf, []byte(addr)); err != nil {
|
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")
|
return I2PAddr(""), errors.New("Address is not base64-encoded")
|
||||||
}
|
}
|
||||||
|
log.Debug("Successfully created I2PAddr from string")
|
||||||
return I2PAddr(addr), nil
|
return I2PAddr(addr), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FiveHundredAs() I2PAddr {
|
func FiveHundredAs() I2PAddr {
|
||||||
|
log.Debug("Generating I2PAddr with 500 'A's")
|
||||||
s := ""
|
s := ""
|
||||||
for x := 0; x < 517; x++ {
|
for x := 0; x < 517; x++ {
|
||||||
s += "A"
|
s += "A"
|
||||||
@ -287,7 +351,9 @@ func FiveHundredAs() I2PAddr {
|
|||||||
|
|
||||||
// Creates a new I2P address from a byte array. The inverse of ToBytes().
|
// Creates a new I2P address from a byte array. The inverse of ToBytes().
|
||||||
func NewI2PAddrFromBytes(addr []byte) (I2PAddr, error) {
|
func NewI2PAddrFromBytes(addr []byte) (I2PAddr, error) {
|
||||||
|
log.Debug("Creating I2PAddr from bytes")
|
||||||
if len(addr) > 4096 || len(addr) < 384 {
|
if len(addr) > 4096 || len(addr) < 384 {
|
||||||
|
log.Error("Invalid I2P address length")
|
||||||
return I2PAddr(""), errors.New("Not an I2P address")
|
return I2PAddr(""), errors.New("Not an I2P address")
|
||||||
}
|
}
|
||||||
buf := make([]byte, i2pB64enc.EncodedLen(len(addr)))
|
buf := make([]byte, i2pB64enc.EncodedLen(len(addr)))
|
||||||
@ -335,6 +401,11 @@ HELLO VERSION MIN=3.1 MAX=3.1
|
|||||||
DEST GENERATE SIGNATURE_TYPE=7
|
DEST GENERATE SIGNATURE_TYPE=7
|
||||||
*/
|
*/
|
||||||
func NewDestination() (*I2PKeys, error) {
|
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")
|
conn, err := net.Dial("tcp", "127.0.0.1:7656")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -342,30 +413,49 @@ func NewDestination() (*I2PKeys, error) {
|
|||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
_, err = conn.Write([]byte("HELLO VERSION MIN=3.1 MAX=3.1\n"))
|
_, err = conn.Write([]byte("HELLO VERSION MIN=3.1 MAX=3.1\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Error writing to SAM bridge")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
buf := make([]byte, 4096)
|
buf := make([]byte, 4096)
|
||||||
n, err := conn.Read(buf)
|
n, err := conn.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Error reading from SAM bridge")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
|
log.Error("No data received from SAM bridge")
|
||||||
return nil, fmt.Errorf("no data received")
|
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") {
|
if strings.Contains(string(buf[:n]), "RESULT=OK") {
|
||||||
_, err = conn.Write([]byte("DEST GENERATE SIGNATURE_TYPE=7\n"))
|
_, err = conn.Write([]byte("DEST GENERATE SIGNATURE_TYPE=7\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Error writing DEST GENERATE to SAM bridge")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
n, err = conn.Read(buf)
|
n, err = conn.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Error reading destination from SAM bridge")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
|
log.Error("No destination data received from SAM bridge")
|
||||||
return nil, fmt.Errorf("no destination data received")
|
return nil, fmt.Errorf("no destination data received")
|
||||||
}
|
}
|
||||||
pub := strings.Split(strings.Split(string(buf[:n]), "PRIV=")[0], "PUB=")[1]
|
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{
|
return &I2PKeys{
|
||||||
Address: I2PAddr(pub),
|
Address: I2PAddr(pub),
|
||||||
@ -373,5 +463,6 @@ func NewDestination() (*I2PKeys, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
log.Error("No RESULT=OK received from SAM bridge")
|
||||||
return nil, fmt.Errorf("no result received")
|
return nil, fmt.Errorf("no result received")
|
||||||
}
|
}
|
||||||
|
313
I2PAddr_test.go
313
I2PAddr_test.go
@ -1,21 +1,28 @@
|
|||||||
package i2pkeys
|
package i2pkeys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"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) {
|
func Test_Basic(t *testing.T) {
|
||||||
fmt.Println("Test_Basic")
|
fmt.Println("Test_Basic")
|
||||||
fmt.Println("\tAttaching to SAM at " + yoursam)
|
fmt.Println("\tAttaching to SAM at " + yoursam)
|
||||||
keys, err := NewDestination()
|
keys, err := NewDestination()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
t.Fatal(err.Error())
|
||||||
t.Fail()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
fmt.Println(keys.String())
|
fmt.Println(keys.String())
|
||||||
}
|
}
|
||||||
@ -23,11 +30,299 @@ func Test_Basic(t *testing.T) {
|
|||||||
func Test_Basic_Lookup(t *testing.T) {
|
func Test_Basic_Lookup(t *testing.T) {
|
||||||
fmt.Println("Test_Basic")
|
fmt.Println("Test_Basic")
|
||||||
fmt.Println("\tAttaching to SAM at " + yoursam)
|
fmt.Println("\tAttaching to SAM at " + yoursam)
|
||||||
keys, err := Lookup("idk.i2p")
|
keys, err := Lookup(validShortenedI2PAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
t.Fatal(err.Error())
|
||||||
t.Fail()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
fmt.Println(keys.String())
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
21
Lookup.go
21
Lookup.go
@ -7,41 +7,60 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Lookup(addr string) (*I2PAddr, error) {
|
func Lookup(addr string) (*I2PAddr, error) {
|
||||||
|
log.WithField("addr", addr).Debug("Starting Lookup")
|
||||||
conn, err := net.Dial("tcp", "127.0.0.1:7656")
|
conn, err := net.Dial("tcp", "127.0.0.1:7656")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Error("Failed to connect to SAM bridge")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
_, err = conn.Write([]byte("HELLO VERSION MIN=3.1 MAX=3.1\n"))
|
_, err = conn.Write([]byte("HELLO VERSION MIN=3.1 MAX=3.1\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Error("Failed to write HELLO VERSION")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
buf := make([]byte, 4096)
|
buf := make([]byte, 4096)
|
||||||
n, err := conn.Read(buf)
|
n, err := conn.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Error("Failed to read HELLO VERSION response")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
|
log.Error("no data received")
|
||||||
return nil, fmt.Errorf("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") {
|
if strings.Contains(string(buf[:n]), "RESULT=OK") {
|
||||||
_, err = conn.Write([]byte(fmt.Sprintf("NAMING LOOKUP NAME=%s\n", addr)))
|
_, err = conn.Write([]byte(fmt.Sprintf("NAMING LOOKUP NAME=%s\n", addr)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Error("Failed to write NAMING LOOKUP command")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
n, err = conn.Read(buf)
|
n, err = conn.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Error("Failed to read NAMING LOOKUP response")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
return nil, fmt.Errorf("no destination data received")
|
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)
|
addr, err := NewI2PAddrFromString(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Error("Failed to parse I2P address from lookup response")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
log.WithField("addr", addr).Debug("Successfully resolved I2P address")
|
||||||
return &addr, err
|
return &addr, err
|
||||||
}
|
}
|
||||||
|
log.Error("no RESULT=OK received in HELLO response")
|
||||||
return nil, fmt.Errorf("no result received")
|
return nil, fmt.Errorf("no result received")
|
||||||
}
|
}
|
||||||
|
90
Makefile
90
Makefile
@ -30,3 +30,93 @@ fmt:
|
|||||||
upload-linux:
|
upload-linux:
|
||||||
github-release upload -R -u $(USER_GH) -r "$(packagename)" -t $(VERSION) -l `sha256sum ` -n "$(packagename)" -f "$(packagename)"
|
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
|
Generates and displays the contents of files that are storing i2p keys in the
|
||||||
incompatible format used for sam3
|
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/go-i2p/i2pkeys
|
module github.com/go-i2p/i2pkeys
|
||||||
|
|
||||||
go 1.17
|
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