[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.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-taldir] branch master updated: Cleanup code. Hash identities,
gnunet <=