mirror of
https://github.com/arnaucube/blockchainIDsystem.git
synced 2026-02-06 18:46:42 +01:00
Implemented signup and login users with JWT and MongoDB connection. Added runTmuxTextPeers.sh to deploy the different peers and servers in a unique console
This commit is contained in:
22
README.md
22
README.md
@@ -24,17 +24,17 @@ There are different types of nodes:
|
||||
|
||||
#### Step by step process
|
||||
1. Once all the nodes of the network are running, a new user can connect to the server-ID-signer.
|
||||
- The user registers a non anonymous user (using email, phone, password, etc), and performs the login with that user
|
||||
- The user, locally, generates a RSA key pair (private key & public key)
|
||||
- The user blinds his Public-Key with the server-ID-signer Public-Key
|
||||
- The user's Public-Key blinded, is sent to the server-ID-signer
|
||||
- The server-ID-signer Blind Signs the Public-Key blinded from the user, and returns it to the user
|
||||
- The user unblinds the Public-Key signed by the server-ID-signer, and now has the Public-Key Blind Signed by the server-ID-signer
|
||||
- The user sends the Public-Key blind signed to the p2p network
|
||||
- The peers verify that the Public-Key Blind Signed is correctly signed by the server-ID-signer, if it is, they add the Public-Key to the Blockchain, inside a new block
|
||||
- Then, when the user wants to login into a platform, just needs to put his Public-Key
|
||||
- The platform goes to the Blockchain, to check if this Public-Key is registered in the blockchain
|
||||
- The platform sends a message encrypted with the user Public-Key, and the user returns the message decrypted with the Private-Key, to verify that is the owner of that Public-Key
|
||||
2. The user registers a non anonymous user (using email, phone, password, etc), and performs the login with that user
|
||||
3. The user, locally, generates a RSA key pair (private key & public key)
|
||||
4. The user blinds his Public-Key with the server-ID-signer Public-Key
|
||||
5. The user's Public-Key blinded, is sent to the server-ID-signer
|
||||
6. The server-ID-signer Blind Signs the Public-Key blinded from the user, and returns it to the user
|
||||
7. The user unblinds the Public-Key signed by the server-ID-signer, and now has the Public-Key Blind Signed by the server-ID-signer
|
||||
8. The user sends the Public-Key blind signed to the p2p network
|
||||
9. The peers verify that the Public-Key Blind Signed is correctly signed by the server-ID-signer, if it is, they add the Public-Key to the Blockchain, inside a new block
|
||||
10. Then, when the user wants to login into a platform, just needs to put his Public-Key
|
||||
11. The platform goes to the Blockchain, to check if this Public-Key is registered in the blockchain
|
||||
12. The platform sends a message encrypted with the user Public-Key, and the user returns the message decrypted with the Private-Key, to verify that is the owner of that Public-Key
|
||||
|
||||
|
||||
##### RSA encryption system
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"genesisblock":"YKWAWY6GM5xrLhYrfi6hAmPmsECUH83n7xVcgaguLF4=","lastupdate":"0001-01-01T00:00:00Z","blocks":[{"hash":"YKWAWY6GM5xrLhYrfi6hAmPmsECUH83n7xVcgaguLF4=","height":0,"date":"2017-11-29T10:42:55.112675187+01:00","previoushash":"","nexthash":"cSN48a9BwgJQZdz2NwBRPJqCtC4Qtv-l-RYeGl9eBZs=","data":[{"address":"firstaddress"}],"emitter":"VOnL-15rFsUiCnRoyGFksKvWKcwNBRz5iarRem0Ilvo="},{"hash":"cSN48a9BwgJQZdz2NwBRPJqCtC4Qtv-l-RYeGl9eBZs=","height":1,"date":"2017-11-29T23:07:43.169204719+01:00","previoushash":"YKWAWY6GM5xrLhYrfi6hAmPmsECUH83n7xVcgaguLF4=","nexthash":"","data":[{"address":"firstaddress"}],"emitter":"VOnL-15rFsUiCnRoyGFksKvWKcwNBRz5iarRem0Ilvo="}]}
|
||||
{"genesisblock":"YKWAWY6GM5xrLhYrfi6hAmPmsECUH83n7xVcgaguLF4=","lastupdate":"0001-01-01T00:00:00Z","blocks":[{"hash":"YKWAWY6GM5xrLhYrfi6hAmPmsECUH83n7xVcgaguLF4=","height":0,"date":"2017-11-29T10:42:55.112675187+01:00","previoushash":"","nexthash":"cSN48a9BwgJQZdz2NwBRPJqCtC4Qtv-l-RYeGl9eBZs=","data":[{"address":"firstaddress"}],"emitter":"VOnL-15rFsUiCnRoyGFksKvWKcwNBRz5iarRem0Ilvo="},{"hash":"cSN48a9BwgJQZdz2NwBRPJqCtC4Qtv-l-RYeGl9eBZs=","height":1,"date":"2017-11-29T23:07:43.169204719+01:00","previoushash":"YKWAWY6GM5xrLhYrfi6hAmPmsECUH83n7xVcgaguLF4=","nexthash":"Ql0MH8WVaCOXzRWmR5xUyAQXaQ5Ovt6PoN3HrkHmYmk=","data":[{"address":"firstaddress"}],"emitter":"VOnL-15rFsUiCnRoyGFksKvWKcwNBRz5iarRem0Ilvo="},{"hash":"Ql0MH8WVaCOXzRWmR5xUyAQXaQ5Ovt6PoN3HrkHmYmk=","height":2,"date":"2017-12-26T14:38:41.446523607+01:00","previoushash":"cSN48a9BwgJQZdz2NwBRPJqCtC4Qtv-l-RYeGl9eBZs=","nexthash":"64bzp4j5jJjCcvKYcsytJOKD5dFyMHUjtNY1S5TD8Sk=","data":[{"address":"firstaddress"}],"emitter":"VOnL-15rFsUiCnRoyGFksKvWKcwNBRz5iarRem0Ilvo="},{"hash":"64bzp4j5jJjCcvKYcsytJOKD5dFyMHUjtNY1S5TD8Sk=","height":3,"date":"2017-12-26T18:05:05.541862456+01:00","previoushash":"Ql0MH8WVaCOXzRWmR5xUyAQXaQ5Ovt6PoN3HrkHmYmk=","nexthash":"N-w5F0pRA0kpZx7JDS3RPBedUSq1Kyk13Pc1guhY7Ws=","data":[{"address":"firstaddress"}],"emitter":"VOnL-15rFsUiCnRoyGFksKvWKcwNBRz5iarRem0Ilvo="},{"hash":"N-w5F0pRA0kpZx7JDS3RPBedUSq1Kyk13Pc1guhY7Ws=","height":4,"date":"2017-12-26T18:06:13.953399725+01:00","previoushash":"64bzp4j5jJjCcvKYcsytJOKD5dFyMHUjtNY1S5TD8Sk=","nexthash":"45Otq5P8WR97T4SxvaFk_0icNdUcIzO-mTjn6wrxJd4=","data":[{"address":"firstaddress"}],"emitter":"VOnL-15rFsUiCnRoyGFksKvWKcwNBRz5iarRem0Ilvo="},{"hash":"45Otq5P8WR97T4SxvaFk_0icNdUcIzO-mTjn6wrxJd4=","height":5,"date":"2017-12-26T18:06:57.93092362+01:00","previoushash":"N-w5F0pRA0kpZx7JDS3RPBedUSq1Kyk13Pc1guhY7Ws=","nexthash":"","data":[{"address":"firstaddress"}],"emitter":"VOnL-15rFsUiCnRoyGFksKvWKcwNBRz5iarRem0Ilvo="}]}
|
||||
18
runTmuxTestPeers.sh
Normal file
18
runTmuxTestPeers.sh
Normal file
@@ -0,0 +1,18 @@
|
||||
SESSION='peersTest'
|
||||
|
||||
tmux new-session -d -s $SESSION
|
||||
tmux split-window -d -t 0 -v
|
||||
tmux split-window -d -t 0 -h
|
||||
tmux split-window -d -t 0 -v
|
||||
tmux split-window -d -t 2 -v
|
||||
|
||||
tmux send-keys -t 0 'cd peer && go run *.go server 3001 3002' enter
|
||||
sleep 2
|
||||
tmux send-keys -t 1 "curl -X POST http://127.0.0.1:3002/register -d '{\"address\": \"firstaddress\"}'" enter
|
||||
sleep 1
|
||||
tmux send-keys -t 1 'cd peer && go run *.go client 3003 3004' enter
|
||||
tmux send-keys -t 2 'cd peer && go run *.go client 3005 3006' enter
|
||||
tmux send-keys -t 3 'cd peer && go run *.go client 3007 3008' enter
|
||||
tmux send-keys -t 4 'cd serverCA && go run *.go' enter
|
||||
|
||||
tmux attach
|
||||
@@ -68,7 +68,9 @@ func reconstructBlockchainFromBlock(urlAPI string, h string) {
|
||||
var err error
|
||||
|
||||
block, err = blockchain.getBlockByHash(h)
|
||||
check(err)
|
||||
if err != nil {
|
||||
fmt.Println("reconstructBlockFromBlock: block with " + h + " not found. Getting genesis block")
|
||||
}
|
||||
|
||||
if h == "" {
|
||||
//no genesis block yet
|
||||
|
||||
32
serverCA/blockchainRESTFunctions.go
Normal file
32
serverCA/blockchainRESTFunctions.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Address struct {
|
||||
Address string `json:"address"` //the pubK of the user, to perform logins
|
||||
}
|
||||
|
||||
func Index(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, "CA")
|
||||
}
|
||||
func GetPeers(w http.ResponseWriter, r *http.Request) {
|
||||
getPeers()
|
||||
|
||||
jResp, err := json.Marshal(peersList)
|
||||
check(err)
|
||||
fmt.Fprintln(w, string(jResp))
|
||||
}
|
||||
|
||||
func GetBlockchain(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Print("aaaaa: ")
|
||||
fmt.Println(blockchain.Blocks[len(blockchain.Blocks)-1].Hash)
|
||||
reconstructBlockchainFromBlock("http://"+config.IP+":"+config.ServerRESTPort, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)
|
||||
|
||||
jResp, err := json.Marshal(blockchain)
|
||||
check(err)
|
||||
fmt.Fprintln(w, string(jResp))
|
||||
}
|
||||
@@ -4,5 +4,9 @@
|
||||
"serverip": "127.0.0.1",
|
||||
"serverport": "3000",
|
||||
"serverrestport": "3002",
|
||||
"webserverport": "3080"
|
||||
"webserverport": "3080",
|
||||
"mongodb": {
|
||||
"ip": "127.0.0.1:27017",
|
||||
"database": "serverCA"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
mgo "gopkg.in/mgo.v2"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/gorilla/handlers"
|
||||
)
|
||||
@@ -26,14 +28,22 @@ type PeersList struct {
|
||||
|
||||
var peersList PeersList
|
||||
|
||||
var userCollection *mgo.Collection
|
||||
|
||||
func main() {
|
||||
color.Blue("Starting CA")
|
||||
|
||||
//read configuration file
|
||||
readConfig("config.json")
|
||||
|
||||
reconstructBlockchainFromBlock("http://"+config.IP+":"+config.ServerRESTPort, "")
|
||||
|
||||
initializeToken()
|
||||
|
||||
//mongodb
|
||||
session, err := getSession()
|
||||
check(err)
|
||||
userCollection = getCollection(session, "users")
|
||||
|
||||
//run thw webserver
|
||||
go webserver()
|
||||
|
||||
|
||||
26
serverCA/mongoOperations.go
Executable file
26
serverCA/mongoOperations.go
Executable file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
mgo "gopkg.in/mgo.v2"
|
||||
)
|
||||
|
||||
func getSession() (*mgo.Session, error) {
|
||||
session, err := mgo.Dial("mongodb://" + config.Mongodb.IP)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
//defer session.Close()
|
||||
|
||||
// Optional. Switch the session to a monotonic behavior.
|
||||
session.SetMode(mgo.Monotonic, true)
|
||||
|
||||
// Optional. Switch the session to a monotonic behavior.
|
||||
session.SetMode(mgo.Monotonic, true)
|
||||
|
||||
return session, err
|
||||
}
|
||||
func getCollection(session *mgo.Session, collection string) *mgo.Collection {
|
||||
|
||||
c := session.DB(config.Mongodb.Database).C(collection)
|
||||
return c
|
||||
}
|
||||
@@ -13,6 +13,11 @@ type Config struct {
|
||||
ServerPort string `json:"serverport"`
|
||||
ServerRESTPort string `json:"serverrestport"`
|
||||
WebServerPort string `json:"webserverport"`
|
||||
Mongodb MongoConfig `json:"mongodb"`
|
||||
}
|
||||
type MongoConfig struct {
|
||||
IP string `json:"ip"`
|
||||
Database string `json:"database"`
|
||||
}
|
||||
|
||||
var config Config
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Routes []Route
|
||||
|
||||
var routes = Routes{
|
||||
@@ -27,29 +21,35 @@ var routes = Routes{
|
||||
"/blockchain",
|
||||
GetBlockchain,
|
||||
},
|
||||
}
|
||||
/*
|
||||
POST /signup
|
||||
POST /loginuser
|
||||
POST /blindsign
|
||||
POST /verifysign
|
||||
|
||||
type Address struct {
|
||||
Address string `json:"address"` //the pubK of the user, to perform logins
|
||||
}
|
||||
|
||||
func Index(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, "CA")
|
||||
}
|
||||
func GetPeers(w http.ResponseWriter, r *http.Request) {
|
||||
getPeers()
|
||||
|
||||
jResp, err := json.Marshal(peersList)
|
||||
check(err)
|
||||
fmt.Fprintln(w, string(jResp))
|
||||
}
|
||||
|
||||
func GetBlockchain(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Print("aaaaa: ")
|
||||
fmt.Println(blockchain.Blocks[len(blockchain.Blocks)-1].Hash)
|
||||
reconstructBlockchainFromBlock("http://"+config.IP+":"+config.ServerRESTPort, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)
|
||||
|
||||
jResp, err := json.Marshal(blockchain)
|
||||
check(err)
|
||||
fmt.Fprintln(w, string(jResp))
|
||||
*/
|
||||
Route{
|
||||
"Signup",
|
||||
"POST",
|
||||
"/signup",
|
||||
Signup,
|
||||
},
|
||||
Route{
|
||||
"Login",
|
||||
"POST",
|
||||
"/login",
|
||||
Login,
|
||||
},
|
||||
Route{
|
||||
"BlindSign",
|
||||
"POST",
|
||||
"/blindsign",
|
||||
BlindSign,
|
||||
},
|
||||
Route{
|
||||
"VerifySign",
|
||||
"POST",
|
||||
"/verifysign",
|
||||
VerifySign,
|
||||
},
|
||||
}
|
||||
|
||||
3
serverCA/testUser.sh
Normal file
3
serverCA/testUser.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
curl -X POST http://127.0.0.1:3030/signup -d '{"email": "user1@e.com", "password": "user1"}'
|
||||
|
||||
curl -X POST http://127.0.0.1:3030/login -d '{"email": "user1@e.com", "password": "user1"}'
|
||||
49
serverCA/tokens.go
Normal file
49
serverCA/tokens.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
const (
|
||||
signingKey = "this is the secret signing key"
|
||||
)
|
||||
|
||||
var createdToken string
|
||||
|
||||
func initializeToken() {
|
||||
var err error
|
||||
createdToken, err = newToken()
|
||||
if err != nil {
|
||||
fmt.Println("Creating token failed")
|
||||
}
|
||||
}
|
||||
|
||||
func newToken() (string, error) {
|
||||
signingKeyB := []byte(signingKey)
|
||||
// Create the token
|
||||
token := jwt.New(jwt.SigningMethodHS256)
|
||||
// Set some claims
|
||||
claims := make(jwt.MapClaims)
|
||||
claims["foo"] = "bar"
|
||||
claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
|
||||
token.Claims = claims
|
||||
|
||||
// Sign and get the complete encoded token as a string
|
||||
tokenString, err := token.SignedString(signingKeyB)
|
||||
return tokenString, err
|
||||
}
|
||||
|
||||
func parseToken(myToken string, myKey string) {
|
||||
token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(myKey), nil
|
||||
})
|
||||
|
||||
if err == nil && token.Valid {
|
||||
fmt.Println("Your token is valid. I like your style.")
|
||||
} else {
|
||||
fmt.Println("This token is terrible! I cannot accept this.")
|
||||
}
|
||||
}
|
||||
127
serverCA/userRESTFunctions.go
Normal file
127
serverCA/userRESTFunctions.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Id bson.ObjectId `json:"id" bson:"_id,omitempty"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func Signup(w http.ResponseWriter, r *http.Request) {
|
||||
//ipFilter(w, r)
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
var user User
|
||||
err := decoder.Decode(&user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
fmt.Print("user signup: ")
|
||||
fmt.Println(user)
|
||||
|
||||
//save the new project to mongodb
|
||||
rUser := User{}
|
||||
err = userCollection.Find(bson.M{"email": user.Email}).One(&rUser)
|
||||
if err != nil {
|
||||
//user not exists
|
||||
err = userCollection.Insert(user) //TODO find a way to get the object result when inserting in one line, without need of the two mgo petitions
|
||||
err = userCollection.Find(bson.M{"email": user.Email}).One(&user)
|
||||
} else {
|
||||
//user exists
|
||||
fmt.Fprintln(w, "User already registered")
|
||||
return
|
||||
}
|
||||
|
||||
jResp, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Fprintln(w, string(jResp))
|
||||
}
|
||||
|
||||
func Login(w http.ResponseWriter, r *http.Request) {
|
||||
//ipFilter(w, r)
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
var user User
|
||||
err := decoder.Decode(&user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
fmt.Print("user login: ")
|
||||
fmt.Println(user)
|
||||
token, err := newToken()
|
||||
check(err)
|
||||
user.Token = token
|
||||
|
||||
//save the new project to mongodb
|
||||
rUser := User{}
|
||||
err = userCollection.Find(bson.M{"email": user.Email}).One(&rUser)
|
||||
if err != nil {
|
||||
} else {
|
||||
//user exists, update with the token
|
||||
err = userCollection.Update(bson.M{"_id": rUser.Id}, user)
|
||||
check(err)
|
||||
}
|
||||
//generate the token
|
||||
//add the token to the user
|
||||
//save the user with the new token
|
||||
|
||||
jResp, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Fprintln(w, string(jResp))
|
||||
}
|
||||
|
||||
type Sign struct {
|
||||
M string `json:"m"`
|
||||
C string `json:"c"`
|
||||
}
|
||||
|
||||
func BlindSign(w http.ResponseWriter, r *http.Request) {
|
||||
//ipFilter(w, r)
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
var user User
|
||||
err := decoder.Decode(&user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
jResp, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Fprintln(w, string(jResp))
|
||||
}
|
||||
func VerifySign(w http.ResponseWriter, r *http.Request) {
|
||||
//ipFilter(w, r)
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
var user User
|
||||
err := decoder.Decode(&user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
jResp, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Fprintln(w, string(jResp))
|
||||
}
|
||||
Reference in New Issue
Block a user