gnunet-svn
[Top][All Lists]
Advanced

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

[taler-taldir] branch master updated: Cleanup code. Hash identities


From: gnunet
Subject: [taler-taldir] branch master updated: Cleanup code. Hash identities
Date: Tue, 19 Apr 2022 14:34:36 +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 f5e140b  Cleanup code. Hash identities
f5e140b is described below

commit f5e140b41c1697f4b013dda1f1c1f7a3caec17fa
Author: Martin Schanzenbach <mschanzenbach@posteo.de>
AuthorDate: Tue Apr 19 14:34:20 2022 +0200

    Cleanup code. Hash identities
---
 config.json |   3 +-
 go.mod      |   1 +
 taldir.go   | 127 +++++++++++++++++++++++++++++++++++++++---------------------
 3 files changed, 85 insertions(+), 46 deletions(-)

diff --git a/config.json b/config.json
index 8b2d4bb..3c1f173 100644
--- a/config.json
+++ b/config.json
@@ -2,5 +2,6 @@
   "production": false,
   "db_backend": "sqlite",
   "validators": ["email","phone"],
-  "email_sender": "taldir@taler.net"
+  "email_sender": "taldir@taler.net",
+  "host": "https://taldir.net/";
 }
diff --git a/go.mod b/go.mod
index ca035d8..d4da52f 100644
--- a/go.mod
+++ b/go.mod
@@ -6,6 +6,7 @@ require (
        github.com/gorilla/mux v1.8.0 // indirect
        github.com/jinzhu/now v1.1.5 // indirect
        github.com/mattn/go-sqlite3 v1.14.12 // indirect
+       golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
        gorm.io/driver/sqlite v1.3.1 // indirect
        gorm.io/gorm v1.23.4 // indirect
 )
diff --git a/taldir.go b/taldir.go
index 2da283e..45d52fa 100644
--- a/taldir.go
+++ b/taldir.go
@@ -12,41 +12,51 @@ import (
   "encoding/base32"
   "math/rand"
   "net/smtp"
+  "golang.org/x/crypto/argon2"
+  "crypto/sha256"
 )
 
-type Validator interface {
-  TriggerValidation() string
-}
-
 type Configuration struct {
   Production    bool
   DbBackend     string `json:"db_backend"`
   Validators   []string
   EmailSender string `json:"email_sender"`
+  Salt string `json:"salt"`
+  Host string `json:"host"`
 }
 
+// A mappind entry from the identity key hash to a wallet key
+// The identity key hash is argon2(sha256(identity)) where identity is
+// one of the identity key types supported (e.g. email)
 type Entry struct {
   gorm.Model
-  IdentityKey string `json:"identity_key"`
-  IdentityKeyType string `json:"identity_key_type"`
+  IdentityKeyHash string `json:"identity_key_hash"`
   TalerWalletKey string `json:"taler_wallet_key"`
-  Status string `json:"status"`
 }
 
+// A validation is created when a registration for an entry is initiated.
+// The validation stores the identity key (sha256(identity)) the secret
+// validation reference. The validation reference is sent to the identity
+// depending on the out-of-band chennel defined through the identity key type.
 type Validation struct {
   gorm.Model
   IdentityKey string `json:"identity_key"`
-  IdentityKeyType string `json:"type"`
+  IdentityKeyType string `json:"identity_key_type"`
   ValidationReference string `json:"reference"`
+  TalerWalletKey string `json:"taler_wallet_key"`
 }
 
 
-var Entries []Entry
-
+// The main DB handle
 var db *gorm.DB
 
+// Our configuration from the config.json
 var config Configuration
 
