gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taldir] branch master updated: forgot to add files; update base32


From: gnunet
Subject: [taler-taldir] branch master updated: forgot to add files; update base32; fix solution calculation
Date: Wed, 06 Jul 2022 14:20:17 +0200

This is an automated email from the git hooks/post-receive script.

martin-schanzenbach pushed a commit to branch master
in repository taldir.

The following commit(s) were added to refs/heads/master by this push:
     new f01dddf  forgot to add files; update base32; fix solution calculation
f01dddf is described below

commit f01dddf4da0689dc612b6a8b7cda332e0d2a3568
Author: Martin Schanzenbach <schanzen@gnunet.org>
AuthorDate: Wed Jul 6 14:20:14 2022 +0200

    forgot to add files; update base32; fix solution calculation
---
 taldir.go                         |  66 +++++++++++++++++---
 templates/validation_landing.html |  17 +++++
 test.sh                           |  12 ++--
 util/base32.go                    | 127 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 207 insertions(+), 15 deletions(-)

diff --git a/taldir.go b/taldir.go
index d8b19e0..38f1608 100644
--- a/taldir.go
+++ b/taldir.go
@@ -3,16 +3,18 @@ package main
 import (
   "os"
   "os/exec"
+  "bufio"
   "time"
   "fmt"
   "log"
+  "flag"
   "net/http"
   "html/template"
   "encoding/json"
   "github.com/gorilla/mux"
   "gorm.io/gorm"
-  "encoding/base32"
   "encoding/base64"
+  "taler.net/taldir/util"
   "math/rand"
   "crypto/sha512"
   "gorm.io/driver/postgres"
@@ -101,7 +103,7 @@ type Validation struct {
   Method string `json:"method"`
   Duration int64 `json:"duration"`
   Inbox string `json:"inbox_url"`
-  Solution string `json:"solution"`
+  Code string `json:"activation_code"`
   PublicKey string `json:"public_key"`
 }
 
@@ -184,11 +186,10 @@ func saltHAddress(h_address string) string {
   if "" == salt {
     salt = cfg.Section("taldir").Key("salt").MustString("ChangeMe")
   }
-  fmt.Println("Using salt " + salt)
   h := sha512.New()
   h.Write([]byte(h_address))
   h.Write([]byte(salt))
-  return base32.StdEncoding.EncodeToString(h.Sum(nil))
+  return util.EncodeBinaryToString(h.Sum(nil))
 }
 
 // Called by the registrant to validate the registration request. The 
reference ID was
@@ -217,7 +218,8 @@ func validationRequest(w http.ResponseWriter, r 
*http.Request){
     w.WriteHeader(http.StatusNotFound)
     return
   }
-  if confirm.Solution != validation.Solution {
+  expectedSolution := generateSolution(validation.PublicKey, validation.Code)
+  if confirm.Solution != expectedSolution {
     // FIXME how TF do we rate limit here??
     w.WriteHeader(http.StatusForbidden)
     return
@@ -237,7 +239,6 @@ func validationRequest(w http.ResponseWriter, r 
*http.Request){
   err = db.First(&entry, "hs_address = ?", entry.HsAddress).Error
   if err == nil {
     db.Save(&entry)
-    return
   } else {
     err = db.Create(&entry).Error
     if err != nil {
@@ -256,7 +257,7 @@ func generateToken() string {
   if err != nil {
     panic(err)
   }
-  return base32.StdEncoding.EncodeToString(randBytes)
+  return util.EncodeBinaryToString(randBytes)
 }
 
 func registerRequest(w http.ResponseWriter, r *http.Request){
@@ -289,7 +290,7 @@ func registerRequest(w http.ResponseWriter, r 
*http.Request){
   }
   h := sha512.New()
   h.Write([]byte(req.Address))
-  validation.HAddress = base32.StdEncoding.EncodeToString(h.Sum(nil))
+  validation.HAddress = util.EncodeBinaryToString(h.Sum(nil))
   // We first try if there is already an entry for this address which
   // is still valid and the duration is not extended.
   hs_address := saltHAddress(validation.HAddress)
@@ -325,7 +326,7 @@ func registerRequest(w http.ResponseWriter, r 
*http.Request){
     w.WriteHeader(202)
     return
   } else {
-    validation.Solution = generateToken()
+    validation.Code = generateToken()
     validation.Inbox = req.Inbox
     validation.Duration = req.Duration
     validation.PublicKey = req.PublicKey
@@ -346,7 +347,7 @@ func registerRequest(w http.ResponseWriter, r 
*http.Request){
     return
   }
   command := cfg.Section("taldir-" + vars["method"]).Key("command").String()
-  out, err := exec.Command(command, req.Address, validation.Solution).Output()
+  out, err := exec.Command(command, req.Address, validation.Code).Output()
   if err != nil {
     log.Fatal(err)
     db.Delete(&validation)
@@ -403,6 +404,20 @@ func validationPage(w http.ResponseWriter, r 
*http.Request) {
   return
 }
 
+// Generates a solution from a code and pubkey
+func generateSolution(pubkeyEncoded string, code string) string {
+  pubkey, err := util.DecodeStringToBinary(pubkeyEncoded, 36)
+  if err != nil {
+    fmt.Println("error decoding pubkey:", err)
+    return ""
+  }
+  h := sha512.New()
+  h.Write([]byte(code))
+  h.Write(pubkey)
+  return util.EncodeBinaryToString(h.Sum(nil))
+}
+
+
 func handleRequests() {
   myRouter := mux.NewRouter().StrictSlash(true)
 
@@ -435,6 +450,19 @@ func main() {
   if cfg.Section("taldir").Key("production").MustBool(false) {
     fmt.Println("Production mode enabled") 
   }
+  var solveFlag = flag.Bool("s", false, "Provide a solution for the 
code/pubkey")
+  var codeFlag = flag.String("c", "", "Activation code")
+  var pubkeyFlag = flag.String("p", "", "Public key")
+  var dropFlag = flag.Bool("D", false, "Drop all data in table (DANGEROUS!)")
+  flag.Parse()
+  if *solveFlag {
+    if len(*codeFlag) == 0 || len(*pubkeyFlag) == 0 {
+      fmt.Println("You need to provide an activation code and a public key to 
generate a solution")
+      os.Exit(1)
+    }
+    fmt.Println(generateSolution(*pubkeyFlag, *codeFlag))
+    os.Exit(0)
+  }
   validators = make(map[string]bool)
   for _, a := range 
strings.Split(cfg.Section("taldir").Key("validators").String(), " ") {
     validators[a] = true
@@ -456,6 +484,24 @@ func main() {
   if err := db.AutoMigrate(&Validation{}); err != nil {
     panic(err)
   }
+  if *dropFlag {
+    fmt.Println("Really delete all data in database? [y/N]:")
+    reader := bufio.NewReader(os.Stdin)
+    char, _, err := reader.ReadRune()
+
+    if err == nil {
+      fmt.Println(char)
+      if char == 'y' {
+        fmt.Println("Deleting entries...")
+        db.Where("1 = 1").Delete(&Entry{})
+        fmt.Println("Deleting validations...")
+        db.Where("1 = 1").Delete(&Validation{})
+      }
+      os.Exit(0)
+    }
+    os.Exit(1)
+  }
+
   validationTpl, err = template.ParseFiles("templates/validation_landing.html")
   if err != nil {
     fmt.Println(err)
diff --git a/templates/validation_landing.html 
b/templates/validation_landing.html
new file mode 100644
index 0000000..ccaa770
--- /dev/null
+++ b/templates/validation_landing.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <!-- Required meta tags -->
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1, 
shrink-to-fit=no">
+        <title>Validation Landing Page</title>
+    </head>
+    <body>
+        <div class="container">
+            <h1>Scan this QR code with your Taler Wallet to complete your 
registration.</h1>
+            <a href="{{.WalletLink}}">
+              <img src="{{.QRCode}}"/>
+            </a>
+        </div>
+    </body>
+</html>
diff --git a/test.sh b/test.sh
index 411fcba..413b47c 100755
--- a/test.sh
+++ b/test.sh
@@ -1,13 +1,15 @@
 #!/bin/bash
 # New request
-curl -v localhost:11000/register/test --data '{"address": "abc@test", 
"public_key": "pkey", "inbox_url": "myinbox@xyz", "duration": 23}'
+PUBKEY="000G006XE97PTWV3B7AJNCRQZA6BF26HPV3XZ07293FMY7KD4181946A90"
+curl -v localhost:11000/register/test --data "{\"address\": \"abc@test\", 
\"public_key\": \"${PUBKEY}\", \"inbox_url\": \"myinbox@xyz\", \"duration\": 
23}"
 # Read validation code from tempfile
 CODE=`cat validation_code`
-H_ADDRESS=`echo -n abc@test | openssl dgst -binary -sha512 | base32 -w0`
+H_ADDRESS=`echo -n abc@test | openssl dgst -binary -sha512 | gnunet-base32`
 echo "Code: $CODE; Address: $H_ADDRESS"
 # Validate
-echo localhost:11000/register/$H_ADDRESS/$CODE
-exit
-curl -v localhost:11000/$H_ADDRESS --data "{\"solution\": \"${CODE}\"}"
+# echo localhost:11000/register/$H_ADDRESS/$CODE
+SOLUTION=$(./taldir -s -c ${CODE} -p ${PUBKEY})
+echo "Solution: $SOLUTION"
+curl -v localhost:11000/$H_ADDRESS --data "{\"solution\": \"${SOLUTION}\"}"
 # Get mapping
 curl -v localhost:11000/$H_ADDRESS
diff --git a/util/base32.go b/util/base32.go
new file mode 100644
index 0000000..f0b149a
--- /dev/null
+++ b/util/base32.go
@@ -0,0 +1,127 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
+package util
+
+import (
+       "errors"
+       "strings"
+)
+
+//------------------------------------------------------------------------
+// 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 EncodeBinaryToString(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
+}
+
+// DecodeStringToBinary 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 DecodeStringToBinary(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
+}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]