taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

commit 4d18913f8c39448f892c3d018fd20daa8ec67faa
parent cfeed0cca3aba77cd2a5b365435e0df47d1c9d3d
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date:   Sun, 27 Apr 2025 00:07:11 +0200

vendor base32 functions

Diffstat:
MMakefile.in | 4++--
Mcmd/taldir-cli/main.go | 3+--
Mcmd/taldir-server/main_test.go | 4+---
Mgo.mod | 4----
Mgo.sum | 2--
Minternal/util/helper.go | 110++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mpkg/rest/taldir.go | 12+++++-------
Dthird_party/gnunet-go | 1-
8 files changed, 116 insertions(+), 24 deletions(-)

diff --git a/Makefile.in b/Makefile.in @@ -4,10 +4,10 @@ SCRIPT_TARGET:=$(shell dirname $(shell go list -f '{{.Target}}' ./cmd/taldir-ser TALER_DIRECTORY_HOME=${datadir}/taler-directory VERSION=`git describe --tags` -server: gana +server: ${GO} build -o taler-directory -ldflags "-X main.version=${VERSION} -X main.taldirdatahome=${TALER_DIRECTORY_HOME}" ./cmd/taldir-server -cli: gana +cli: ${GO} build -ldflags "-X main.version=${VERSION} -X main.taldirdatahome=${TALER_DIRECTORY_HOME}" ./cmd/taldir-cli install: server cli diff --git a/cmd/taldir-cli/main.go b/cmd/taldir-cli/main.go @@ -26,7 +26,6 @@ import ( "net/url" "os" - gnunetutil "gnunet/util" "gopkg.in/ini.v1" "taler.net/taldir/internal/util" ) @@ -35,7 +34,7 @@ import ( func generateLink(host string, addr string, challenge string) string { h := sha512.New() h.Write([]byte(addr)) - h_addr := gnunetutil.EncodeBinaryToString(h.Sum(nil)) + h_addr := util.Base32CrockfordEncode(h.Sum(nil)) return host + "/register/" + url.QueryEscape(h_addr) + "/" + url.QueryEscape(challenge) + "?address=" + url.QueryEscape(addr) } diff --git a/cmd/taldir-server/main_test.go b/cmd/taldir-server/main_test.go @@ -30,8 +30,6 @@ import ( "strings" "testing" - gnunetutil "gnunet/util" - "github.com/schanzen/taler-go/pkg/merchant" "gopkg.in/ini.v1" "gorm.io/driver/sqlite" @@ -150,7 +148,7 @@ func TestMain(m *testing.M) { func getHAddress(addr string) string { h := sha512.New() h.Write([]byte(addr)) - return gnunetutil.EncodeBinaryToString(h.Sum(nil)) + return util.Base32CrockfordEncode(h.Sum(nil)) } func TestNoEntry(s *testing.T) { diff --git a/go.mod b/go.mod @@ -8,7 +8,6 @@ require ( github.com/kataras/i18n v0.0.8 github.com/schanzen/taler-go v1.1.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e - gnunet v0.1.27 gopkg.in/ini.v1 v1.67.0 gorm.io/driver/postgres v1.5.11 gorm.io/driver/sqlite v1.5.7 @@ -17,7 +16,6 @@ require ( require ( github.com/BurntSushi/toml v1.5.0 // indirect - github.com/bfix/gospel v1.2.31 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgx/v5 v5.5.5 // indirect @@ -33,5 +31,3 @@ require ( golang.org/x/text v0.22.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -replace gnunet v0.1.27 => ./third_party/gnunet-go/src/gnunet diff --git a/go.sum b/go.sum @@ -1,7 +1,5 @@ github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/bfix/gospel v1.2.31 h1:14ymN2Fo7aTYiJ0HEhL0jMg+ofe97HwTHvkntj0DutE= -github.com/bfix/gospel v1.2.31/go.mod h1:s1zIBLFzCWoz2khLuNgDMtzzXtReGmyWVyGTO7ELkHg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/gertd/go-pluralize v0.2.1 h1:M3uASbVjMnTsPb0PNqg+E/24Vwigyo/tvyMTtAlLgiA= diff --git a/internal/util/helper.go b/internal/util/helper.go @@ -21,8 +21,9 @@ package util import ( "crypto/sha512" "crypto/rand" - gnunetutil "gnunet/util" "time" + "errors" + "strings" talerutil "github.com/schanzen/taler-go/pkg/util" ) @@ -32,7 +33,7 @@ func GenerateSolution(targetUriEncoded string, challenge string) string { h := sha512.New() h.Write([]byte(challenge)) h.Write([]byte(targetUriEncoded)) - return gnunetutil.EncodeBinaryToString(h.Sum(nil)) + return Base32CrockfordEncode(h.Sum(nil)) } // Generates random reference token used in the validation flow. @@ -42,7 +43,7 @@ func GenerateChallenge(bytes int) string { if err != nil { panic(err) } - return gnunetutil.EncodeBinaryToString(randBytes) + return Base32CrockfordEncode(randBytes) } // Check if this is a non-zero, positive amount @@ -73,3 +74,106 @@ func CalculateCost(sliceCostAmount string, fixedCostAmount string, howLong time. } return sum, nil } + +//------------------------------------------------------------------------ +// Base32 conversion between binary data and string representation +//------------------------------------------------------------------------ +// +// A binary array of size m is viewed as a consecutive stream of bits +// from left to right. Bytes are ordered with ascending address, while +// bits (in a byte) are ordered MSB to LSB. + +// For encoding the stream is partitioned into 5-bit chunks; the last chunk +// is right-padded with 0's if 8*m is not divisible by 5. Each chunk (value +// between 0 and 31) is encoded into a character; the mapping for encoding +// is the same as in [https://www.crockford.com/wrmg/base32.html]. +// +// For decoding each character is converted to a 5-bit chunk based on the +// encoder mapping (with one addition: the character 'U' maps to the value +// 27). The chunks are concatenated to produce the bit stream to be stored +// in the output array. + +// character set used for encoding/decoding +const xlate = "0123456789ABCDEFGHJKMNPQRSTVWXYZ" + +var ( + // ErrInvalidEncoding signals an invalid encoding + ErrInvalidEncoding = errors.New("invalid encoding") + // ErrBufferTooSmall signalsa too small buffer for decoding + ErrBufferTooSmall = errors.New("buffer to small") +) + +// EncodeBinaryToString encodes a byte array into a string. +func Base32CrockfordEncode(data []byte) string { + size, pos, bits, n := len(data), 0, 0, 0 + out := "" + for { + if n < 5 { + if pos < size { + bits = (bits << 8) | (int(data[pos]) & 0xFF) + pos++ + n += 8 + } else if n > 0 { + bits <<= uint(5 - n) + n = 5 + } else { + break + } + } + out += string(xlate[(bits>>uint(n-5))&0x1F]) + n -= 5 + } + return out +} + +// Base32CrockfordDecode decodes a string into a byte array. +// The function expects the size of the output buffer to be sepcified as an +// argument ('num'); the function returns an error if the buffer is overrun +// or if an invalid character is found in the encoded string. If the decoded +// bit stream is smaller than the output buffer, it is padded with 0's. +func Base32CrockfordDecode(s string, num int) ([]byte, error) { + size := len(s) + out := make([]byte, num) + rpos, wpos, n, bits := 0, 0, 0, 0 + for { + if n < 8 { + if rpos < size { + c := rune(s[rpos]) + rpos++ + v := strings.IndexRune(xlate, c) + if v == -1 { + switch c { + case 'O': + v = 0 + case 'I', 'L': + v = 1 + case 'U': + v = 27 + default: + return nil, ErrInvalidEncoding + } + } + bits = (bits << 5) | (v & 0x1F) + n += 5 + } else { + if wpos < num { + out[wpos] = byte(bits & ((1 << uint(n+1)) - 1)) + wpos++ + for i := wpos; i < num; i++ { + out[i] = 0 + } + } + break + } + } else { + if wpos < num { + out[wpos] = byte((bits >> uint(n-8)) & 0xFF) + wpos++ + n -= 8 + } else { + return nil, ErrBufferTooSmall + } + } + } + return out, nil +} diff --git a/pkg/rest/taldir.go b/pkg/rest/taldir.go @@ -39,8 +39,6 @@ import ( "strings" "time" - gnunetutil "gnunet/util" - "github.com/gertd/go-pluralize" "github.com/gorilla/mux" "github.com/kataras/i18n" @@ -381,7 +379,7 @@ func saltHAddress(hAddress string, salt string) string { h := sha512.New() h.Write([]byte(hAddress)) h.Write([]byte(salt)) - return gnunetutil.EncodeBinaryToString(h.Sum(nil)) + return util.Base32CrockfordEncode(h.Sum(nil)) } // Called by the registrant to validate the registration request. The reference ID was @@ -524,7 +522,7 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request) { // exists. h := sha512.New() h.Write([]byte(req.Address)) - hAddress := gnunetutil.EncodeBinaryToString(h.Sum(nil)) + hAddress := util.Base32CrockfordEncode(h.Sum(nil)) validation.HAddress = hAddress hsAddress := saltHAddress(validation.HAddress, t.Salt) err = t.Db.First(&entry, "hs_address = ?", hsAddress).Error @@ -695,7 +693,7 @@ func (t *Taldir) validationPage(w http.ResponseWriter, r *http.Request) { h := sha512.New() h.Write([]byte(address)) - expectedHAddress := gnunetutil.EncodeBinaryToString(h.Sum(nil)) + expectedHAddress := util.Base32CrockfordEncode(h.Sum(nil)) if expectedHAddress != validation.HAddress { log.Println("Address does not match challenge!") @@ -850,7 +848,7 @@ func (t *Taldir) methodLookupResultPage(w http.ResponseWriter, r *http.Request) return } else { hAddressBin := sha512.Sum512([]byte(r.URL.Query().Get("address"))) - hAddress := gnunetutil.EncodeBinaryToString(hAddressBin[:]) + hAddress := util.Base32CrockfordEncode(hAddressBin[:]) hsAddress := saltHAddress(hAddress, t.Salt) err = t.Db.First(&entry, "hs_address = ?", hsAddress).Error if err != nil { @@ -979,7 +977,7 @@ func (t *Taldir) Initialize(cfg TaldirConfig) { continue } vname := strings.TrimPrefix(sec.Name(), "taldir-validator-") - vlandingPageTplFile := sec.Key("registration_page").MustString(t.getFileName("web/templates/landing_"+vname+".html")) + vlandingPageTplFile := sec.Key("registration_page").MustString(t.getFileName("web/templates/landing_" + vname + ".html")) vlandingPageTpl, err := template.ParseFiles(vlandingPageTplFile, navTplFile, footerTplFile) if err != nil { log.Printf("`%s` template not found, disabling validator `%s`.\n", vlandingPageTplFile, vname) diff --git a/third_party/gnunet-go b/third_party/gnunet-go @@ -1 +0,0 @@ -Subproject commit f425c2aeef06d1a6105678c8b058bdde65a26e78