+// Map of supported validators as defined in the configuration
+var validators map[string]bool
+
+// Send an email for email identities 
 func sendEmail(recipient string, ref Validation) {
 
   from := config.EmailSender
@@ -57,9 +67,9 @@ func sendEmail(recipient string, ref Validation) {
   smtpHost := "localhost"
   smtpPort := "587"
 
-  message := []byte("Please click here to validate your Taldir identity: " + 
ref.ValidationReference)
+  message := fmt.Sprintf("Please click here to validate your Taldir identity: 
%s%s", config.Host, ref.ValidationReference)
   
-  err := smtp.SendMail(smtpHost+":"+smtpPort, nil, from, to, message)
+  err := smtp.SendMail(smtpHost+":"+smtpPort, nil, from, to, []byte(message))
   if err != nil {
     fmt.Println(err)
     return
@@ -70,7 +80,8 @@ func sendEmail(recipient string, ref Validation) {
 func returnSingleEntry(w http.ResponseWriter, r *http.Request){
   vars := mux.Vars(r)
   var entry Entry
-  var err = db.First(&entry, "identity_key = ?", vars["identity_key"]).Error
+  identityKeyHash := hashIdentityKey(vars["identity_key"])
+  var err = db.First(&entry, "identity_key_hash = ?", identityKeyHash).Error
   if err == nil {
     w.Header().Set("Content-Type", "application/json")
     json.NewEncoder(w).Encode(entry)
@@ -79,23 +90,41 @@ func returnSingleEntry(w http.ResponseWriter, r 
*http.Request){
   w.WriteHeader(http.StatusNotFound)
 }
 
+func hashIdentityKey(idkey string) string {
+    salt := make([]byte, len(config.Salt))
+    return base32.StdEncoding.EncodeToString(argon2.IDKey([]byte(idkey), salt, 
1, 64*1024, 4, 32))
+}
+
 func validateSingleEntry(w http.ResponseWriter, r *http.Request){
   vars := mux.Vars(r)
   var entry Entry
-  var ref Validation
+  var validation Validation
   //TODO actually validate
-  var err = db.First(&ref, "validation_reference = ?", vars["reference"]).Error
+  var err = db.First(&validation, "validation_reference = ?", 
vars["reference"]).Error
   if err != nil {
     w.WriteHeader(http.StatusNotFound)
   }
-  err = db.First(&entry, "identity_key = ?", entry.IdentityKey).Error
+  err = db.First(&validation, "identity_key = ?", validation.IdentityKey).Error
   if err != nil {
     w.WriteHeader(http.StatusNotFound)
   }
-  err = db.Model(&entry).Update("status", "validated").Error
+  err = db.Delete(&validation).Error
   if err != nil {
     w.WriteHeader(http.StatusInternalServerError)
   }
+  entry.IdentityKeyHash = hashIdentityKey(validation.IdentityKey)
+  entry.TalerWalletKey = validation.TalerWalletKey
+  err = db.First(&entry, "identity_key_hash = ?", entry.IdentityKeyHash).Error
+  if err == nil {
+    w.WriteHeader(http.StatusConflict)
+    return
+  }
+  err = db.Create(&entry).Error
+  if err != nil {
+    w.WriteHeader(http.StatusInternalServerError)
+    return
+  }
+  w.WriteHeader(http.StatusCreated)
 }
 
 func generateToken() string {
@@ -107,45 +136,54 @@ func generateToken() string {
     return base32.StdEncoding.EncodeToString(randBytes)
 }
 
-func addSingleEntry(w http.ResponseWriter, r *http.Request){
-  var entry Entry
+func addPendingValidation(w http.ResponseWriter, r *http.Request){
+  vars := mux.Vars(r)
+  var validation Validation
   if r.Body == nil {
     http.Error(w, "No request body", 400)
     return
   }
-  err := json.NewDecoder(r.Body).Decode(&entry)
+  err := json.NewDecoder(r.Body).Decode(&validation)
   if err != nil {
     http.Error(w, err.Error(), 400)
     return
   }
-  ref := Validation{IdentityKey: entry.IdentityKey, ValidationReference: 
generateToken() }
-  fmt.Println("Got ID key:", entry.IdentityKey)
-  err = db.First(&entry, "identity_key = ?", entry.IdentityKey).Error
-  if err == nil {
-    w.WriteHeader(http.StatusConflict)
+  fmt.Println(validators)
+  fmt.Println(validation)
+  if !validators[validation.IdentityKeyType] {
+    http.Error(w, "Identity key type not supported.", 400)
     return
   }
-  entry.Status = "unvalidated"
-  err = db.Create(&entry).Error
-  if err != nil {
-    w.WriteHeader(http.StatusInternalServerError)
+  // TODO make sure sha256(vars["identity"]) == validation.IdentityKey
+  h := sha256.New()
+  h.Write([]byte(vars["identity"]))
+  identityKey := base32.StdEncoding.EncodeToString(h.Sum(nil))
+  if (identityKey != validation.IdentityKey) {
+    fmt.Printf("Identity key hash %s does not match identity %s\n", 
identityKey, validation.IdentityKey)
+    w.WriteHeader(http.StatusBadRequest)
+    return
+  }
+  validation.ValidationReference = generateToken()
+  fmt.Println("Got ID key:", validation.IdentityKey)
+  err = db.First(&validation, "identity_key = ?", validation.IdentityKey).Error
+  if err == nil {
+    w.WriteHeader(http.StatusConflict)
     return
   }
-  err = db.Create(&ref).Error
+  err = db.Create(&validation).Error
   if err != nil {
     w.WriteHeader(http.StatusInternalServerError)
     return
   }
-  fmt.Println("Validation reference created:", ref)
-  sendEmail(ref.IdentityKey, ref)
-  json.NewEncoder(w).Encode(entry)
+  fmt.Println("Pending validation created:", validation)
+  sendEmail(vars["identity"], validation)
 }
 
 func handleRequests() {
   myRouter := mux.NewRouter().StrictSlash(true)
-  myRouter.HandleFunc("/directory/{id}", returnSingleEntry).Methods("GET")
-  myRouter.HandleFunc("/validation/{reference}", 
validateSingleEntry).Methods("POST")
-  myRouter.HandleFunc("/directory/", addSingleEntry).Methods("POST")
+  myRouter.HandleFunc("/directory/{identity_key}", 
returnSingleEntry).Methods("GET")
+  myRouter.HandleFunc("/validation/{reference}", 
validateSingleEntry).Methods("GET")
+  myRouter.HandleFunc("/register/{identity}", 
addPendingValidation).Methods("POST")
   log.Fatal(http.ListenAndServe(":10000", myRouter))
 }
 
@@ -158,7 +196,14 @@ func main() {
   if err != nil {
     fmt.Println("error:", err)
   }
-  fmt.Println("Configuration:", config)
+  if config.Production {
+    fmt.Println("Production mode enabled") 
+  }
+  validators = make(map[string]bool)
+  fmt.Println("Enabled validators:", config.Validators)
+  for _, a := range config.Validators {
+    validators[a] = true
+  }
   _db, err := gorm.Open(sqlite.Open("./taldir.db"), &gorm.Config{})
   if err != nil {
     panic(err)
@@ -170,13 +215,5 @@ func main() {
   if err := db.AutoMigrate(&Validation{}); err != nil {
     panic(err)
   }
-  var entry Entry;
-  db.Create(&Entry{IdentityKey: "jdoe@example.com", IdentityKeyType: "email", 
TalerWalletKey: "OIU123"})
-  db.Create(&Entry{IdentityKey: "+12345678", IdentityKeyType: "phone", 
TalerWalletKey: "OIU123"})
   handleRequests()
-  db.First(&entry, "identity_key = ?", "jdoe@example.com")
-  db.Delete(&entry)
-  db.First(&entry, "identity_key = ?", "+12345678")
-  db.Delete(&entry)
-
 }

-- 
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]