From 08e3915994b8ed44b5baed70bfdf223729e1c48e Mon Sep 17 00:00:00 2001 From: arnaucode Date: Tue, 26 Dec 2017 18:52:09 +0100 Subject: [PATCH] Implemented signup and login users with JWT and MongoDB connection. Added runTmuxTextPeers.sh to deploy the different peers and servers in a unique console --- README.md | 22 ++-- peer/blockchain.data | 2 +- runTmuxTestPeers.sh | 18 ++++ runTestPeers.sh => runXtermTestPeers.sh | 0 serverCA/blockchain.go | 4 +- serverCA/blockchainRESTFunctions.go | 32 ++++++ serverCA/config.json | 6 +- serverCA/main.go | 12 ++- serverCA/mongoOperations.go | 26 +++++ serverCA/readConfig.go | 17 ++-- serverCA/restRoutes.go | 60 +++++------ serverCA/testUser.sh | 3 + serverCA/tokens.go | 49 +++++++++ serverCA/userRESTFunctions.go | 127 ++++++++++++++++++++++++ 14 files changed, 327 insertions(+), 51 deletions(-) create mode 100644 runTmuxTestPeers.sh rename runTestPeers.sh => runXtermTestPeers.sh (100%) create mode 100644 serverCA/blockchainRESTFunctions.go create mode 100755 serverCA/mongoOperations.go create mode 100644 serverCA/testUser.sh create mode 100644 serverCA/tokens.go create mode 100644 serverCA/userRESTFunctions.go diff --git a/README.md b/README.md index 5805451..ea2773f 100644 --- a/README.md +++ b/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 diff --git a/peer/blockchain.data b/peer/blockchain.data index 91461c2..59a2bea 100644 --- a/peer/blockchain.data +++ b/peer/blockchain.data @@ -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="}]} \ No newline at end of file +{"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="}]} \ No newline at end of file diff --git a/runTmuxTestPeers.sh b/runTmuxTestPeers.sh new file mode 100644 index 0000000..bdee0d0 --- /dev/null +++ b/runTmuxTestPeers.sh @@ -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 diff --git a/runTestPeers.sh b/runXtermTestPeers.sh similarity index 100% rename from runTestPeers.sh rename to runXtermTestPeers.sh diff --git a/serverCA/blockchain.go b/serverCA/blockchain.go index 9c96996..281bc28 100644 --- a/serverCA/blockchain.go +++ b/serverCA/blockchain.go @@ -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 diff --git a/serverCA/blockchainRESTFunctions.go b/serverCA/blockchainRESTFunctions.go new file mode 100644 index 0000000..33c3af1 --- /dev/null +++ b/serverCA/blockchainRESTFunctions.go @@ -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)) +} diff --git a/serverCA/config.json b/serverCA/config.json index 740f974..c46ba7c 100755 --- a/serverCA/config.json +++ b/serverCA/config.json @@ -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" + } } diff --git a/serverCA/main.go b/serverCA/main.go index 87dc40b..937e7df 100644 --- a/serverCA/main.go +++ b/serverCA/main.go @@ -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() diff --git a/serverCA/mongoOperations.go b/serverCA/mongoOperations.go new file mode 100755 index 0000000..4b21ca6 --- /dev/null +++ b/serverCA/mongoOperations.go @@ -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 +} diff --git a/serverCA/readConfig.go b/serverCA/readConfig.go index 8856597..399d711 100755 --- a/serverCA/readConfig.go +++ b/serverCA/readConfig.go @@ -7,12 +7,17 @@ import ( //Config reads the config type Config struct { - IP string `json:"ip"` - Port string `json:"port"` - ServerIP string `json:"serverip"` - ServerPort string `json:"serverport"` - ServerRESTPort string `json:"serverrestport"` - WebServerPort string `json:"webserverport"` + IP string `json:"ip"` + Port string `json:"port"` + ServerIP string `json:"serverip"` + 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 diff --git a/serverCA/restRoutes.go b/serverCA/restRoutes.go index 31d89ab..c892019 100755 --- a/serverCA/restRoutes.go +++ b/serverCA/restRoutes.go @@ -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, }, -} - -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) + /* + POST /signup + POST /loginuser + POST /blindsign + POST /verifysign - 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, + }, } diff --git a/serverCA/testUser.sh b/serverCA/testUser.sh new file mode 100644 index 0000000..33cb99e --- /dev/null +++ b/serverCA/testUser.sh @@ -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"}' diff --git a/serverCA/tokens.go b/serverCA/tokens.go new file mode 100644 index 0000000..94db69c --- /dev/null +++ b/serverCA/tokens.go @@ -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.") + } +} diff --git a/serverCA/userRESTFunctions.go b/serverCA/userRESTFunctions.go new file mode 100644 index 0000000..59a7518 --- /dev/null +++ b/serverCA/userRESTFunctions.go @@ -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)) +}